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

Commit 531e2b7

Browse files
authored
Merge pull request #3643 from kinke/elf_exe
Fix Issue 21656 - Read correct ELF executable for DWARF file/line infos
2 parents 9f331c5 + dc17630 commit 531e2b7

File tree

3 files changed

+138
-11
lines changed

3 files changed

+138
-11
lines changed

src/core/internal/backtrace/elf.d

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ else version (OpenBSD)
3434

3535
version (LinuxOrBSD):
3636

37-
import core.internal.elf.dl;
3837
import core.internal.elf.io;
3938

4039
struct Image
@@ -43,9 +42,15 @@ struct Image
4342

4443
static Image openSelf()
4544
{
46-
const(char)* selfPath = SharedObject.thisExecutable().name().ptr;
45+
import core.stdc.stdlib : free;
4746

4847
Image image;
48+
49+
char* selfPath = thisExePath();
50+
if (selfPath is null)
51+
return image;
52+
scope(exit) free(selfPath);
53+
4954
if (!ElfFile.open(selfPath, image.file))
5055
image.file = ElfFile.init;
5156

@@ -74,6 +79,8 @@ struct Image
7479

7580
@property size_t baseAddress()
7681
{
82+
import core.internal.elf.dl : SharedObject;
83+
7784
// the DWARF addresses for DSOs are relative
7885
const isDynamicSharedObject = (file.ehdr.e_type == ET_DYN);
7986
if (!isDynamicSharedObject)

src/core/internal/elf/io.d

Lines changed: 115 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ version (Posix):
1515

1616
import core.memory : pageSize;
1717
import core.lifetime : move;
18+
import core.stdc.stdlib : malloc, free;
1819
import core.sys.posix.fcntl;
1920
import core.sys.posix.sys.mman;
2021
import core.sys.posix.unistd;
@@ -361,23 +362,132 @@ private struct MMapRegion
361362
public const(ubyte)[] data;
362363
}
363364

365+
@nogc nothrow:
366+
367+
version (OpenBSD)
368+
private extern(C) const(char)* getprogname();
369+
370+
/// Returns the path to the process' executable as newly allocated C string
371+
/// (free() when done), or null on error.
372+
version (LinuxOrBSD)
373+
char* thisExePath()
374+
{
375+
version (linux)
376+
{
377+
return readLink("/proc/self/exe");
378+
}
379+
else version (Solaris)
380+
{
381+
import core.stdc.stdio : snprintf;
382+
import core.sys.posix.unistd : getpid;
383+
384+
// only Solaris 10 and later
385+
char[32] buffer = void;
386+
const numWritten = snprintf(buffer.ptr, sizeof(buffer), "/proc/%d/path/a.out", getpid());
387+
assert(numWritten > 0 && numWritten < sizeof(buffer));
388+
assert(buffer[numWritten] == 0);
389+
390+
return readLink(buffer.ptr);
391+
}
392+
else version (OpenBSD)
393+
{
394+
// there's apparently no proper way :/
395+
import core.stdc.string : strdup;
396+
return strdup(getprogname());
397+
}
398+
else
399+
{
400+
version (DragonFlyBSD)
401+
{
402+
import core.sys.dragonflybsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME;
403+
int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1];
404+
}
405+
else version (FreeBSD)
406+
{
407+
import core.sys.freebsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME;
408+
int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1];
409+
}
410+
else version (NetBSD)
411+
{
412+
import core.sys.netbsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC_ARGS, KERN_PROC_PATHNAME;
413+
int[4] mib = [CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME];
414+
}
415+
else
416+
static assert(0, "Unsupported platform");
417+
418+
// get the length of the path
419+
size_t len;
420+
auto result = sysctl(mib.ptr, mib.length, null, &len, null, 0);
421+
if (result != 0)
422+
return null;
423+
424+
auto buffer = cast(char*) malloc(len);
425+
if (!buffer)
426+
return null;
427+
result = sysctl(mib.ptr, mib.length, buffer, &len, null, 0);
428+
if (result != 0)
429+
{
430+
free(buffer);
431+
return null;
432+
}
433+
434+
assert(buffer[len - 1] == 0);
435+
return buffer;
436+
}
437+
}
438+
439+
// Tries to read the target of the specified link as newly allocated C string.
440+
// Returns null on error; free() result otherwise when done.
441+
private char* readLink(const(char)* link)
442+
{
443+
for (size_t bufferSize = 128; bufferSize < 131_072; bufferSize *= 2)
444+
{
445+
auto buffer = cast(char*) malloc(bufferSize);
446+
if (!buffer)
447+
return null;
448+
449+
const numWritten = readlink(link, buffer, bufferSize);
450+
if (numWritten == -1)
451+
{
452+
free(buffer);
453+
return null;
454+
}
455+
456+
enum maxCodeUnits = 6;
457+
if (numWritten <= bufferSize - maxCodeUnits)
458+
{
459+
buffer[numWritten] = 0; // null-terminate
460+
return buffer;
461+
}
462+
else
463+
free(buffer);
464+
}
465+
466+
return null;
467+
}
468+
364469
version (LinuxOrBSD)
365470
unittest
366471
{
367-
import core.internal.elf.dl, core.stdc.stdio;
472+
import core.internal.elf.dl : SharedObject;
473+
import core.stdc.stdio : printf;
368474

369-
SharedObject exe = SharedObject.thisExecutable();
475+
char* exePath = thisExePath();
476+
assert(exePath);
477+
scope(exit) free(exePath);
370478

371479
ElfFile file;
372-
bool success = ElfFile.open(exe.name.ptr, file);
373-
assert(success, "cannot open ELF file");
480+
bool success = ElfFile.open(exePath, file);
481+
assert(success, "cannot open ELF executable");
482+
483+
const exeBaseAddress = SharedObject.thisExecutable().baseAddress;
374484

375485
foreach (index, name, sectionHeader; file.namedSections)
376486
{
377487
printf("section %3d %-32s", cast(int) index, name.ptr);
378488
if (const offset = sectionHeader.shdr.sh_addr)
379489
{
380-
auto beg = exe.baseAddress + offset;
490+
auto beg = exeBaseAddress + offset;
381491
printf("%p - %p\n", beg, beg + sectionHeader.shdr.sh_size);
382492
}
383493
else

test/exceptions/Makefile

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@ TESTS=stderr_msg unittest_assert invalid_memory_operation unknown_gc static_dtor
44
future_message refcounted rt_trap_exceptions_drt catch_in_finally
55

66
ifeq ($(OS)-$(BUILD),linux-debug)
7-
TESTS+=line_trace long_backtrace_trunc rt_trap_exceptions
7+
TESTS+=line_trace line_trace_21656 long_backtrace_trunc rt_trap_exceptions
88
LINE_TRACE_DFLAGS:=-L--export-dynamic
99
endif
1010
ifeq ($(OS),linux)
1111
TESTS+=rt_trap_exceptions_drt_gdb
1212
endif
1313
ifeq ($(OS)-$(BUILD),freebsd-debug)
14-
TESTS+=line_trace long_backtrace_trunc
14+
TESTS+=line_trace line_trace_21656 long_backtrace_trunc
1515
LINE_TRACE_DFLAGS:=-L--export-dynamic
1616
endif
1717
ifeq ($(OS)-$(BUILD),dragonflybsd-debug)
18-
TESTS+=line_trace long_backtrace_trunc
18+
TESTS+=line_trace line_trace_21656 long_backtrace_trunc
1919
LINE_TRACE_DFLAGS:=-L--export-dynamic
2020
endif
2121
ifeq ($(OS)-$(BUILD),osx-debug)
22-
TESTS+=line_trace long_backtrace_trunc
22+
TESTS+=line_trace line_trace_21656 long_backtrace_trunc
2323
LINE_TRACE_DFLAGS:=
2424
endif
2525

@@ -42,6 +42,16 @@ $(ROOT)/line_trace.done: $(ROOT)/line_trace
4242
@rm -f $(ROOT)/line_trace.output
4343
@touch $@
4444

45+
# https://issues.dlang.org/show_bug.cgi?id=21656
46+
$(ROOT)/line_trace_21656.done: $(ROOT)/line_trace
47+
@echo Testing line_trace_21656
48+
@mkdir -p $(ROOT)/line_trace_21656
49+
@touch $(ROOT)/line_trace_21656/line_trace
50+
$(QUIET)cd $(ROOT)/line_trace_21656 && PATH="..:$$PATH" $(TIMELIMIT)line_trace $(RUN_ARGS) > line_trace.output
51+
$(QUIET)$(SED) "s/\[0x[0-9a-f]*\]/\[ADDR\]/g; s/scope //g; s/Nl//g" $(ROOT)/line_trace_21656/line_trace.output | $(DIFF) line_trace.exp -
52+
@rm -rf $(ROOT)/line_trace_21656
53+
@touch $@
54+
4555
$(ROOT)/long_backtrace_trunc.done: $(ROOT)/long_backtrace_trunc
4656
@echo Testing long_backtrace_trunc
4757
$(QUIET)$(TIMELIMIT)$(ROOT)/long_backtrace_trunc $(RUN_ARGS) > $(ROOT)/long_backtrace_trunc.output

0 commit comments

Comments
 (0)