diff --git a/src/rt/backtrace/dwarf.d b/src/rt/backtrace/dwarf.d index f1853b2c95..b9c217d9a9 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,9 @@ void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations) runStateMachine(lph, program, standardOpcodeLengths, (size_t address, LocationInfo locInfo, bool isEndSequence) { + // 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 diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index 7a9b44f991..f10fb044ce 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -58,6 +58,61 @@ 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; + return 0; + } + } + // fall back to the base address of the object file + obj.begin = info.dlpi_addr; + 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; + } }