Skip to content

Commit

Permalink
Revert "use libunwind to retrieve procedure names in stack trace (ins…
Browse files Browse the repository at this point in the history
…tead of dladdr)"

This reverts commit 10a2b02.
  • Loading branch information
JohanEngelen committed May 7, 2024
1 parent 7307912 commit 3ab1e12
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 62 deletions.
75 changes: 28 additions & 47 deletions runtime/druntime/src/core/internal/backtrace/handler.d
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ class LibunwindHandler : Throwable.TraceInfo
enum MAXFRAMES = 128;
FrameInfo[MAXFRAMES] callstack = void;

enum MAXPROCNAMELENGTH = 500;
char*[MAXFRAMES] namestack = void; // will be allocated using malloc, must be freed in destructor

/**
* Create a new instance of this trace handler saving the current context
*
Expand All @@ -51,9 +48,6 @@ class LibunwindHandler : Throwable.TraceInfo
*/
public this (size_t frames_to_skip = 1) nothrow @nogc
{
import core.stdc.stdlib : malloc;
import core.stdc.string : memcpy;

unw_context_t context;
unw_cursor_t cursor;
unw_getcontext(&context);
Expand All @@ -74,51 +68,12 @@ class LibunwindHandler : Throwable.TraceInfo
// adjust the frame address to point to the caller.
frame.address = cast(void*) ip - CALL_INSTRUCTION_SIZE;

unw_word_t offset;
char* buffer = cast(char*)malloc(MAXPROCNAMELENGTH);
if (buffer)
{
switch (unw_get_proc_name(&cursor, buffer, MAXPROCNAMELENGTH, &offset))
{
case UNW_ESUCCESS:
namestack[idx] = buffer;
break;
case UNW_ENOMEM:
// Name is longer than MAXPROCNAMELENGTH, truncated name was put in buffer.
// TODO: realloc larger buffer and try again.
namestack[idx] = buffer;
break;
default:
immutable error_string = "<ERROR: Unable to retrieve function name>";
memcpy(buffer, error_string.ptr, error_string.length+1); // include 0-terminator
namestack[idx] = buffer;
break;
}
}
else
{
// Out of memory
namestack[idx] = null;
}

this.numframes++;
if (unw_step(&cursor) <= 0)
break;
}
}

~this()
{
import core.stdc.stdlib : free;
// Need to deallocate the procedure name strings allocated in constructor.
foreach (ref ptr; this.namestack[0..numframes])
{
if (ptr)
free(ptr);
ptr = null;
}
}

///
override int opApply (scope int delegate(ref const(char[])) dg) const
{
Expand All @@ -128,11 +83,37 @@ class LibunwindHandler : Throwable.TraceInfo
///
override int opApply (scope int delegate(ref size_t, ref const(char[])) dg) const
{
import core.stdc.string : strlen;
// https://code.woboq.org/userspace/glibc/debug/backtracesyms.c.html
// The logic that glibc's backtrace use is to check for for `dli_fname`,
// the file name, and error if not present, then check for `dli_sname`.
// In case `dli_fname` is present but not `dli_sname`, the address is
// printed related to the file. We just print the file.
static const(char)[] getFrameName (const(void)* ptr)
{
import core.sys.posix.dlfcn;
import core.stdc.string;

Dl_info info = void;
// Note: See the module documentation about `-L--export-dynamic`
// TODO: Rewrite using libunwind's unw_get_proc_name
if (dladdr(ptr, &info))
{
// Return symbol name if possible
if (info.dli_sname !is null && info.dli_sname[0] != '\0')
return info.dli_sname[0 .. strlen(info.dli_sname)];

// Fall back to file name
if (info.dli_fname !is null && info.dli_fname[0] != '\0')
return info.dli_fname[0 .. strlen(info.dli_fname)];
}

// `dladdr` failed
return "<ERROR: Unable to retrieve function name>";
}

return traceHandlerOpApplyImpl(numframes,
i => callstack[i].address,
i => namestack[i] ? namestack[i][0..strlen(namestack[i])] : "<no memory to lookup name>",
i => getFrameName(callstack[i].address),
dg);
}

Expand Down
15 changes: 0 additions & 15 deletions runtime/druntime/src/core/internal/backtrace/libunwind.d
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,6 @@ enum
UNW_REG_SP = -2, // stack pointer
}

enum
{
UNW_ESUCCESS = 0, /* no error */
UNW_EUNSPEC = -6540, /* unspecified (general) error */
UNW_ENOMEM = -6541, /* out of memory */
UNW_EBADREG = -6542, /* bad register number */
UNW_EREADONLYREG = -6543, /* attempt to write read-only register */
UNW_ESTOPUNWIND = -6544, /* stop unwinding */
UNW_EINVALIDIP = -6545, /* invalid IP */
UNW_EBADFRAME = -6546, /* bad frame */
UNW_EINVAL = -6547, /* unsupported operation or bad value */
UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
UNW_ENOINFO = -6549 /* no unwind info found */
}

private:

// The API between libunwind and llvm-libunwind is almost the same,
Expand Down

0 comments on commit 3ab1e12

Please sign in to comment.