@@ -323,76 +323,141 @@ int Profiler::getNativeTrace(void *ucontext, ASGCT_CallFrame *frames,
323323 return convertNativeTrace (native_frames, callchain, frames);
324324}
325325
326- int Profiler::convertNativeTrace (int native_frames, const void **callchain,
327- ASGCT_CallFrame *frames) {
328- int depth = 0 ;
329- jmethodID prev_method = NULL ;
326+ void Profiler::applyRemoteSymbolicationToVMFrames (ASGCT_CallFrame *frames, int num_frames) {
327+ for (int i = 0 ; i < num_frames; i++) {
328+ // Only process native frames (not Java frames or special frames)
329+ if (frames[i].bci != BCI_NATIVE_FRAME) {
330+ continue ;
331+ }
330332
331- for (int i = 0 ; i < native_frames; i++) {
332- uintptr_t pc = (uintptr_t )callchain[i];
333+ // method_id contains the resolved symbol name (const char*)
334+ const char * symbol_name = (const char *)frames[i].method_id ;
335+ if (symbol_name == nullptr ) {
336+ continue ;
337+ }
333338
334- jmethodID current_method;
335- int current_bci;
336-
337- if (_remote_symbolication) {
338- // Remote symbolication mode: store build-id and PC offset
339- CodeCache* lib = _libs->findLibraryByAddress ((void *)pc);
340- TEST_LOG (" Remote symbolication: pc=0x%lx, lib=%p, hasBuildId=%d" ,
341- pc, lib, lib != nullptr ? lib->hasBuildId () : -1 );
342- if (lib != nullptr && lib->hasBuildId ()) {
343- TEST_LOG (" Using remote symbolication for lib=%s, build-id=%s" ,
344- lib->name (), lib->buildId ());
345- // Check if this is a marked C++ interpreter frame before using remote format
346- const char *method_name = nullptr ;
347- lib->binarySearch (callchain[i], &method_name);
348- if (method_name != nullptr && NativeFunc::isMarked (method_name)) {
349- // This is C++ interpreter frame, this and later frames should be reported
350- // as Java frames returned by AGCT. Terminate the scan here.
351- return depth;
352- }
339+ // Find the library containing this symbol to get the PC
340+ // We search all libraries for this symbol
341+ uintptr_t pc = 0 ;
342+ CodeCache* lib = nullptr ;
343+ const CodeCacheArray& native_libs = _libs->native_libs ();
344+ int lib_count = native_libs.count ();
345+ for (int lib_idx = 0 ; lib_idx < lib_count; lib_idx++) {
346+ CodeCache* candidate_lib = native_libs[lib_idx];
347+ if (candidate_lib == nullptr ) {
348+ continue ;
349+ }
353350
354- // Calculate PC offset within the library
355- uintptr_t offset = pc - (uintptr_t )lib->imageBase ();
351+ // Search for the symbol in this library
352+ const void * symbol_addr = candidate_lib->findSymbol (symbol_name);
353+ if (symbol_addr != nullptr ) {
354+ lib = candidate_lib;
355+ pc = (uintptr_t )symbol_addr;
356+ TEST_LOG (" Found symbol %s in lib %s at pc=0x%lx" , symbol_name, lib->name (), pc);
357+ break ;
358+ }
359+ }
356360
357- // Allocate RemoteFrameInfo (TODO: optimize with LinearAllocator)
358- RemoteFrameInfo* rfi = static_cast <RemoteFrameInfo*>(malloc (sizeof (RemoteFrameInfo)));
359- if (rfi != nullptr ) {
360- rfi->build_id = lib->buildId ();
361- rfi->pc_offset = offset;
362- rfi->lib_index = lib->libIndex ();
361+ // If we found the PC and the library has a build-id, apply remote symbolication
362+ if (pc != 0 && lib != nullptr && lib->hasBuildId ()) {
363+ TEST_LOG (" Applying remote symbolication to VM frame: symbol=%s, lib=%s, build-id=%s" ,
364+ symbol_name, lib->name (), lib->buildId ());
365+
366+ // Calculate PC offset within the library
367+ uintptr_t offset = pc - (uintptr_t )lib->imageBase ();
368+
369+ // Allocate RemoteFrameInfo
370+ RemoteFrameInfo* rfi = static_cast <RemoteFrameInfo*>(malloc (sizeof (RemoteFrameInfo)));
371+ if (rfi != nullptr ) {
372+ rfi->build_id = lib->buildId ();
373+ rfi->pc_offset = offset;
374+ rfi->lib_index = lib->libIndex ();
375+
376+ // Replace the frame with remote symbolication format
377+ frames[i].method_id = (jmethodID)rfi;
378+ frames[i].bci = BCI_NATIVE_FRAME_REMOTE;
379+ TEST_LOG (" Converted VM frame to remote format: build-id=%s, offset=0x%lx" , rfi->build_id , rfi->pc_offset );
380+ }
381+ }
382+ }
383+ }
363384
364- current_method = (jmethodID)rfi;
365- current_bci = BCI_NATIVE_FRAME_REMOTE;
366- } else {
367- // Fallback to resolved symbol if allocation failed
368- // Need to resolve the symbol now since we didn't do it earlier
369- const char *fallback_name = nullptr ;
370- lib->binarySearch (callchain[i], &fallback_name);
371- current_method = (jmethodID)fallback_name;
372- current_bci = BCI_NATIVE_FRAME;
373- }
385+ Profiler::NativeFrameResolution Profiler::resolveNativeFrame (uintptr_t pc) {
386+ if (_remote_symbolication) {
387+ // Remote symbolication mode: store build-id and PC offset
388+ CodeCache* lib = _libs->findLibraryByAddress ((void *)pc);
389+ TEST_LOG (" Remote symbolication: pc=0x%lx, lib=%p, hasBuildId=%d" ,
390+ pc, lib, lib != nullptr ? lib->hasBuildId () : -1 );
391+ if (lib != nullptr && lib->hasBuildId ()) {
392+ TEST_LOG (" Using remote symbolication for lib=%s, build-id=%s" ,
393+ lib->name (), lib->buildId ());
394+ // Check if this is a marked C++ interpreter frame before using remote format
395+ const char *method_name = nullptr ;
396+ lib->binarySearch ((void *)pc, &method_name);
397+ if (method_name != nullptr && NativeFunc::isMarked (method_name)) {
398+ // This is C++ interpreter frame, this and later frames should be reported
399+ // as Java frames returned by AGCT. Terminate the scan here.
400+ return {nullptr , BCI_NATIVE_FRAME, true };
401+ }
402+
403+ // Calculate PC offset within the library
404+ uintptr_t offset = pc - (uintptr_t )lib->imageBase ();
405+
406+ // Allocate RemoteFrameInfo (TODO: optimize with LinearAllocator)
407+ RemoteFrameInfo* rfi = static_cast <RemoteFrameInfo*>(malloc (sizeof (RemoteFrameInfo)));
408+ if (rfi != nullptr ) {
409+ rfi->build_id = lib->buildId ();
410+ rfi->pc_offset = offset;
411+ rfi->lib_index = lib->libIndex ();
412+
413+ return {(jmethodID)rfi, BCI_NATIVE_FRAME_REMOTE, false };
374414 } else {
375- // Library not found or no build-id, fallback to resolved symbol
376- const char *method_name = findNativeMethod (callchain[i]);
377- if (method_name != nullptr && NativeFunc::isMarked (method_name)) {
378- // This is C++ interpreter frame, this and later frames should be reported
379- // as Java frames returned by AGCT. Terminate the scan here.
380- return depth;
381- }
382- current_method = (jmethodID)method_name;
383- current_bci = BCI_NATIVE_FRAME;
415+ // Fallback to resolved symbol if allocation failed
416+ // Need to resolve the symbol now since we didn't do it earlier
417+ const char *fallback_name = nullptr ;
418+ lib->binarySearch ((void *)pc, &fallback_name);
419+ return {(jmethodID)fallback_name, BCI_NATIVE_FRAME, false };
384420 }
385421 } else {
386- // Traditional mode: resolve and store symbol name
387- const char *method_name = findNativeMethod (callchain[i] );
422+ // Library not found or no build-id, fallback to resolved symbol
423+ const char *method_name = findNativeMethod (( void *)pc );
388424 if (method_name != nullptr && NativeFunc::isMarked (method_name)) {
389425 // This is C++ interpreter frame, this and later frames should be reported
390426 // as Java frames returned by AGCT. Terminate the scan here.
391- return depth ;
427+ return { nullptr , BCI_NATIVE_FRAME, true } ;
392428 }
393- current_method = (jmethodID)method_name;
394- current_bci = BCI_NATIVE_FRAME;
429+ return {(jmethodID)method_name, BCI_NATIVE_FRAME, false };
430+ }
431+ } else {
432+ // Traditional mode: resolve and store symbol name
433+ const char *method_name = findNativeMethod ((void *)pc);
434+ if (method_name != nullptr && NativeFunc::isMarked (method_name)) {
435+ // This is C++ interpreter frame, this and later frames should be reported
436+ // as Java frames returned by AGCT. Terminate the scan here.
437+ return {nullptr , BCI_NATIVE_FRAME, true };
395438 }
439+ return {(jmethodID)method_name, BCI_NATIVE_FRAME, false };
440+ }
441+ }
442+
443+ int Profiler::convertNativeTrace (int native_frames, const void **callchain,
444+ ASGCT_CallFrame *frames) {
445+ int depth = 0 ;
446+ jmethodID prev_method = NULL ;
447+
448+ for (int i = 0 ; i < native_frames; i++) {
449+ uintptr_t pc = (uintptr_t )callchain[i];
450+
451+ // Resolve native frame using shared logic
452+ NativeFrameResolution resolution = resolveNativeFrame (pc);
453+
454+ // Check if this is a marked frame (terminate scan)
455+ if (resolution.is_marked ) {
456+ return depth;
457+ }
458+
459+ jmethodID current_method = resolution.method_id ;
460+ int current_bci = resolution.bci ;
396461
397462 // Skip duplicates in LBR stack
398463 if (current_method == prev_method && _cstack == CSTACK_LBR) {
@@ -770,10 +835,22 @@ void Profiler::recordSample(void *ucontext, u64 counter, int tid,
770835 if (num_frames < _max_stack_depth) {
771836 int max_remaining = _max_stack_depth - num_frames;
772837 if (_features.mixed ) {
773- num_frames += ddprof::StackWalker::walkVM (ucontext, frames + num_frames, max_remaining, _features, eventTypeFromBCI (event_type), &truncated);
838+ int vm_start = num_frames;
839+ int vm_frames = ddprof::StackWalker::walkVM (ucontext, frames + vm_start, max_remaining, _features, eventTypeFromBCI (event_type), &truncated);
840+ num_frames += vm_frames;
841+ // Apply remote symbolication to VM frames if enabled
842+ if (_remote_symbolication) {
843+ applyRemoteSymbolicationToVMFrames (frames + vm_start, vm_frames);
844+ }
774845 } else if (event_type == BCI_CPU || event_type == BCI_WALL) {
775846 if (_cstack >= CSTACK_VM) {
776- num_frames += ddprof::StackWalker::walkVM (ucontext, frames + num_frames, max_remaining, _features, eventTypeFromBCI (event_type), &truncated);
847+ int vm_start = num_frames;
848+ int vm_frames = ddprof::StackWalker::walkVM (ucontext, frames + vm_start, max_remaining, _features, eventTypeFromBCI (event_type), &truncated);
849+ num_frames += vm_frames;
850+ // Apply remote symbolication to VM frames if enabled
851+ if (_remote_symbolication) {
852+ applyRemoteSymbolicationToVMFrames (frames + vm_start, vm_frames);
853+ }
777854 } else {
778855 // Async events
779856 AsyncSampleMutex mutex (ProfiledThread::currentSignalSafe ());
0 commit comments