Skip to content

Commit 7ba247f

Browse files
jbachorikclaude
andcommitted
Render unsymbolized native frames as [lib+0xoffset] instead of unknown
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent de241f6 commit 7ba247f

4 files changed

Lines changed: 58 additions & 31 deletions

File tree

ddprof-lib/src/main/cpp/flightRecorder.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,19 @@ MethodInfo *Lookup::resolveMethod(ASGCT_CallFrame &frame) {
375375
// Note: This is called during JFR serialization with lockAll() held (see Profiler::dump),
376376
// so the library array is stable - no concurrent dlopen_hook calls can modify it.
377377
CodeCache* lib = Libraries::instance()->getLibraryByIndex(lib_index);
378-
if (lib != nullptr) {
378+
if (lib != nullptr && lib->hasBuildId() && Profiler::instance()->isRemoteSymbolication()) {
379379
TEST_LOG("Found library: %s, build_id=%s", lib->name(), lib->buildId());
380-
// Create temporary RemoteFrameInfo for fillRemoteFrameInfo
380+
// Remote symbolication: defer to backend
381381
RemoteFrameInfo rfi(lib->buildId(), pc_offset, lib_index);
382382
fillRemoteFrameInfo(mi, &rfi);
383+
} else if (lib != nullptr) {
384+
// Locally unsymbolized: render as [libname+0xoffset]
385+
char name_buf[256];
386+
const char* s = lib->name();
387+
const char* basename = strrchr(s, '/');
388+
if (basename) basename++; else basename = s;
389+
snprintf(name_buf, sizeof(name_buf), "[%s+0x%" PRIxPTR "]", basename, pc_offset);
390+
fillNativeMethodInfo(mi, name_buf, nullptr);
383391
} else {
384392
TEST_LOG("WARNING: Library lookup failed for index %u", lib_index);
385393
fillNativeMethodInfo(mi, "unknown_library", nullptr);

ddprof-lib/src/main/cpp/profiler.cpp

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -365,40 +365,54 @@ void Profiler::populateRemoteFrame(ASGCT_CallFrame* frame, uintptr_t pc, CodeCac
365365
* - Returns is_marked=true if mark indicates termination (MARK_INTERPRETER, etc.)
366366
*
367367
* For traditional symbolication:
368-
* - Does full symbol resolution via findNativeMethod()
368+
* - Does symbol resolution via binarySearch() on the found library
369369
* - Checks marks after symbol resolution (same O(log n) + O(1) cost)
370+
* - If no symbol found but PC is in a known library, packs as
371+
* BCI_NATIVE_FRAME_REMOTE for library-relative rendering ([lib+0xoffset])
370372
*/
371373
Profiler::NativeFrameResolution Profiler::resolveNativeFrameForWalkVM(uintptr_t pc, int lock_index) {
372-
if (_remote_symbolication) {
373-
CodeCache* lib = _libs->findLibraryByAddress((void*)pc);
374-
if (lib != nullptr && lib->hasBuildId()) {
375-
// Get symbol name and check mark
376-
const char *method_name = nullptr;
377-
lib->binarySearch((void*)pc, &method_name);
378-
char mark = (method_name != nullptr) ? NativeFunc::read_mark(method_name) : 0;
379-
380-
if (mark != 0) {
381-
return {nullptr, BCI_NATIVE_FRAME, true}; // Marked - stop processing
382-
}
383-
384-
// Pack remote symbolication data using utility struct
385-
uintptr_t pc_offset = pc - (uintptr_t)lib->imageBase();
386-
uint32_t lib_index = (uint32_t)lib->libIndex();
387-
unsigned long packed = RemoteFramePacker::pack(pc_offset, mark, lib_index);
374+
CodeCache* lib = _libs->findLibraryByAddress((void*)pc);
388375

389-
TEST_LOG("resolveNativeFrameForWalkVM: lib=%s, build_id=%s, pc=0x%lx, pc_offset=0x%lx, mark=%d, lib_index=%u, packed=0x%zx",
390-
lib->name(), lib->buildId(), pc, pc_offset, (int)mark, lib_index, packed);
376+
if (_remote_symbolication && lib != nullptr && lib->hasBuildId()) {
377+
// Get symbol name and check mark
378+
const char *method_name = nullptr;
379+
lib->binarySearch((void*)pc, &method_name);
380+
char mark = (method_name != nullptr) ? NativeFunc::read_mark(method_name) : 0;
391381

392-
return NativeFrameResolution(packed, BCI_NATIVE_FRAME_REMOTE, false);
382+
if (mark != 0) {
383+
return {nullptr, BCI_NATIVE_FRAME, true}; // Marked - stop processing
393384
}
385+
386+
// Pack remote symbolication data using utility struct
387+
uintptr_t pc_offset = pc - (uintptr_t)lib->imageBase();
388+
uint32_t lib_index = (uint32_t)lib->libIndex();
389+
unsigned long packed = RemoteFramePacker::pack(pc_offset, mark, lib_index);
390+
391+
TEST_LOG("resolveNativeFrameForWalkVM: lib=%s, build_id=%s, pc=0x%lx, pc_offset=0x%lx, mark=%d, lib_index=%u, packed=0x%zx",
392+
lib->name(), lib->buildId(), pc, pc_offset, (int)mark, lib_index, packed);
393+
394+
return NativeFrameResolution(packed, BCI_NATIVE_FRAME_REMOTE, false);
394395
}
395396

396-
// Fallback: Traditional symbol resolution
397-
const char *method_name = findNativeMethod((void*)pc);
397+
// Traditional symbol resolution
398+
const char *method_name = nullptr;
399+
if (lib != nullptr) {
400+
lib->binarySearch((void*)pc, &method_name);
401+
}
398402
if (method_name != nullptr && NativeFunc::is_marked(method_name)) {
399403
return NativeFrameResolution(nullptr, BCI_NATIVE_FRAME, true);
400404
}
401405

406+
// No symbol but known library: pack for library-relative identification.
407+
// Reuses BCI_NATIVE_FRAME_REMOTE encoding; resolveMethod() in flightRecorder.cpp
408+
// distinguishes remote vs local rendering via hasBuildId() && isRemoteSymbolication().
409+
if (method_name == nullptr && lib != nullptr) {
410+
uintptr_t pc_offset = pc - (uintptr_t)lib->imageBase();
411+
uint32_t lib_index = (uint32_t)lib->libIndex();
412+
unsigned long packed = RemoteFramePacker::pack(pc_offset, 0, lib_index);
413+
return NativeFrameResolution(packed, BCI_NATIVE_FRAME_REMOTE, false);
414+
}
415+
402416
return NativeFrameResolution(method_name, BCI_NATIVE_FRAME, false);
403417
}
404418

ddprof-lib/src/main/cpp/profiler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ class alignas(alignof(SpinLock)) Profiler {
315315

316316
/**
317317
* Pack remote symbolication data into a 64-bit jmethodID.
318-
* Layout: pc_offset (44 bits) | mark (3 bits) | lib_index (17 bits)
318+
* Layout: pc_offset (44 bits) | mark (3 bits) | lib_index (15 bits)
319319
*/
320320
static inline unsigned long pack(uintptr_t pc_offset, char mark, uint32_t lib_index) {
321321
return (unsigned long)(
@@ -381,6 +381,7 @@ class alignas(alignof(SpinLock)) Profiler {
381381
const char *value, const char *unit);
382382
void writeHeapUsage(long value, bool live);
383383
int eventMask() const { return _event_mask; }
384+
bool isRemoteSymbolication() const { return _remote_symbolication; }
384385

385386
const void *resolveSymbol(const char *name);
386387
const char *getLibraryName(const char *native_symbol);

ddprof-lib/src/main/cpp/stackWalker.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -657,14 +657,18 @@ __attribute__((no_sanitize("address"))) int StackWalker::walkVM(void* ucontext,
657657
Counters::increment(WALKVM_ANCHOR_INLINE_NO_SP);
658658
}
659659
// Check previous frame for thread entry points (Rust, libc/pthread)
660+
// Only check marks for traditionally-resolved frames; packed remote
661+
// frames store an integer in the method_name union, not a valid pointer.
660662
if (prev_native_pc != NULL) {
661663
Profiler::NativeFrameResolution prev_resolution = profiler->resolveNativeFrameForWalkVM((uintptr_t)prev_native_pc, lock_index);
662-
const char* prev_method_name = (const char*)prev_resolution.method_name;
663-
if (prev_method_name != NULL) {
664-
char prev_mark = NativeFunc::read_mark(prev_method_name);
665-
if (prev_mark == MARK_THREAD_ENTRY) {
666-
Counters::increment(THREAD_ENTRY_MARK_DETECTIONS);
667-
break;
664+
if (prev_resolution.bci != BCI_NATIVE_FRAME_REMOTE) {
665+
const char* prev_method_name = prev_resolution.method_name;
666+
if (prev_method_name != NULL) {
667+
char prev_mark = NativeFunc::read_mark(prev_method_name);
668+
if (prev_mark == MARK_THREAD_ENTRY) {
669+
Counters::increment(THREAD_ENTRY_MARK_DETECTIONS);
670+
break;
671+
}
668672
}
669673
}
670674
}

0 commit comments

Comments
 (0)