From 7ccfb958fa5e09b94e7b1ccc783375f23922fa77 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Thu, 3 May 2018 04:44:36 +0200 Subject: [PATCH 1/3] Fix Issue 18068 - No file names and line numbers in stack trace --- src/rt/backtrace/dwarf.d | 6 +++-- src/rt/backtrace/elf.d | 56 ++++++++++++++++++++++++++++++++++++++++ src/rt/backtrace/macho.d | 5 ++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/rt/backtrace/dwarf.d b/src/rt/backtrace/dwarf.d index f1853b2c95..8d2572043e 100644 --- a/src/rt/backtrace/dwarf.d +++ b/src/rt/backtrace/dwarf.d @@ -72,7 +72,7 @@ int traceHandlerOpApplyImpl(const void*[] callstack, scope int delegate(ref size foreach(size_t i; 0 .. callstack.length) locations[i].address = cast(size_t) callstack[i]; - resolveAddresses(debugLineSectionData, locations[]); + resolveAddresses(debugLineSectionData, locations[], image.baseAddress); } } @@ -108,7 +108,7 @@ int traceHandlerOpApplyImpl(const void*[] callstack, scope int delegate(ref size private: // the lifetime of the Location data is the lifetime of the mmapped ElfSection -void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations) @nogc nothrow +void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations, size_t baseAddress) @nogc nothrow { debug(DwarfDebugMachine) import core.stdc.stdio; @@ -202,6 +202,8 @@ void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations) runStateMachine(lph, program, standardOpcodeLengths, (size_t address, LocationInfo locInfo, bool isEndSequence) { + // adjust to ASLR offset + address += baseAddress; // If loc.line != -1, then it has been set previously. // Some implementations (eg. dmd) write an address to // the debug data multiple times, but so far I have found diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index 7a9b44f991..2c2dd9c87e 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -58,6 +58,62 @@ struct Image return null; } + + @property size_t baseAddress() + { + version(linux) + { + import core.sys.linux.link; + import core.sys.linux.elf; + } + else version(FreeBSD) + { + import core.sys.freebsd.sys.link_elf; + import core.sys.freebsd.sys.elf; + } + else version(DragonFlyBSD) + { + import core.sys.dragonflybsd.sys.link_elf; + import core.sys.dragonflybsd.sys.elf; + } + + static struct ElfAddress + { + size_t begin; + bool set; + } + ElfAddress elfAddress; + + // the DWARF addresses for DSOs are relative + const isDynamicSharedObject = (file.ehdr.e_type == ET_DYN); + if (!isDynamicSharedObject) + return 0; + + extern(C) int dl_iterate_phdr_cb_ngc_tracehandler(dl_phdr_info* info, size_t, void* elfObj) @nogc + { + auto obj = cast(ElfAddress*) elfObj; + // only take the first address as this will be the main binary + if (obj.set) + return 0; + + obj.set = true; + // search for the executable code segment + foreach (const ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) + { + if (phdr.p_type == PT_LOAD && phdr.p_flags & PF_X) + { + obj.begin = info.dlpi_addr + phdr.p_vaddr; + //obj.length = phdr.p_memsz; + } + } + // temporarily fall back to this + obj.begin = info.dlpi_addr; + //obj.length = info.dlpi_phdr.p_memsz; + return 0; + } + dl_iterate_phdr(&dl_iterate_phdr_cb_ngc_tracehandler, &elfAddress); + return elfAddress.begin; + } } private: diff --git a/src/rt/backtrace/macho.d b/src/rt/backtrace/macho.d index af43475323..3659110a8c 100644 --- a/src/rt/backtrace/macho.d +++ b/src/rt/backtrace/macho.d @@ -67,4 +67,9 @@ struct Image auto data = getsectiondata(self, "__DWARF", "__debug_line", &size); return data[0 .. size]; } + + @property size_t baseAddress() + { + return 0; + } } From 5142b4d125cea4754ee82ff2dbb594742c3af3f2 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Mon, 7 May 2018 20:44:58 +0200 Subject: [PATCH 2/3] Add shared library exception line_trace test --- test/exceptions/Makefile | 18 ++++++++++++++++++ test/exceptions/line_trace_shared.exp | 2 ++ test/exceptions/src/line_trace_shared.d | 5 +++++ test/exceptions/src/line_trace_shared_lib.d | 4 ++++ 4 files changed, 29 insertions(+) create mode 100644 test/exceptions/line_trace_shared.exp create mode 100644 test/exceptions/src/line_trace_shared.d create mode 100644 test/exceptions/src/line_trace_shared_lib.d diff --git a/test/exceptions/Makefile b/test/exceptions/Makefile index f13d797a58..22f0e9bde2 100644 --- a/test/exceptions/Makefile +++ b/test/exceptions/Makefile @@ -4,6 +4,9 @@ TESTS:=stderr_msg unittest_assert invalid_memory_operation unknown_gc static_dto ifeq ($(OS)-$(BUILD),linux-debug) TESTS:=$(TESTS) line_trace rt_trap_exceptions +ifeq ($(MODEL), 64) + TESTS+=line_trace_shared +endif LINE_TRACE_DFLAGS:=-L--export-dynamic endif ifeq ($(OS)-$(BUILD),freebsd-debug) @@ -33,6 +36,14 @@ $(ROOT)/line_trace.done: $(ROOT)/line_trace @rm -f $(ROOT)/line_trace.output @touch $@ +$(ROOT)/line_trace_shared.done: $(ROOT)/line_trace_shared + @echo Testing line_trace + ! LD_LIBRARY_PATH="$(ROOT)" $(QUIET)$(TIMELIMIT)$(ROOT)/line_trace_shared $(RUN_ARGS) 2> $(ROOT)/line_trace_shared.output + # Use sed to canonicalize line_trace_shared.output and compare against expected output in line_trace_shared.exp + $(QUIET)$(SED) "s/\[0x[0-9a-f]*\]/\[ADDR\]/g; s/scope //g; s/Nl//g" $(ROOT)/line_trace_shared.output | $(DIFF) -p line_trace_shared.exp - + @rm -f $(ROOT)/line_trace_shared.output + @touch $@ + $(ROOT)/chain.done: $(ROOT)/chain @echo Testing chain $(QUIET)$(TIMELIMIT)$(ROOT)/chain $(RUN_ARGS) > $(ROOT)/chain.output @@ -55,6 +66,13 @@ $(ROOT)/%.done: $(ROOT)/% $(ROOT)/unittest_assert: DFLAGS+=-unittest $(ROOT)/line_trace: DFLAGS+=$(LINE_TRACE_DFLAGS) + +$(ROOT)/line_trace_shared_lib.so: $(SRC)/line_trace_shared_lib.d + $(QUIET)$(DMD) $(DFLAGS) $(LINE_TRACE_DFLAGS) -shared -of$@ $< + +$(ROOT)/line_trace_shared: $(SRC)/line_trace_shared.d $(ROOT)/line_trace_shared_lib.so + $(QUIET)$(DMD) $(LINE_TRACE_DFLAGS) -Isrc -L-L$(ROOT) -L-l:line_trace_shared_lib.so -of$@ $< + $(ROOT)/%: $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< diff --git a/test/exceptions/line_trace_shared.exp b/test/exceptions/line_trace_shared.exp new file mode 100644 index 0000000000..894491b56f --- /dev/null +++ b/test/exceptions/line_trace_shared.exp @@ -0,0 +1,2 @@ +object.Exception@src/line_trace_shared_lib.d(3): exception +---------------- diff --git a/test/exceptions/src/line_trace_shared.d b/test/exceptions/src/line_trace_shared.d new file mode 100644 index 0000000000..e5f89e8148 --- /dev/null +++ b/test/exceptions/src/line_trace_shared.d @@ -0,0 +1,5 @@ +void main() +{ + import line_trace_shared_lib; + exception(); +} diff --git a/test/exceptions/src/line_trace_shared_lib.d b/test/exceptions/src/line_trace_shared_lib.d new file mode 100644 index 0000000000..3037c01af7 --- /dev/null +++ b/test/exceptions/src/line_trace_shared_lib.d @@ -0,0 +1,4 @@ +void exception() +{ + throw new Exception("exception"); +} From e263004bf461514c221a8224cad824cc078fac28 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Mon, 7 May 2018 21:55:34 +0200 Subject: [PATCH 3/3] Add DwarfDebugMachine debug logging --- src/rt/backtrace/dwarf.d | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rt/backtrace/dwarf.d b/src/rt/backtrace/dwarf.d index 8d2572043e..b9c217d9a9 100644 --- a/src/rt/backtrace/dwarf.d +++ b/src/rt/backtrace/dwarf.d @@ -204,6 +204,7 @@ void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations, { // adjust to ASLR offset address += baseAddress; + debug(DwarfDebugMachine) printf("-- offsetting 0x%x to 0x%x\n", address - baseAddress, address); // If loc.line != -1, then it has been set previously. // Some implementations (eg. dmd) write an address to // the debug data multiple times, but so far I have found