Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 14ba7e8

Browse files
committed
fix Issue 18068 - Account for DSO-relative DWARF addresses
1 parent c8b6f19 commit 14ba7e8

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

src/rt/backtrace/dwarf.d

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ int traceHandlerOpApplyImpl(const void*[] callstack, scope int delegate(ref size
6565
foreach(size_t i; 0 .. callstack.length)
6666
locations[i].address = cast(size_t) callstack[i];
6767

68-
resolveAddresses(&dbgSection, locations[]);
68+
// the DWARF addresses for DSOs are relative
69+
const isDynamicSharedObject = (file.ehdr.e_type == ET_DYN);
70+
const baseAddress = (isDynamicSharedObject ? cast(size_t) getAbsoluteAddressRangeForExecutable().ptr : 0);
71+
72+
resolveAddresses(&dbgSection, baseAddress, locations[]);
6973
}
7074
}
7175

@@ -115,7 +119,7 @@ int traceHandlerOpApplyImpl(const void*[] callstack, scope int delegate(ref size
115119
private:
116120

117121
// the lifetime of the Location data is the lifetime of the mmapped ElfSection
118-
void resolveAddresses(ElfSection* debugLineSection, Location[] locations) @nogc nothrow
122+
void resolveAddresses(ElfSection* debugLineSection, size_t baseAddress, Location[] locations) @nogc nothrow
119123
{
120124
debug(DwarfDebugMachine) import core.stdc.stdio;
121125

@@ -134,6 +138,8 @@ void resolveAddresses(ElfSection* debugLineSection, Location[] locations) @nogc
134138
runStateMachine(lp,
135139
(size_t address, LocationInfo locInfo, bool isEndSequence)
136140
{
141+
address += baseAddress;
142+
137143
// If loc.line != -1, then it has been set previously.
138144
// Some implementations (eg. dmd) write an address to
139145
// the debug data multiple times, but so far I have found

src/rt/backtrace/elf.d

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,59 @@ version(linux) public import core.sys.linux.elf;
2424
version(FreeBSD) public import core.sys.freebsd.sys.elf;
2525
version(DragonFlyBSD) public import core.sys.dragonflybsd.sys.elf;
2626

27+
const(void)[] getAbsoluteAddressRangeForExecutable() @nogc nothrow
28+
{
29+
import core.sys.posix.unistd : readlink, getpid;
30+
import core.stdc.stdio, core.stdc.stdlib, core.stdc.string;
31+
32+
// get absolute path to executable
33+
char[1024] selfPath = void;
34+
version (FreeBSD)
35+
{
36+
getFreeBSDExePath(selfPath[]);
37+
}
38+
else
39+
{
40+
version (linux)
41+
{
42+
auto selfLink = "/proc/self/exe".ptr;
43+
}
44+
else version (DragonFlyBSD)
45+
{
46+
auto selfLink = "/proc/curproc/file".ptr;
47+
}
48+
49+
const length = readlink(selfLink, selfPath.ptr, selfPath.length);
50+
assert(length > 0 && length < selfPath.length);
51+
selfPath[length] = 0;
52+
}
53+
54+
// open the current process' maps file
55+
char[1024] selfMapsPath = void;
56+
snprintf(selfMapsPath.ptr, selfMapsPath.length, "/proc/%d/maps", getpid());
57+
FILE* fp = fopen(selfMapsPath.ptr, "r");
58+
assert(fp);
59+
scope(exit) fclose(fp);
60+
61+
// use the address range of the first line for the executable file
62+
char[128] line = void;
63+
while (fgets(line.ptr, line.length, fp) !is null)
64+
{
65+
line[strlen(line.ptr) - 1] = '\0'; // remove trailing '\n'
66+
char* path = strchr(line.ptr, '/');
67+
if (path && strcmp(selfPath.ptr, path) == 0)
68+
{
69+
char* tail;
70+
const start = cast(void*) strtoul(line.ptr, &tail, 16);
71+
++tail; // skip over '-'
72+
const end = cast(void*) strtoul(tail, &tail, 16);
73+
return start[0 .. end - start];
74+
}
75+
}
76+
77+
assert(0);
78+
}
79+
2780
struct ElfFile
2881
{
2982
static bool openSelf(ElfFile* file) @nogc nothrow

0 commit comments

Comments
 (0)