66
77#include < climits>
88#include < cstdlib>
9- #include < setjmp.h>
109#include " asyncSampleMutex.h"
10+ #include " frames.h"
11+ #include " guards.h"
1112#include " hotspot/hotspotSupport.h"
1213#include " hotspot/jitCodeCache.h"
1314#include " hotspot/vmStructs.inline.h"
1415#include " jvmSupport.inline.h"
15- #include " guards.h"
16+ #include " jvmThread.h"
17+ #include " profiler.h"
1618#include " stackWalker.inline.h"
17- #include " frames .h"
19+ #include " threadLocal .h"
1820
1921using StackWalkValidation::inDeadZone;
2022using StackWalkValidation::aligned;
2123using StackWalkValidation::MAX_FRAME_SIZE ;
22- using StackWalkValidation::sameStack;
2324
2425// Initialize once, they survive on profiler restart
2526static jobject JAVA_PLATFORM_CLASSLOADER = nullptr ;
@@ -227,15 +228,46 @@ __attribute__((no_sanitize("address"))) int HotspotSupport::walkVM(void* ucontex
227228__attribute__ ((no_sanitize(" address" ))) int HotspotSupport::walkVM(void * ucontext, ASGCT_CallFrame* frames, int max_depth,
228229 StackWalkFeatures features, EventType event_type,
229230 const void * pc, uintptr_t sp, uintptr_t fp, int lock_index, bool * truncated) {
231+
230232 // VMStructs is only available for hotspot JVM
231233 assert (VM::isHotspot ());
234+
235+ ProfiledThread* prof_thread = ProfiledThread::currentSignalSafe ();
236+ if (prof_thread == nullptr ) {
237+ Counters::increment (SAMPLES_DROPPED_THREAD_LOCAL );
238+ return 0 ;
239+ }
240+
232241 HotspotStackFrame frame (ucontext);
233242 uintptr_t bottom = (uintptr_t )&frame + MAX_WALK_SIZE ;
234243
235244 Profiler* profiler = Profiler::instance ();
236245 int bcp_offset = InterpreterFrame::bcp_offset ();
237246
247+
238248 jmp_buf crash_protection_ctx;
249+ // Chaining jmp_buf
250+ // A non-signal-based-sampler can be interrupted by signal based sampler,
251+ // then we end up with multiple HotspotSupport::walkVM() calls on stack,
252+ // each one sets up jmp_buf, they need to be chained to jump back to
253+ // correct location.
254+ jmp_buf* prev_jmp_buf = prof_thread->getJmpCtx ();
255+ // Should be preserved across setjmp/longjmp
256+ volatile int depth = 0 ;
257+ int actual_max_depth = truncated ? max_depth + 1 : max_depth;
258+
259+ if (setjmp (crash_protection_ctx) != 0 ) {
260+ // checkFault() does a longjmp from inside segvHandler, bypassing
261+ // segvHandler's SignalHandlerScope destructor. Compensate.
262+ SIGNAL_HANDLER_UNWIND_AFTER_LONGJMP ();
263+ prof_thread->setJmpCtx (prev_jmp_buf);
264+ if (depth < max_depth) {
265+ fillFrame (frames[depth++], BCI_ERROR , " break_not_walkable" );
266+ }
267+ return depth;
268+ }
269+
270+ prof_thread->setJmpCtx (&crash_protection_ctx);
239271 VMThread* vm_thread = VMThread::current ();
240272 if (vm_thread != NULL && !vm_thread->isThreadAccessible ()) {
241273 Counters::increment (WALKVM_THREAD_INACCESSIBLE );
@@ -246,39 +278,16 @@ __attribute__((no_sanitize("address"))) int HotspotSupport::walkVM(void* ucontex
246278 } else {
247279 Counters::increment (WALKVM_VMTHREAD_OK );
248280 }
249- void * saved_exception = vm_thread != NULL ? vm_thread->exception () : NULL ;
250281
251- // Should be preserved across setjmp/longjmp
252- volatile int depth = 0 ;
253- int actual_max_depth = truncated ? max_depth + 1 : max_depth;
254282 bool fp_chain_fallback = false ;
255283 int fp_chain_depth = 0 ;
256284
257- ProfiledThread* profiled_thread = ProfiledThread::currentSignalSafe ();
258-
259285 VMJavaFrameAnchor* anchor = NULL ;
260286 if (vm_thread != NULL ) {
261287 anchor = vm_thread->anchor ();
262288 if (anchor == NULL ) {
263289 Counters::increment (WALKVM_ANCHOR_NULL );
264290 }
265- vm_thread->exception () = &crash_protection_ctx;
266- if (profiled_thread != nullptr ) {
267- profiled_thread->setCrashProtectionActive (true );
268- }
269- if (setjmp (crash_protection_ctx) != 0 ) {
270- // checkFault() does a longjmp from inside segvHandler, bypassing
271- // segvHandler's SignalHandlerScope destructor. Compensate.
272- SIGNAL_HANDLER_UNWIND_AFTER_LONGJMP ();
273- if (profiled_thread != nullptr ) {
274- profiled_thread->setCrashProtectionActive (false );
275- }
276- vm_thread->exception () = saved_exception;
277- if (depth < max_depth) {
278- fillFrame (frames[depth++], BCI_ERROR , " break_not_walkable" );
279- }
280- return depth;
281- }
282291 }
283292
284293 const void * prev_native_pc = NULL ;
@@ -616,7 +625,8 @@ __attribute__((no_sanitize("address"))) int HotspotSupport::walkVM(void* ucontex
616625 if (features.vtable_target && nm->isVTableStub () && depth == 0 ) {
617626 uintptr_t receiver = frame.jarg0 ();
618627 if (receiver != 0 ) {
619- VMSymbol* symbol = VMKlass::fromOop (receiver)->name ();
628+ VMKlass* klass = VMKlass::fromOop (receiver);
629+ VMSymbol* symbol = klass != nullptr ? klass->name () : nullptr ;
620630 // Store the raw VMSymbol* in the frame's method_id
621631 // slot. BCI_VTABLE_RECEIVER (vmEntry.h) repurposes
622632 // method_id for this pointer — same precedent as
@@ -922,12 +932,7 @@ __attribute__((no_sanitize("address"))) int HotspotSupport::walkVM(void* ucontex
922932 }
923933
924934 done:
925- if (profiled_thread != nullptr ) {
926- profiled_thread->setCrashProtectionActive (false );
927- }
928- if (vm_thread != NULL ) {
929- vm_thread->exception () = saved_exception;
930- }
935+ prof_thread->setJmpCtx (prev_jmp_buf);
931936
932937 // Drop unknown leaf frame - it provides no useful information and breaks
933938 // aggregation by lumping unrelated samples under a single "unknown" entry
@@ -953,33 +958,20 @@ __attribute__((no_sanitize("address"))) int HotspotSupport::walkVM(void* ucontex
953958}
954959
955960void HotspotSupport::checkFault (ProfiledThread* thrd) {
956- if (!JVMThread::isInitialized ()) {
957- // JVM has not been loaded or has not been initialized yet
958- return ;
959- }
960-
961- VMThread* vm_thread = VMThread::current ();
962- if (vm_thread == NULL || !vm_thread->isThreadAccessible ()) {
961+ // Should not get to here (?)
962+ if (thrd == nullptr ) {
963963 return ;
964964 }
965965
966- // Prefer the semantic crash protection flag (reliable regardless of stack frame sizes).
967- // Fall back to sameStack heuristic when ProfiledThread TLS is unavailable (e.g. during
968- // early init or in crash recovery tests). sameStack uses a fixed 8KB threshold which
969- // can fail with ASAN-inflated frames, but the crashProtectionActive path handles that.
970- bool protected_walk = (thrd != nullptr && thrd->isCrashProtectionActive ())
971- || sameStack (vm_thread->exception (), &vm_thread);
972- if (!protected_walk) {
966+ // Check if longjmp is setup for this thread
967+ if (!thrd->isProtected ()) {
973968 return ;
974969 }
975970
976- if (thrd != nullptr ) {
977- thrd->resetCrashHandler ();
978- }
979- longjmp (*(jmp_buf*)vm_thread->exception (), 1 );
971+ thrd->resetCrashHandler ();
972+ longjmp (*thrd->getJmpCtx (), 1 );
980973}
981974
982-
983975int HotspotSupport::getJavaTraceAsync (void *ucontext, ASGCT_CallFrame *frames,
984976 int max_depth, StackContext *java_ctx,
985977 bool *truncated) {
@@ -1189,7 +1181,6 @@ int HotspotSupport::getJavaTraceAsync(void *ucontext, ASGCT_CallFrame *frames,
11891181 return trace.frames - frames + 1 ;
11901182}
11911183
1192-
11931184int HotspotSupport::walkJavaStack (StackWalkRequest& request) {
11941185 CStack cstack = Profiler::instance ()->cstackMode ();
11951186 StackWalkFeatures features = Profiler::instance ()->stackWalkFeatures ();
0 commit comments