From fab4a68accf4e03af0b81c60c9fce548697b522e Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 11 Oct 2018 00:35:56 +0200 Subject: [PATCH 01/16] Extract ELF section reading from rt.backtrace.elf to core.elf Incl. some minor refactoring (pointer to ref, make `findSectionByName()` an ElfFile method, add `findSectionHeaderByName()` convenience method etc.). --- mak/DOCS | 1 + mak/SRCS | 1 + src/core/elf.d | 264 +++++++++++++++++++++++++++++++++++++ src/rt/backtrace/elf.d | 287 ++++------------------------------------- 4 files changed, 291 insertions(+), 262 deletions(-) create mode 100644 src/core/elf.d diff --git a/mak/DOCS b/mak/DOCS index 0bcce15cda..84e1d94214 100644 --- a/mak/DOCS +++ b/mak/DOCS @@ -6,6 +6,7 @@ DOCS=\ $(DOCDIR)\core_checkedint.html \ $(DOCDIR)\core_cpuid.html \ $(DOCDIR)\core_demangle.html \ + $(DOCDIR)\core_elf.html \ $(DOCDIR)\core_exception.html \ $(DOCDIR)\core_lifetime.html \ $(DOCDIR)\core_math.html \ diff --git a/mak/SRCS b/mak/SRCS index dd2aa23a2d..3d83763813 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -7,6 +7,7 @@ SRCS=\ src\core\checkedint.d \ src\core\cpuid.d \ src\core\demangle.d \ + src\core\elf.d \ src\core\exception.d \ src\core\lifetime.d \ src\core\math.d \ diff --git a/src/core/elf.d b/src/core/elf.d new file mode 100644 index 0000000000..e1c30c3137 --- /dev/null +++ b/src/core/elf.d @@ -0,0 +1,264 @@ +/** + * This code reads ELF files and sections using memory mapped IO. + * + * Reference: http://www.dwarfstd.org/ + * + * Copyright: Copyright Digital Mars 2015 - 2015. + * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). + * Authors: Yazan Dabain + * Source: $(DRUNTIMESRC core/elf.d) + */ + +module core.elf; + +version (linux) version = linux_or_bsd; +else version (FreeBSD) version = linux_or_bsd; +else version (DragonFlyBSD) version = linux_or_bsd; + +version (linux_or_bsd): + +import core.sys.posix.fcntl; +import core.sys.posix.unistd; + +version (linux) import core.sys.linux.elf; +version (FreeBSD) import core.sys.freebsd.sys.elf; +version (DragonFlyBSD) import core.sys.dragonflybsd.sys.elf; + +struct ElfFile +{ + static bool open(const(char)* path, out ElfFile file) @nogc nothrow + { + file.fd = .open(path, O_RDONLY); + if (file.fd < 0) + return false; + + // memory map header + file.ehdr = MMapRegion!Elf_Ehdr(file.fd, 0, Elf_Ehdr.sizeof); + return isValidElfHeader(*file.ehdr); + } + + @disable this(this); + + ~this() @nogc nothrow + { + if (fd != -1) close(fd); + } + + int fd = -1; + MMapRegion!Elf_Ehdr ehdr; + + bool findSectionHeaderByName(const(char)[] sectionName, out ElfSectionHeader header) const @nogc nothrow + { + const index = findSectionIndexByName(sectionName); + if (index == -1) + return false; + header = ElfSectionHeader(this, index); + return true; + } + + size_t findSectionIndexByName(const(char)[] sectionName) const @nogc nothrow + { + const stringSectionHeader = ElfSectionHeader(this, ehdr.e_shstrndx); + const stringSection = ElfSection(this, stringSectionHeader); + + foreach (i; 0 .. ehdr.e_shnum) + { + auto sectionHeader = ElfSectionHeader(this, i); + auto currentName = getSectionName(stringSection, sectionHeader.sh_name); + if (sectionName == currentName) + return i; + } + + // not found + return -1; + } +} + +struct ElfSectionHeader +{ + this(ref const ElfFile file, size_t index) @nogc nothrow + { + assert(Elf_Shdr.sizeof == file.ehdr.e_shentsize); + shdr = MMapRegion!Elf_Shdr( + file.fd, + file.ehdr.e_shoff + index * file.ehdr.e_shentsize, + file.ehdr.e_shentsize + ); + } + + @disable this(this); + + alias shdr this; + MMapRegion!Elf_Shdr shdr; +} + +struct ElfSection +{ + this(ref const ElfFile file, ref const ElfSectionHeader shdr) @nogc nothrow + { + data = MMapRegion!void( + file.fd, + shdr.sh_offset, + shdr.sh_size, + ); + + length = shdr.sh_size; + } + + @disable this(this); + + const(void)[] get() const @nogc nothrow + { + return data.get()[0 .. length]; + } + + alias get this; + + MMapRegion!void data; + size_t length; +} + +private: + +const(char)[] getSectionName(ref const ElfSection stringSection, size_t nameIndex) @nogc nothrow +{ + const data = cast(const(ubyte[])) stringSection.get(); + + foreach (i; nameIndex .. data.length) + { + if (data[i] == 0) + return cast(const(char)[]) data[nameIndex .. i]; + } + + return null; +} + +bool isValidElfHeader(ref const Elf_Ehdr ehdr) @nogc nothrow +{ + if (ehdr.e_ident[EI_MAG0] != ELFMAG0) return false; + if (ehdr.e_ident[EI_MAG1] != ELFMAG1) return false; + if (ehdr.e_ident[EI_MAG2] != ELFMAG2) return false; + if (ehdr.e_ident[EI_MAG3] != ELFMAG3) return false; + + // elf class and data encoding should match target's config + if (ehdr.e_ident[EI_CLASS] != ELFCLASS) return false; + if (ehdr.e_ident[EI_DATA] != ELFDATA ) return false; + + return true; +} + +struct MMapRegion(T) +{ + import core.sys.posix.sys.mman; + import core.sys.posix.unistd; + + this(int fd, size_t offset, size_t length) @nogc nothrow + { + auto pagesize = sysconf(_SC_PAGESIZE); + + auto realOffset = (offset / pagesize) * pagesize; + offsetDiff = offset - realOffset; + realLength = length + offsetDiff; + + mptr = mmap(null, realLength, PROT_READ, MAP_PRIVATE, fd, realOffset); + } + + @disable this(this); + + ~this() @nogc nothrow + { + if (mptr) munmap(mptr, realLength); + } + + const(T)* get() const @nogc nothrow + { + return cast(T*)(mptr + offsetDiff); + } + + alias get this; + + size_t realLength; + size_t offsetDiff; + void* mptr; +} + +version (X86) +{ + alias Elf_Ehdr = Elf32_Ehdr; + alias Elf_Shdr = Elf32_Shdr; + enum ELFCLASS = ELFCLASS32; +} +else version (X86_64) +{ + version (D_X32) + { + alias Elf_Ehdr = Elf32_Ehdr; + alias Elf_Shdr = Elf32_Shdr; + enum ELFCLASS = ELFCLASS32; + } + else + { + alias Elf_Ehdr = Elf64_Ehdr; + alias Elf_Shdr = Elf64_Shdr; + enum ELFCLASS = ELFCLASS64; + } +} +else version (ARM) +{ + alias Elf_Ehdr = Elf32_Ehdr; + alias Elf_Shdr = Elf32_Shdr; + enum ELFCLASS = ELFCLASS32; +} +else version (AArch64) +{ + alias Elf_Ehdr = Elf64_Ehdr; + alias Elf_Shdr = Elf64_Shdr; + enum ELFCLASS = ELFCLASS64; +} +else version (PPC) +{ + alias Elf_Ehdr = Elf32_Ehdr; + alias Elf_Shdr = Elf32_Shdr; + enum ELFCLASS = ELFCLASS32; +} +else version (PPC64) +{ + alias Elf_Ehdr = Elf64_Ehdr; + alias Elf_Shdr = Elf64_Shdr; + enum ELFCLASS = ELFCLASS64; +} +else version (MIPS) +{ + alias Elf_Ehdr = Elf32_Ehdr; + alias Elf_Shdr = Elf32_Shdr; + enum ELFCLASS = ELFCLASS32; +} +else version (MIPS64) +{ + alias Elf_Ehdr = Elf64_Ehdr; + alias Elf_Shdr = Elf64_Shdr; + enum ELFCLASS = ELFCLASS64; +} +else version (SystemZ) +{ + alias Elf_Ehdr = Elf64_Ehdr; + alias Elf_Shdr = Elf64_Shdr; + enum ELFCLASS = ELFCLASS64; +} +else +{ + static assert(0, "unsupported architecture"); +} + +version (LittleEndian) +{ + alias ELFDATA = ELFDATA2LSB; +} +else version (BigEndian) +{ + alias ELFDATA = ELFDATA2MSB; +} +else +{ + static assert(0, "unsupported byte order"); +} diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index c16a204c36..802a4a5b42 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -17,6 +17,7 @@ else version (DragonFlyBSD) version = linux_or_bsd; version (linux_or_bsd): +import core.elf; import core.sys.posix.fcntl; import core.sys.posix.unistd; @@ -30,9 +31,23 @@ struct Image static Image openSelf() { - Image image; + version (linux) + { + auto selfPath = "/proc/self/exe".ptr; + } + else version (FreeBSD) + { + char[1024] selfPathBuffer = void; + auto selfPath = getFreeBSDExePath(selfPathBuffer[]); + if (selfPath is null) return false; + } + else version (DragonFlyBSD) + { + auto selfPath = "/proc/curproc/file".ptr; + } - if (!ElfFile.openSelf(&image.file)) + Image image; + if (!ElfFile.open(selfPath, image.file)) image.file = ElfFile.init; return image; @@ -45,21 +60,16 @@ struct Image const(ubyte)[] getDebugLineSectionData() { - auto stringSectionHeader = ElfSectionHeader(&file, file.ehdr.e_shstrndx); - auto stringSection = ElfSection(&file, &stringSectionHeader); + ElfSectionHeader dbgSectionHeader; + if (!file.findSectionHeaderByName(".debug_line", dbgSectionHeader)) + return null; - auto dbgSectionIndex = findSectionByName(&file, &stringSection, ".debug_line"); - if (dbgSectionIndex != -1) - { - auto dbgSectionHeader = ElfSectionHeader(&file, dbgSectionIndex); - // we don't support compressed debug sections - if ((dbgSectionHeader.shdr.sh_flags & SHF_COMPRESSED) != 0) - return null; - // debug_line section found and loaded - return ElfSection(&file, &dbgSectionHeader); - } + // we don't support compressed debug sections + if ((dbgSectionHeader.shdr.sh_flags & SHF_COMPRESSED) != 0) + return null; - return null; + // debug_line section found and loaded + return cast(const(ubyte)[]) ElfSection(file, dbgSectionHeader).get(); } @property size_t baseAddress() @@ -112,123 +122,6 @@ struct Image private: -struct ElfFile -{ - static bool openSelf(ElfFile* file) @nogc nothrow - { - version (linux) - { - auto selfPath = "/proc/self/exe".ptr; - } - else version (FreeBSD) - { - char[1024] selfPathBuffer = void; - auto selfPath = getFreeBSDExePath(selfPathBuffer[]); - if (selfPath is null) return false; - } - else version (DragonFlyBSD) - { - auto selfPath = "/proc/curproc/file".ptr; - } - - file.fd = open(selfPath, O_RDONLY); - if (file.fd >= 0) - { - // memory map header - file.ehdr = MMapRegion!Elf_Ehdr(file.fd, 0, Elf_Ehdr.sizeof); - if (file.ehdr.isValidElfHeader()) - return true; - else - return false; - } - else - return false; - } - - @disable this(this); - - ~this() @nogc nothrow - { - if (fd != -1) close(fd); - } - - int fd = -1; - MMapRegion!Elf_Ehdr ehdr; -} - -struct ElfSectionHeader -{ - this(const(ElfFile)* file, size_t index) @nogc nothrow - { - assert(Elf_Shdr.sizeof == file.ehdr.e_shentsize); - shdr = MMapRegion!Elf_Shdr( - file.fd, - file.ehdr.e_shoff + index * file.ehdr.e_shentsize, - file.ehdr.e_shentsize - ); - } - - @disable this(this); - - alias shdr this; - MMapRegion!Elf_Shdr shdr; -} - -struct ElfSection -{ - this(ElfFile* file, ElfSectionHeader* shdr) @nogc nothrow - { - data = MMapRegion!ubyte( - file.fd, - shdr.sh_offset, - shdr.sh_size, - ); - - length = shdr.sh_size; - } - - @disable this(this); - - const(ubyte)[] get() @nogc nothrow - { - return data.get()[0 .. length]; - } - - alias get this; - - MMapRegion!ubyte data; - size_t length; -} - -const(char)[] getSectionName(const(ElfFile)* file, ElfSection* stringSection, size_t nameIndex) @nogc nothrow -{ - const(ubyte)[] data = stringSection.get(); - - foreach (i; nameIndex .. data.length) - { - if (data[i] == 0) - return cast(const(char)[])data[nameIndex .. i]; - } - - return null; -} - -size_t findSectionByName(const(ElfFile)* file, ElfSection* stringSection, const(char)[] sectionName) @nogc nothrow -{ - foreach (s; 0 .. file.ehdr.e_shnum) - { - auto sectionHeader = ElfSectionHeader(file, s); - auto currentName = getSectionName(file, stringSection, sectionHeader.sh_name); - if (sectionName == currentName) - return s; // TODO: attempt to move ElfSectionHeader instead of returning index - } - - // not found - return -1; -} - -private: - version (FreeBSD) { extern (C) int sysctl(const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen) @nogc nothrow; @@ -251,133 +144,3 @@ version (FreeBSD) return buffer.ptr; } } - -bool isValidElfHeader(const(Elf_Ehdr)* ehdr) @nogc nothrow -{ - if (ehdr.e_ident[EI_MAG0] != ELFMAG0) return false; - if (ehdr.e_ident[EI_MAG1] != ELFMAG1) return false; - if (ehdr.e_ident[EI_MAG2] != ELFMAG2) return false; - if (ehdr.e_ident[EI_MAG3] != ELFMAG3) return false; - - // elf class and data encoding should match target's config - if (ehdr.e_ident[EI_CLASS] != ELFCLASS) return false; - if (ehdr.e_ident[EI_DATA] != ELFDATA ) return false; - - return true; -} - -struct MMapRegion(T) -{ - import core.sys.posix.sys.mman; - import core.sys.posix.unistd; - - this(int fd, size_t offset, size_t length) @nogc nothrow - { - auto pagesize = sysconf(_SC_PAGESIZE); - - auto realOffset = (offset / pagesize) * pagesize; - offsetDiff = offset - realOffset; - realLength = length + offsetDiff; - - mptr = mmap(null, realLength, PROT_READ, MAP_PRIVATE, fd, realOffset); - } - - @disable this(this); - - ~this() @nogc nothrow - { - if (mptr) munmap(mptr, realLength); - } - - const(T)* get() const @nogc nothrow - { - return cast(T*)(mptr + offsetDiff); - } - - alias get this; - - size_t realLength; - size_t offsetDiff; - void* mptr; -} - -version (X86) -{ - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; -} -else version (X86_64) -{ - version (D_X32) - { - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; - } - else - { - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; - } -} -else version (ARM) -{ - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; -} -else version (AArch64) -{ - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; -} -else version (PPC) -{ - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; -} -else version (PPC64) -{ - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; -} -else version (MIPS) -{ - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; -} -else version (MIPS64) -{ - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; -} -else version (SystemZ) -{ - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; -} -else -{ - static assert(0, "unsupported architecture"); -} - -version (LittleEndian) -{ - alias ELFDATA = ELFDATA2LSB; -} -else version (BigEndian) -{ - alias ELFDATA = ELFDATA2MSB; -} -else -{ - static assert(0, "unsupported byte order"); -} From 91797287090b183210a82f67441fa0e07c663ff4 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 11 Oct 2018 22:12:44 +0200 Subject: [PATCH 02/16] rt.backtrace.elf: Prevent munmap()ping the .debug_line section data before use --- src/rt/backtrace/elf.d | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index 802a4a5b42..68d0654896 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -68,8 +68,14 @@ struct Image if ((dbgSectionHeader.shdr.sh_flags & SHF_COMPRESSED) != 0) return null; - // debug_line section found and loaded - return cast(const(ubyte)[]) ElfSection(file, dbgSectionHeader).get(); + auto dbgSection = ElfSection(file, dbgSectionHeader); + const sectionData = cast(const(ubyte)[]) dbgSection.get(); + // do not munmap() the section data to be returned + import core.stdc.string; + ElfSection initialSection; + memcpy(&dbgSection, &initialSection, ElfSection.sizeof); + + return sectionData; } @property size_t baseAddress() From 2e4b2253b5270927267f86c6c8fe850d784ed2b0 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 11 Oct 2018 22:44:31 +0200 Subject: [PATCH 03/16] core.elf: Support simple iteration over the currently loaded shared objects --- src/core/elf.d | 37 +++++++++++++++++++++++++++++++++--- src/rt/backtrace/elf.d | 43 ++++++------------------------------------ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/core/elf.d b/src/core/elf.d index e1c30c3137..ce3dd26179 100644 --- a/src/core/elf.d +++ b/src/core/elf.d @@ -20,9 +20,40 @@ version (linux_or_bsd): import core.sys.posix.fcntl; import core.sys.posix.unistd; -version (linux) import core.sys.linux.elf; -version (FreeBSD) import core.sys.freebsd.sys.elf; -version (DragonFlyBSD) import core.sys.dragonflybsd.sys.elf; +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; +} + +/**** + * Enables iterating over the process' currently loaded shared objects. + */ +struct SharedObjects +{ + alias Callback = int delegate(ref const dl_phdr_info) @nogc nothrow; + + static int opApply(scope Callback dg) @nogc nothrow + { + extern(C) int nativeCallback(dl_phdr_info* info, size_t, void* data) @nogc nothrow + { + auto dg = *cast(Callback*) data; + return dg(*info); + } + + return dl_iterate_phdr(&nativeCallback, &dg); + } +} struct ElfFile { diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index 68d0654896..f2d0d7f7a0 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -18,8 +18,6 @@ else version (DragonFlyBSD) version = linux_or_bsd; version (linux_or_bsd): import core.elf; -import core.sys.posix.fcntl; -import core.sys.posix.unistd; version (linux) import core.sys.linux.elf; version (FreeBSD) import core.sys.freebsd.sys.elf; @@ -80,49 +78,20 @@ struct Image @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 + size_t base = 0; + foreach (ref info; SharedObjects) { - 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; - - // use the base address of the object file - obj.begin = info.dlpi_addr; - return 0; + base = info.dlpi_addr; + break; } - dl_iterate_phdr(&dl_iterate_phdr_cb_ngc_tracehandler, &elfAddress); - return elfAddress.begin; + + return base; } } From 296dc2f265c384362c6638924be3d9fa698b5d8e Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 11 Oct 2018 22:47:28 +0200 Subject: [PATCH 04/16] core.elf: Avoid code duplication --- src/core/elf.d | 96 ++++++++++++-------------------------------------- 1 file changed, 23 insertions(+), 73 deletions(-) diff --git a/src/core/elf.d b/src/core/elf.d index ce3dd26179..01e8917fd2 100644 --- a/src/core/elf.d +++ b/src/core/elf.d @@ -41,11 +41,12 @@ else version (DragonFlyBSD) */ struct SharedObjects { - alias Callback = int delegate(ref const dl_phdr_info) @nogc nothrow; +@nogc nothrow: + alias Callback = int delegate(ref const dl_phdr_info); - static int opApply(scope Callback dg) @nogc nothrow + static int opApply(scope Callback dg) { - extern(C) int nativeCallback(dl_phdr_info* info, size_t, void* data) @nogc nothrow + extern(C) int nativeCallback(dl_phdr_info* info, size_t, void* data) { auto dg = *cast(Callback*) data; return dg(*info); @@ -57,7 +58,8 @@ struct SharedObjects struct ElfFile { - static bool open(const(char)* path, out ElfFile file) @nogc nothrow +@nogc nothrow: + static bool open(const(char)* path, out ElfFile file) { file.fd = .open(path, O_RDONLY); if (file.fd < 0) @@ -70,7 +72,7 @@ struct ElfFile @disable this(this); - ~this() @nogc nothrow + ~this() { if (fd != -1) close(fd); } @@ -78,7 +80,7 @@ struct ElfFile int fd = -1; MMapRegion!Elf_Ehdr ehdr; - bool findSectionHeaderByName(const(char)[] sectionName, out ElfSectionHeader header) const @nogc nothrow + bool findSectionHeaderByName(const(char)[] sectionName, out ElfSectionHeader header) const { const index = findSectionIndexByName(sectionName); if (index == -1) @@ -87,7 +89,7 @@ struct ElfFile return true; } - size_t findSectionIndexByName(const(char)[] sectionName) const @nogc nothrow + size_t findSectionIndexByName(const(char)[] sectionName) const { const stringSectionHeader = ElfSectionHeader(this, ehdr.e_shstrndx); const stringSection = ElfSection(this, stringSectionHeader); @@ -107,7 +109,8 @@ struct ElfFile struct ElfSectionHeader { - this(ref const ElfFile file, size_t index) @nogc nothrow +@nogc nothrow: + this(ref const ElfFile file, size_t index) { assert(Elf_Shdr.sizeof == file.ehdr.e_shentsize); shdr = MMapRegion!Elf_Shdr( @@ -125,7 +128,8 @@ struct ElfSectionHeader struct ElfSection { - this(ref const ElfFile file, ref const ElfSectionHeader shdr) @nogc nothrow +@nogc nothrow: + this(ref const ElfFile file, ref const ElfSectionHeader shdr) { data = MMapRegion!void( file.fd, @@ -138,7 +142,7 @@ struct ElfSection @disable this(this); - const(void)[] get() const @nogc nothrow + const(void)[] get() const { return data.get()[0 .. length]; } @@ -149,9 +153,9 @@ struct ElfSection size_t length; } -private: +private @nogc nothrow: -const(char)[] getSectionName(ref const ElfSection stringSection, size_t nameIndex) @nogc nothrow +const(char)[] getSectionName(ref const ElfSection stringSection, size_t nameIndex) { const data = cast(const(ubyte[])) stringSection.get(); @@ -164,7 +168,7 @@ const(char)[] getSectionName(ref const ElfSection stringSection, size_t nameInde return null; } -bool isValidElfHeader(ref const Elf_Ehdr ehdr) @nogc nothrow +bool isValidElfHeader(ref const Elf_Ehdr ehdr) { if (ehdr.e_ident[EI_MAG0] != ELFMAG0) return false; if (ehdr.e_ident[EI_MAG1] != ELFMAG1) return false; @@ -180,10 +184,11 @@ bool isValidElfHeader(ref const Elf_Ehdr ehdr) @nogc nothrow struct MMapRegion(T) { +@nogc nothrow: import core.sys.posix.sys.mman; import core.sys.posix.unistd; - this(int fd, size_t offset, size_t length) @nogc nothrow + this(int fd, size_t offset, size_t length) { auto pagesize = sysconf(_SC_PAGESIZE); @@ -196,12 +201,12 @@ struct MMapRegion(T) @disable this(this); - ~this() @nogc nothrow + ~this() { if (mptr) munmap(mptr, realLength); } - const(T)* get() const @nogc nothrow + const(T)* get() const { return cast(T*)(mptr + offsetDiff); } @@ -213,73 +218,18 @@ struct MMapRegion(T) void* mptr; } -version (X86) -{ - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; -} -else version (X86_64) -{ - version (D_X32) - { - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; - } - else - { - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; - } -} -else version (ARM) -{ - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; -} -else version (AArch64) -{ - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; -} -else version (PPC) -{ - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; -} -else version (PPC64) +version (D_LP64) { alias Elf_Ehdr = Elf64_Ehdr; alias Elf_Shdr = Elf64_Shdr; enum ELFCLASS = ELFCLASS64; } -else version (MIPS) +else { alias Elf_Ehdr = Elf32_Ehdr; alias Elf_Shdr = Elf32_Shdr; enum ELFCLASS = ELFCLASS32; } -else version (MIPS64) -{ - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; -} -else version (SystemZ) -{ - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; -} -else -{ - static assert(0, "unsupported architecture"); -} version (LittleEndian) { From 65712a9ea27fa7ec0354eaf3d57b8a31a755af19 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 11 Oct 2018 23:07:04 +0200 Subject: [PATCH 05/16] core.elf: Add ElfFile convenience ctor taking a file descriptor --- src/core/elf.d | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/core/elf.d b/src/core/elf.d index 01e8917fd2..44aa058518 100644 --- a/src/core/elf.d +++ b/src/core/elf.d @@ -61,13 +61,18 @@ struct ElfFile @nogc nothrow: static bool open(const(char)* path, out ElfFile file) { - file.fd = .open(path, O_RDONLY); - if (file.fd < 0) - return false; + file = ElfFile(.open(path, O_RDONLY)); + return file.isValid(); + } - // memory map header - file.ehdr = MMapRegion!Elf_Ehdr(file.fd, 0, Elf_Ehdr.sizeof); - return isValidElfHeader(*file.ehdr); + this(int fd) + { + this.fd = fd; + if (fd != -1) + { + // memory map header + this.ehdr = MMapRegion!Elf_Ehdr(fd, 0, Elf_Ehdr.sizeof); + } } @disable this(this); @@ -80,6 +85,11 @@ struct ElfFile int fd = -1; MMapRegion!Elf_Ehdr ehdr; + bool isValid() const + { + return fd != -1 && isValidElfHeader(*ehdr); + } + bool findSectionHeaderByName(const(char)[] sectionName, out ElfSectionHeader header) const { const index = findSectionIndexByName(sectionName); From fe6639d8df0a026d3e2e97c7847d2d00480d3c81 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 14 Oct 2018 13:07:11 +0200 Subject: [PATCH 06/16] Move some functionality from rt.sections_elf_shared to core.elf --- src/core/elf.d | 110 +++++++++++++++++++++++++++++- src/rt/backtrace/elf.d | 4 +- src/rt/sections_elf_shared.d | 126 +++++------------------------------ 3 files changed, 127 insertions(+), 113 deletions(-) diff --git a/src/core/elf.d b/src/core/elf.d index 44aa058518..5e4aae9bdc 100644 --- a/src/core/elf.d +++ b/src/core/elf.d @@ -5,7 +5,7 @@ * * Copyright: Copyright Digital Mars 2015 - 2015. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). - * Authors: Yazan Dabain + * Authors: Yazan Dabain, Martin Kinkelin * Source: $(DRUNTIMESRC core/elf.d) */ @@ -42,20 +42,124 @@ else version (DragonFlyBSD) struct SharedObjects { @nogc nothrow: - alias Callback = int delegate(ref const dl_phdr_info); + alias Callback = int delegate(SharedObject); static int opApply(scope Callback dg) { extern(C) int nativeCallback(dl_phdr_info* info, size_t, void* data) { auto dg = *cast(Callback*) data; - return dg(*info); + return dg(SharedObject(*info)); } return dl_iterate_phdr(&nativeCallback, &dg); } } +version (linux) +{ + import core.sys.linux.errno : program_invocation_name; +} +else +{ + extern(C) const(char)* getprogname() nothrow @nogc; +} + +struct SharedObject +{ +@nogc nothrow: + alias ProgramHeader = const(ElfW!"Phdr"); + + /**** + * Finds the shared object containing the specified address in one of its segments. + */ + static bool findForAddress(const scope void* address, out SharedObject result) + { + version (linux) enum IterateManually = true; + else version (NetBSD) enum IterateManually = true; + else enum IterateManually = false; + + static if (IterateManually) + { + foreach (object; SharedObjects) + { + ProgramHeader* segment; + if (object.findSegmentForAddress(address, segment)) + { + result = object; + return true; + } + } + return false; + } + else + { + return !!_rtld_addr_phdr(address, &result.info); + } + } + + dl_phdr_info info; + + void* baseAddress() const + { + return cast(void*) info.dlpi_addr; + } + + const(char)[] name() const + { + const(char)* cstr = info.dlpi_name; + + // the main executable has an empty name + if (cstr[0] == 0) + { + version (linux) + { + cstr = program_invocation_name; + } + else + { + cstr = getprogname(); + } + } + + import core.stdc.string; + return cstr[0 .. strlen(cstr)]; + } + + /**** + * Iterates over this object's segments. + */ + int opApply(scope int delegate(ref ProgramHeader) @nogc nothrow dg) const + { + foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) + { + const r = dg(phdr); + if (r != 0) + return r; + } + return 0; + } + + bool findSegmentForAddress(const scope void* address, out ProgramHeader* result) const + { + if (address < baseAddress()) + return false; + + foreach (ref phdr; this) + { + const begin = baseAddress() + phdr.p_vaddr; + if (cast(size_t)(address - begin) < phdr.p_memsz) + { + result = &phdr; + return true; + } + } + return false; + } +} + +// file-based I/O: + struct ElfFile { @nogc nothrow: diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index f2d0d7f7a0..39e02a40a4 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -84,10 +84,10 @@ struct Image return 0; size_t base = 0; - foreach (ref info; SharedObjects) + foreach (object; SharedObjects) { // only take the first address as this will be the main binary - base = info.dlpi_addr; + base = cast(size_t) object.baseAddress(); break; } diff --git a/src/rt/sections_elf_shared.d b/src/rt/sections_elf_shared.d index 767d1a682c..88f907b622 100644 --- a/src/rt/sections_elf_shared.d +++ b/src/rt/sections_elf_shared.d @@ -20,6 +20,7 @@ else enum SharedELF = false; static if (SharedELF): // debug = PRINTF; +import core.elf; import core.memory; import core.stdc.config; import core.stdc.stdio; @@ -413,17 +414,17 @@ extern(C) void _d_dso_registry(CompilerDSOData* data) pdso._moduleGroup = ModuleGroup(toRange(data._minfo_beg, data._minfo_end)); - dl_phdr_info info = void; - const headerFound = findDSOInfoForAddr(data._slot, &info); - safeAssert(headerFound, "Failed to find image header."); + SharedObject object = void; + const objectFound = SharedObject.findForAddress(data._slot, object); + safeAssert(objectFound, "Failed to find shared ELF object."); - scanSegments(info, pdso); + scanSegments(object, pdso); version (Shared) { auto handle = handleForAddr(data._slot); - getDependencies(info, pdso._deps); + getDependencies(object, pdso._deps); pdso._handle = handle; setDSOForHandle(pdso, pdso._handle); @@ -696,15 +697,15 @@ version (Shared) !pthread_mutex_unlock(&_handleToDSOMutex) || assert(0); } - void getDependencies(const scope ref dl_phdr_info info, ref Array!(DSO*) deps) + void getDependencies(const scope ref SharedObject object, ref Array!(DSO*) deps) { // get the entries of the .dynamic section ElfW!"Dyn"[] dyns; - foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) + foreach (ref phdr; object) { if (phdr.p_type == PT_DYNAMIC) { - auto p = cast(ElfW!"Dyn"*)(info.dlpi_addr + (phdr.p_vaddr & ~(size_t.sizeof - 1))); + auto p = cast(ElfW!"Dyn"*)(object.baseAddress() + (phdr.p_vaddr & ~(size_t.sizeof - 1))); dyns = p[0 .. phdr.p_memsz / ElfW!"Dyn".sizeof]; break; } @@ -716,15 +717,15 @@ version (Shared) if (dyn.d_tag == DT_STRTAB) { version (CRuntime_Musl) - strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate + strtab = cast(const(char)*)(object.baseAddress() + dyn.d_un.d_ptr); // relocate else version (linux) strtab = cast(const(char)*)dyn.d_un.d_ptr; else version (FreeBSD) - strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate + strtab = cast(const(char)*)(object.baseAddress() + dyn.d_un.d_ptr); // relocate else version (NetBSD) - strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate + strtab = cast(const(char)*)(object.baseAddress() + dyn.d_un.d_ptr); // relocate else version (DragonFlyBSD) - strtab = cast(const(char)*)(info.dlpi_addr + dyn.d_un.d_ptr); // relocate + strtab = cast(const(char)*)(object.baseAddress() + dyn.d_un.d_ptr); // relocate else static assert(0, "unimplemented"); break; @@ -764,21 +765,21 @@ version (Shared) * Scan segments in Linux dl_phdr_info struct and store * the TLS and writeable data segments in *pdso. */ -void scanSegments(const scope ref dl_phdr_info info, DSO* pdso) nothrow @nogc +void scanSegments(const scope ref SharedObject object, DSO* pdso) nothrow @nogc { - foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) + foreach (ref phdr; object) { switch (phdr.p_type) { case PT_LOAD: if (phdr.p_flags & PF_W) // writeable data segment { - auto beg = cast(void*)(info.dlpi_addr + (phdr.p_vaddr & ~(size_t.sizeof - 1))); + auto beg = object.baseAddress() + (phdr.p_vaddr & ~(size_t.sizeof - 1)); pdso._gcRanges.insertBack(beg[0 .. phdr.p_memsz]); } version (Shared) if (phdr.p_flags & PF_X) // code segment { - auto beg = cast(void*)(info.dlpi_addr + (phdr.p_vaddr & ~(size_t.sizeof - 1))); + auto beg = object.baseAddress() + (phdr.p_vaddr & ~(size_t.sizeof - 1)); pdso._codeSegments.insertBack(beg[0 .. phdr.p_memsz]); } break; @@ -790,7 +791,7 @@ void scanSegments(const scope ref dl_phdr_info info, DSO* pdso) nothrow @nogc // uClibc doesn't provide a 'dlpi_tls_modid' definition } else - pdso._tlsMod = info.dlpi_tls_modid; + pdso._tlsMod = object.info.dlpi_tls_modid; pdso._tlsSize = phdr.p_memsz; break; @@ -800,97 +801,6 @@ void scanSegments(const scope ref dl_phdr_info info, DSO* pdso) nothrow @nogc } } -/************************** - * Input: - * result where the output is to be written; dl_phdr_info is an OS struct - * Returns: - * true if found, and *result is filled in - * References: - * http://linux.die.net/man/3/dl_iterate_phdr - */ -bool findDSOInfoForAddr(in void* addr, dl_phdr_info* result=null) nothrow @nogc -{ - version (linux) enum IterateManually = true; - else version (NetBSD) enum IterateManually = true; - else enum IterateManually = false; - - static if (IterateManually) - { - static struct DG { const(void)* addr; dl_phdr_info* result; } - - extern(C) int callback(dl_phdr_info* info, size_t sz, void* arg) nothrow @nogc - { - auto p = cast(DG*)arg; - if (findSegmentForAddr(*info, p.addr)) - { - if (p.result !is null) *p.result = *info; - return 1; // break; - } - return 0; // continue iteration - } - - auto dg = DG(addr, result); - - /* OS function that walks through the list of an application's shared objects and - * calls 'callback' once for each object, until either all shared objects - * have been processed or 'callback' returns a nonzero value. - */ - return dl_iterate_phdr(&callback, &dg) != 0; - } - else version (FreeBSD) - { - return !!_rtld_addr_phdr(addr, result); - } - else version (DragonFlyBSD) - { - return !!_rtld_addr_phdr(addr, result); - } - else - static assert(0, "unimplemented"); -} - -/********************************* - * Determine if 'addr' lies within shared object 'info'. - * If so, return true and fill in 'result' with the corresponding ELF program header. - */ -bool findSegmentForAddr(const scope ref dl_phdr_info info, const scope void* addr, ElfW!"Phdr"* result=null) nothrow @nogc -{ - if (addr < cast(void*)info.dlpi_addr) // less than base address of object means quick reject - return false; - - foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) - { - auto beg = cast(void*)(info.dlpi_addr + phdr.p_vaddr); - if (cast(size_t)(addr - beg) < phdr.p_memsz) - { - if (result !is null) *result = phdr; - return true; - } - } - return false; -} - -version (linux) import core.sys.linux.errno : program_invocation_name; -// should be in core.sys.freebsd.stdlib -version (FreeBSD) extern(C) const(char)* getprogname() nothrow @nogc; -version (DragonFlyBSD) extern(C) const(char)* getprogname() nothrow @nogc; -version (NetBSD) extern(C) const(char)* getprogname() nothrow @nogc; - -@property const(char)* progname() nothrow @nogc -{ - version (linux) return program_invocation_name; - version (FreeBSD) return getprogname(); - version (DragonFlyBSD) return getprogname(); - version (NetBSD) return getprogname(); -} - -const(char)[] dsoName(const char* dlpi_name) nothrow @nogc -{ - // the main executable doesn't have a name in its dlpi_name field - const char* p = dlpi_name[0] != 0 ? dlpi_name : progname; - return p[0 .. strlen(p)]; -} - /************************** * Input: * addr an internal address of a DSO From d0065616713b26a7759f1d184de529be7535c9bc Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 14 Oct 2018 16:35:00 +0200 Subject: [PATCH 07/16] Slight core.elf refactoring --- src/core/elf.d | 90 ++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 54 deletions(-) diff --git a/src/core/elf.d b/src/core/elf.d index 5e4aae9bdc..d9f0b79fea 100644 --- a/src/core/elf.d +++ b/src/core/elf.d @@ -1,5 +1,7 @@ /** - * This code reads ELF files and sections using memory mapped IO. + * This code simplifies working with ELF binaries, e.g., iterating + * over loaded shared objects & their segments as well as reading + * headers and sections from ELF files. * * Reference: http://www.dwarfstd.org/ * @@ -11,8 +13,8 @@ module core.elf; -version (linux) version = linux_or_bsd; -else version (FreeBSD) version = linux_or_bsd; +version (linux) version = linux_or_bsd; +else version (FreeBSD) version = linux_or_bsd; else version (DragonFlyBSD) version = linux_or_bsd; version (linux_or_bsd): @@ -36,6 +38,10 @@ else version (DragonFlyBSD) import core.sys.dragonflybsd.sys.elf; } +alias Elf_Phdr = ElfW!"Phdr"; +alias Elf_Ehdr = ElfW!"Ehdr"; +alias Elf_Shdr = ElfW!"Shdr"; + /**** * Enables iterating over the process' currently loaded shared objects. */ @@ -56,20 +62,9 @@ struct SharedObjects } } -version (linux) -{ - import core.sys.linux.errno : program_invocation_name; -} -else -{ - extern(C) const(char)* getprogname() nothrow @nogc; -} - struct SharedObject { @nogc nothrow: - alias ProgramHeader = const(ElfW!"Phdr"); - /**** * Finds the shared object containing the specified address in one of its segments. */ @@ -83,7 +78,7 @@ struct SharedObject { foreach (object; SharedObjects) { - ProgramHeader* segment; + const(Elf_Phdr)* segment; if (object.findSegmentForAddress(address, segment)) { result = object; @@ -111,16 +106,7 @@ struct SharedObject // the main executable has an empty name if (cstr[0] == 0) - { - version (linux) - { - cstr = program_invocation_name; - } - else - { - cstr = getprogname(); - } - } + cstr = getprogname(); import core.stdc.string; return cstr[0 .. strlen(cstr)]; @@ -129,7 +115,7 @@ struct SharedObject /**** * Iterates over this object's segments. */ - int opApply(scope int delegate(ref ProgramHeader) @nogc nothrow dg) const + int opApply(scope int delegate(ref const Elf_Phdr) @nogc nothrow dg) const { foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) { @@ -140,7 +126,7 @@ struct SharedObject return 0; } - bool findSegmentForAddress(const scope void* address, out ProgramHeader* result) const + bool findSegmentForAddress(const scope void* address, out const(Elf_Phdr)* result) const { if (address < baseAddress()) return false; @@ -158,7 +144,9 @@ struct SharedObject } } -// file-based I/O: +// ------------------------------- +// File-based memory-mapped I/O: +// ------------------------------- struct ElfFile { @@ -269,6 +257,19 @@ struct ElfSection private @nogc nothrow: +version (linux) +{ + const(char)* getprogname() + { + import core.sys.linux.errno; + return program_invocation_name; + } +} +else +{ + extern(C) const(char)* getprogname(); +} + const(char)[] getSectionName(ref const ElfSection stringSection, size_t nameIndex) { const data = cast(const(ubyte[])) stringSection.get(); @@ -284,6 +285,13 @@ const(char)[] getSectionName(ref const ElfSection stringSection, size_t nameInde bool isValidElfHeader(ref const Elf_Ehdr ehdr) { + version (D_LP64) alias ELFCLASS = ELFCLASS64; + else alias ELFCLASS = ELFCLASS32; + + version (LittleEndian) alias ELFDATA = ELFDATA2LSB; + else version (BigEndian) alias ELFDATA = ELFDATA2MSB; + else static assert(0, "unsupported byte order"); + if (ehdr.e_ident[EI_MAG0] != ELFMAG0) return false; if (ehdr.e_ident[EI_MAG1] != ELFMAG1) return false; if (ehdr.e_ident[EI_MAG2] != ELFMAG2) return false; @@ -331,29 +339,3 @@ struct MMapRegion(T) size_t offsetDiff; void* mptr; } - -version (D_LP64) -{ - alias Elf_Ehdr = Elf64_Ehdr; - alias Elf_Shdr = Elf64_Shdr; - enum ELFCLASS = ELFCLASS64; -} -else -{ - alias Elf_Ehdr = Elf32_Ehdr; - alias Elf_Shdr = Elf32_Shdr; - enum ELFCLASS = ELFCLASS32; -} - -version (LittleEndian) -{ - alias ELFDATA = ELFDATA2LSB; -} -else version (BigEndian) -{ - alias ELFDATA = ELFDATA2MSB; -} -else -{ - static assert(0, "unsupported byte order"); -} From 0c3f5aa07e3116b3a361a1ff16c38c3d711df2a2 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 14 Oct 2018 16:46:52 +0200 Subject: [PATCH 08/16] Slightly simplify rt.backtrace.elf --- src/rt/backtrace/elf.d | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index 39e02a40a4..6c0648551b 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -29,19 +29,12 @@ struct Image static Image openSelf() { - version (linux) - { - auto selfPath = "/proc/self/exe".ptr; - } - else version (FreeBSD) - { - char[1024] selfPathBuffer = void; - auto selfPath = getFreeBSDExePath(selfPathBuffer[]); - if (selfPath is null) return false; - } - else version (DragonFlyBSD) + const(char)* selfPath; + foreach (object; SharedObjects) { - auto selfPath = "/proc/curproc/file".ptr; + // the first object is the main binary + selfPath = object.name().ptr; + break; } Image image; @@ -94,28 +87,3 @@ struct Image return base; } } - -private: - -version (FreeBSD) -{ - extern (C) int sysctl(const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen) @nogc nothrow; - const(char)* getFreeBSDExePath(char[] buffer) @nogc nothrow - { - enum - { - CTL_KERN = 1, - KERN_PROC = 14, - KERN_PROC_PATHNAME = 12 - } - - int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1]; - size_t len = buffer.length; - - auto result = sysctl(mib.ptr, mib.length, buffer.ptr, &len, null, 0); // get the length of the path - if (result != 0) return null; - if (len + 1 > buffer.length) return null; - buffer[len] = 0; - return buffer.ptr; - } -} From 13dbc3fe9a276911e9e7ec5ea1c7bdf507ed98b5 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 8 Dec 2018 02:30:36 +0100 Subject: [PATCH 09/16] core.elf: Refactor file-based memory-mapped I/O a bit --- src/core/elf.d | 77 ++++++++++++++++-------------------------- src/rt/backtrace/elf.d | 2 +- 2 files changed, 30 insertions(+), 49 deletions(-) diff --git a/src/core/elf.d b/src/core/elf.d index d9f0b79fea..9904991d48 100644 --- a/src/core/elf.d +++ b/src/core/elf.d @@ -19,6 +19,7 @@ else version (DragonFlyBSD) version = linux_or_bsd; version (linux_or_bsd): +import core.stdc.string : strlen; import core.sys.posix.fcntl; import core.sys.posix.unistd; @@ -108,7 +109,6 @@ struct SharedObject if (cstr[0] == 0) cstr = getprogname(); - import core.stdc.string; return cstr[0 .. strlen(cstr)]; } @@ -163,7 +163,7 @@ struct ElfFile if (fd != -1) { // memory map header - this.ehdr = MMapRegion!Elf_Ehdr(fd, 0, Elf_Ehdr.sizeof); + this.ehdr = MMapRegion!Elf_Ehdr(fd, 0); } } @@ -171,10 +171,11 @@ struct ElfFile ~this() { - if (fd != -1) close(fd); + if (fd != -1) + close(fd); } - int fd = -1; + private int fd = -1; MMapRegion!Elf_Ehdr ehdr; bool isValid() const @@ -199,7 +200,8 @@ struct ElfFile foreach (i; 0 .. ehdr.e_shnum) { auto sectionHeader = ElfSectionHeader(this, i); - auto currentName = getSectionName(stringSection, sectionHeader.sh_name); + auto pCurrentName = cast(const(char)*) (stringSection.data.ptr + sectionHeader.sh_name); + auto currentName = pCurrentName[0 .. strlen(pCurrentName)]; if (sectionName == currentName) return i; } @@ -217,8 +219,7 @@ struct ElfSectionHeader assert(Elf_Shdr.sizeof == file.ehdr.e_shentsize); shdr = MMapRegion!Elf_Shdr( file.fd, - file.ehdr.e_shoff + index * file.ehdr.e_shentsize, - file.ehdr.e_shentsize + file.ehdr.e_shoff + index * Elf_Shdr.sizeof ); } @@ -233,26 +234,22 @@ struct ElfSection @nogc nothrow: this(ref const ElfFile file, ref const ElfSectionHeader shdr) { - data = MMapRegion!void( - file.fd, - shdr.sh_offset, - shdr.sh_size, - ); - - length = shdr.sh_size; + mappedRegion = MMapRegion!void(file.fd, shdr.sh_offset, shdr.sh_size); + size = shdr.sh_size; } @disable this(this); - const(void)[] get() const + const(void)[] data() const { - return data.get()[0 .. length]; + return mappedRegion.data[0 .. size]; } - alias get this; + alias data this; - MMapRegion!void data; - size_t length; +private: + MMapRegion!void mappedRegion; + size_t size; } private @nogc nothrow: @@ -270,19 +267,6 @@ else extern(C) const(char)* getprogname(); } -const(char)[] getSectionName(ref const ElfSection stringSection, size_t nameIndex) -{ - const data = cast(const(ubyte[])) stringSection.get(); - - foreach (i; nameIndex .. data.length) - { - if (data[i] == 0) - return cast(const(char)[]) data[nameIndex .. i]; - } - - return null; -} - bool isValidElfHeader(ref const Elf_Ehdr ehdr) { version (D_LP64) alias ELFCLASS = ELFCLASS64; @@ -310,32 +294,29 @@ struct MMapRegion(T) import core.sys.posix.sys.mman; import core.sys.posix.unistd; - this(int fd, size_t offset, size_t length) + this(int fd, size_t offset, size_t length = 1) { - auto pagesize = sysconf(_SC_PAGESIZE); + const pageSize = sysconf(_SC_PAGESIZE); + const pagedOffset = (offset / pageSize) * pageSize; + const offsetDiff = offset - pagedOffset; + const mappedSize = length * T.sizeof + offsetDiff; - auto realOffset = (offset / pagesize) * pagesize; - offsetDiff = offset - realOffset; - realLength = length + offsetDiff; + auto ptr = cast(ubyte*) mmap(null, mappedSize, PROT_READ, MAP_PRIVATE, fd, pagedOffset); - mptr = mmap(null, realLength, PROT_READ, MAP_PRIVATE, fd, realOffset); + mappedRegion = ptr[0 .. mappedSize]; + data = cast(T*) (ptr + offsetDiff); } @disable this(this); ~this() { - if (mptr) munmap(mptr, realLength); - } - - const(T)* get() const - { - return cast(T*)(mptr + offsetDiff); + if (mappedRegion !is null) + munmap(mappedRegion.ptr, mappedRegion.length); } - alias get this; + alias data this; - size_t realLength; - size_t offsetDiff; - void* mptr; + private ubyte[] mappedRegion; + const(T)* data; } diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index 6c0648551b..ffd0dfa013 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -60,7 +60,7 @@ struct Image return null; auto dbgSection = ElfSection(file, dbgSectionHeader); - const sectionData = cast(const(ubyte)[]) dbgSection.get(); + const sectionData = cast(const(ubyte)[]) dbgSection.data(); // do not munmap() the section data to be returned import core.stdc.string; ElfSection initialSection; From 3f1392dfb22c7c7fffbf37e5c90bb9feaf96aaf2 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 8 Dec 2018 03:31:18 +0100 Subject: [PATCH 10/16] core.elf: Prepare for generic ELF I/O I.e., allowing to read non-native ELF files too. The byte order must match the target's though. --- src/core/elf.d | 241 ++++++++++++++++++++++++++++--------------------- 1 file changed, 140 insertions(+), 101 deletions(-) diff --git a/src/core/elf.d b/src/core/elf.d index 9904991d48..f7ae96f939 100644 --- a/src/core/elf.d +++ b/src/core/elf.d @@ -144,114 +144,174 @@ struct SharedObject } } -// ------------------------------- -// File-based memory-mapped I/O: -// ------------------------------- - -struct ElfFile +/** + * File-based memory-mapped I/O (read-only). + * Only supports ELF files with a byte-order matching the target platform's. + * Params: + * Elf_Ehdr = Expected type of the ELF header (Elf{32,64}_Ehdr) + * Elf_Shdr = Expected type of the ELF section header (Elf{32,64}_Shdr) + * ELFCLASS = Expected ELF class (ELFCLASS{32,64}) + */ +template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) { -@nogc nothrow: - static bool open(const(char)* path, out ElfFile file) + struct ElfFile { - file = ElfFile(.open(path, O_RDONLY)); - return file.isValid(); - } + @nogc nothrow: + static bool open(const(char)* path, out ElfFile file) + { + file = ElfFile(.open(path, O_RDONLY)); + return file.isValid(); + } - this(int fd) - { - this.fd = fd; - if (fd != -1) + this(int fd) { - // memory map header - this.ehdr = MMapRegion!Elf_Ehdr(fd, 0); + this.fd = fd; + if (fd != -1) + { + // memory map header + this.ehdr = MMapRegion!Elf_Ehdr(fd, 0); + } } - } - @disable this(this); + @disable this(this); - ~this() - { - if (fd != -1) - close(fd); - } + ~this() + { + if (fd != -1) + close(fd); + } - private int fd = -1; - MMapRegion!Elf_Ehdr ehdr; + private int fd = -1; + MMapRegion!Elf_Ehdr ehdr; - bool isValid() const - { - return fd != -1 && isValidElfHeader(*ehdr); - } + bool isValid() const + { + enum EI_MAG0 = 0; + enum EI_MAG1 = 1; + enum EI_MAG2 = 2; + enum EI_MAG3 = 3; + enum EI_CLASS = 4; + enum EI_DATA = 5; - bool findSectionHeaderByName(const(char)[] sectionName, out ElfSectionHeader header) const - { - const index = findSectionIndexByName(sectionName); - if (index == -1) - return false; - header = ElfSectionHeader(this, index); - return true; - } + enum ELFMAG0 = 0x7f; + enum ELFMAG1 = 'E'; + enum ELFMAG2 = 'L'; + enum ELFMAG3 = 'F'; - size_t findSectionIndexByName(const(char)[] sectionName) const - { - const stringSectionHeader = ElfSectionHeader(this, ehdr.e_shstrndx); - const stringSection = ElfSection(this, stringSectionHeader); + enum ELFCLASS32 = 1; + enum ELFCLASS64 = 2; + + enum ELFDATA2LSB = 1; + enum ELFDATA2MSB = 2; + + version (LittleEndian) alias ELFDATA = ELFDATA2LSB; + else version (BigEndian) alias ELFDATA = ELFDATA2MSB; + else static assert(0, "unsupported byte order"); + + if (fd == -1) + return false; - foreach (i; 0 .. ehdr.e_shnum) + const ident = ehdr.e_ident; + + if (!(ident[EI_MAG0] == ELFMAG0 && + ident[EI_MAG1] == ELFMAG1 && + ident[EI_MAG2] == ELFMAG2 && + ident[EI_MAG3] == ELFMAG3)) + return false; + + if (ident[EI_CLASS] != ELFCLASS) + return false; + + // the file's byte order must match the target's + if (ident[EI_DATA] != ELFDATA) + return false; + + return true; + } + + bool findSectionHeaderByName(const(char)[] sectionName, out ElfSectionHeader header) const { - auto sectionHeader = ElfSectionHeader(this, i); - auto pCurrentName = cast(const(char)*) (stringSection.data.ptr + sectionHeader.sh_name); - auto currentName = pCurrentName[0 .. strlen(pCurrentName)]; - if (sectionName == currentName) - return i; + const index = findSectionIndexByName(sectionName); + if (index == -1) + return false; + header = ElfSectionHeader(this, index); + return true; } - // not found - return -1; + size_t findSectionIndexByName(const(char)[] sectionName) const + { + const stringSectionHeader = ElfSectionHeader(this, ehdr.e_shstrndx); + const stringSection = ElfSection(this, stringSectionHeader); + + foreach (i; 0 .. ehdr.e_shnum) + { + auto sectionHeader = ElfSectionHeader(this, i); + auto pCurrentName = cast(const(char)*) (stringSection.data.ptr + sectionHeader.sh_name); + auto currentName = pCurrentName[0 .. strlen(pCurrentName)]; + if (sectionName == currentName) + return i; + } + + // not found + return -1; + } } -} -struct ElfSectionHeader -{ -@nogc nothrow: - this(ref const ElfFile file, size_t index) + struct ElfSectionHeader { - assert(Elf_Shdr.sizeof == file.ehdr.e_shentsize); - shdr = MMapRegion!Elf_Shdr( - file.fd, - file.ehdr.e_shoff + index * Elf_Shdr.sizeof - ); - } + @nogc nothrow: + this(ref const ElfFile file, size_t index) + { + assert(Elf_Shdr.sizeof == file.ehdr.e_shentsize); + shdr = MMapRegion!Elf_Shdr( + file.fd, + file.ehdr.e_shoff + index * Elf_Shdr.sizeof + ); + } - @disable this(this); + @disable this(this); - alias shdr this; - MMapRegion!Elf_Shdr shdr; -} + alias shdr this; + MMapRegion!Elf_Shdr shdr; + } -struct ElfSection -{ -@nogc nothrow: - this(ref const ElfFile file, ref const ElfSectionHeader shdr) + struct ElfSection { - mappedRegion = MMapRegion!void(file.fd, shdr.sh_offset, shdr.sh_size); - size = shdr.sh_size; - } + @nogc nothrow: + this(ref const ElfFile file, ref const ElfSectionHeader shdr) + { + mappedRegion = MMapRegion!void(file.fd, shdr.sh_offset, shdr.sh_size); + size = shdr.sh_size; + } - @disable this(this); + @disable this(this); - const(void)[] data() const - { - return mappedRegion.data[0 .. size]; - } + const(void)[] data() const + { + return mappedRegion.data[0 .. size]; + } - alias data this; + alias data this; -private: - MMapRegion!void mappedRegion; - size_t size; + private: + MMapRegion!void mappedRegion; + size_t size; + } } +enum ELFCLASS32 = 1; +enum ELFCLASS64 = 2; + +version (D_LP64) alias ELFCLASS = ELFCLASS64; +else alias ELFCLASS = ELFCLASS32; + +alias NativeElfIO = ElfIO!(Elf_Ehdr, Elf_Shdr, ELFCLASS); + +// convenience aliases for native ELF files +alias ElfFile = NativeElfIO.ElfFile; +alias ElfSectionHeader = NativeElfIO.ElfSectionHeader; +alias ElfSection = NativeElfIO.ElfSection; + private @nogc nothrow: version (linux) @@ -267,27 +327,6 @@ else extern(C) const(char)* getprogname(); } -bool isValidElfHeader(ref const Elf_Ehdr ehdr) -{ - version (D_LP64) alias ELFCLASS = ELFCLASS64; - else alias ELFCLASS = ELFCLASS32; - - version (LittleEndian) alias ELFDATA = ELFDATA2LSB; - else version (BigEndian) alias ELFDATA = ELFDATA2MSB; - else static assert(0, "unsupported byte order"); - - if (ehdr.e_ident[EI_MAG0] != ELFMAG0) return false; - if (ehdr.e_ident[EI_MAG1] != ELFMAG1) return false; - if (ehdr.e_ident[EI_MAG2] != ELFMAG2) return false; - if (ehdr.e_ident[EI_MAG3] != ELFMAG3) return false; - - // elf class and data encoding should match target's config - if (ehdr.e_ident[EI_CLASS] != ELFCLASS) return false; - if (ehdr.e_ident[EI_DATA] != ELFDATA ) return false; - - return true; -} - struct MMapRegion(T) { @nogc nothrow: From 3c77e417c3e9c37ebc3dbcb4e203d1b73a7cd683 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 8 Dec 2018 15:29:49 +0100 Subject: [PATCH 11/16] Split core.elf into core.elf.{dl,io} --- mak/DOCS | 3 +- mak/SRCS | 3 +- src/core/elf/dl.d | 159 +++++++++++++++++++++++++++++++++ src/core/{elf.d => elf/io.d} | 168 +++++------------------------------ src/rt/backtrace/elf.d | 31 ++++--- src/rt/sections_elf_shared.d | 16 ++-- 6 files changed, 214 insertions(+), 166 deletions(-) create mode 100644 src/core/elf/dl.d rename src/core/{elf.d => elf/io.d} (58%) diff --git a/mak/DOCS b/mak/DOCS index 84e1d94214..3c2be9a10a 100644 --- a/mak/DOCS +++ b/mak/DOCS @@ -6,7 +6,8 @@ DOCS=\ $(DOCDIR)\core_checkedint.html \ $(DOCDIR)\core_cpuid.html \ $(DOCDIR)\core_demangle.html \ - $(DOCDIR)\core_elf.html \ + $(DOCDIR)\core_elf_dl.html \ + $(DOCDIR)\core_elf_io.html \ $(DOCDIR)\core_exception.html \ $(DOCDIR)\core_lifetime.html \ $(DOCDIR)\core_math.html \ diff --git a/mak/SRCS b/mak/SRCS index 3d83763813..6deeb63475 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -7,7 +7,8 @@ SRCS=\ src\core\checkedint.d \ src\core\cpuid.d \ src\core\demangle.d \ - src\core\elf.d \ + src\core\elf\dl.d \ + src\core\elf\io.d \ src\core\exception.d \ src\core\lifetime.d \ src\core\math.d \ diff --git a/src/core/elf/dl.d b/src/core/elf/dl.d new file mode 100644 index 0000000000..077370c810 --- /dev/null +++ b/src/core/elf/dl.d @@ -0,0 +1,159 @@ +/** + * Simplifies working with shared ELF objects of the current process. + * + * Reference: http://www.dwarfstd.org/ + * + * Copyright: Copyright Digital Mars 2015 - 2018. + * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). + * Authors: Martin Kinkelin + * Source: $(DRUNTIMESRC core/elf/dl.d) + */ + +module core.elf.dl; + +version (linux) +{ + import core.sys.linux.link; + version = LinuxOrBSD; +} +else version (FreeBSD) +{ + import core.sys.freebsd.sys.link_elf; + version = LinuxOrBSD; +} +else version (DragonFlyBSD) +{ + import core.sys.dragonflybsd.sys.link_elf; + version = LinuxOrBSD; +} + +version (LinuxOrBSD): + +alias Elf_Ehdr = ElfW!"Ehdr"; +alias Elf_Phdr = ElfW!"Phdr"; + +/** + * Enables iterating over the process' currently loaded shared objects. + */ +struct SharedObjects +{ +@nogc nothrow: + alias Callback = int delegate(SharedObject); + + static int opApply(scope Callback dg) + { + extern(C) int nativeCallback(dl_phdr_info* info, size_t, void* data) + { + auto dg = *cast(Callback*) data; + return dg(SharedObject(*info)); + } + + return dl_iterate_phdr(&nativeCallback, &dg); + } +} + +/** + * A loaded shared ELF object/binary, i.e., executable or shared library. + */ +struct SharedObject +{ +@nogc nothrow: + /** + * Tries to find the shared object containing the specified address in one of its segments. + * Returns: True on success. + */ + static bool findForAddress(const scope void* address, out SharedObject result) + { + version (linux) enum IterateManually = true; + else version (NetBSD) enum IterateManually = true; + else enum IterateManually = false; + + static if (IterateManually) + { + foreach (object; SharedObjects) + { + const(Elf_Phdr)* segment; + if (object.findSegmentForAddress(address, segment)) + { + result = object; + return true; + } + } + return false; + } + else + { + return !!_rtld_addr_phdr(address, &result.info); + } + } + + dl_phdr_info info; + + /// Returns the base address of the object. + @property void* baseAddress() const + { + return cast(void*) info.dlpi_addr; + } + + /// Returns the name of (usually: path to) the object. + const(char)[] name() const + { + import core.stdc.string : strlen; + + const(char)* cstr = info.dlpi_name; + + // the main executable has an empty name + if (cstr[0] == 0) + cstr = getprogname(); + + return cstr[0 .. strlen(cstr)]; + } + + /// Iterates over this object's segments. + int opApply(scope int delegate(ref const Elf_Phdr) @nogc nothrow dg) const + { + foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) + { + const r = dg(phdr); + if (r != 0) + return r; + } + return 0; + } + + /** + * Tries to find the segment containing the specified address. + * Returns: True on success. + */ + bool findSegmentForAddress(const scope void* address, out const(Elf_Phdr)* result) const + { + if (address < baseAddress) + return false; + + foreach (ref phdr; this) + { + const begin = baseAddress + phdr.p_vaddr; + if (cast(size_t)(address - begin) < phdr.p_memsz) + { + result = &phdr; + return true; + } + } + return false; + } +} + +private @nogc nothrow: + +version (linux) +{ + const(char)* getprogname() + { + import core.sys.linux.errno; + return program_invocation_name; + } +} +else +{ + extern(C) const(char)* getprogname(); +} diff --git a/src/core/elf.d b/src/core/elf/io.d similarity index 58% rename from src/core/elf.d rename to src/core/elf/io.d index f7ae96f939..c984a5b01f 100644 --- a/src/core/elf.d +++ b/src/core/elf/io.d @@ -1,147 +1,36 @@ /** - * This code simplifies working with ELF binaries, e.g., iterating - * over loaded shared objects & their segments as well as reading - * headers and sections from ELF files. + * Provides (read-only) memory-mapped I/O for ELF files. * * Reference: http://www.dwarfstd.org/ * - * Copyright: Copyright Digital Mars 2015 - 2015. + * Copyright: Copyright Digital Mars 2015 - 2018. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Yazan Dabain, Martin Kinkelin - * Source: $(DRUNTIMESRC core/elf.d) + * Source: $(DRUNTIMESRC core/elf/io.d) */ -module core.elf; +module core.elf.io; -version (linux) version = linux_or_bsd; -else version (FreeBSD) version = linux_or_bsd; -else version (DragonFlyBSD) version = linux_or_bsd; +version (Posix): -version (linux_or_bsd): - -import core.stdc.string : strlen; import core.sys.posix.fcntl; +import core.sys.posix.sys.mman; import core.sys.posix.unistd; version (linux) { import core.sys.linux.link; - import core.sys.linux.elf; + version = LinuxOrBSD; } else version (FreeBSD) { import core.sys.freebsd.sys.link_elf; - import core.sys.freebsd.sys.elf; + version = LinuxOrBSD; } else version (DragonFlyBSD) { import core.sys.dragonflybsd.sys.link_elf; - import core.sys.dragonflybsd.sys.elf; -} - -alias Elf_Phdr = ElfW!"Phdr"; -alias Elf_Ehdr = ElfW!"Ehdr"; -alias Elf_Shdr = ElfW!"Shdr"; - -/**** - * Enables iterating over the process' currently loaded shared objects. - */ -struct SharedObjects -{ -@nogc nothrow: - alias Callback = int delegate(SharedObject); - - static int opApply(scope Callback dg) - { - extern(C) int nativeCallback(dl_phdr_info* info, size_t, void* data) - { - auto dg = *cast(Callback*) data; - return dg(SharedObject(*info)); - } - - return dl_iterate_phdr(&nativeCallback, &dg); - } -} - -struct SharedObject -{ -@nogc nothrow: - /**** - * Finds the shared object containing the specified address in one of its segments. - */ - static bool findForAddress(const scope void* address, out SharedObject result) - { - version (linux) enum IterateManually = true; - else version (NetBSD) enum IterateManually = true; - else enum IterateManually = false; - - static if (IterateManually) - { - foreach (object; SharedObjects) - { - const(Elf_Phdr)* segment; - if (object.findSegmentForAddress(address, segment)) - { - result = object; - return true; - } - } - return false; - } - else - { - return !!_rtld_addr_phdr(address, &result.info); - } - } - - dl_phdr_info info; - - void* baseAddress() const - { - return cast(void*) info.dlpi_addr; - } - - const(char)[] name() const - { - const(char)* cstr = info.dlpi_name; - - // the main executable has an empty name - if (cstr[0] == 0) - cstr = getprogname(); - - return cstr[0 .. strlen(cstr)]; - } - - /**** - * Iterates over this object's segments. - */ - int opApply(scope int delegate(ref const Elf_Phdr) @nogc nothrow dg) const - { - foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum]) - { - const r = dg(phdr); - if (r != 0) - return r; - } - return 0; - } - - bool findSegmentForAddress(const scope void* address, out const(Elf_Phdr)* result) const - { - if (address < baseAddress()) - return false; - - foreach (ref phdr; this) - { - const begin = baseAddress() + phdr.p_vaddr; - if (cast(size_t)(address - begin) < phdr.p_memsz) - { - result = &phdr; - return true; - } - } - return false; - } + version = LinuxOrBSD; } /** @@ -240,6 +129,8 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) size_t findSectionIndexByName(const(char)[] sectionName) const { + import core.stdc.string : strlen; + const stringSectionHeader = ElfSectionHeader(this, ehdr.e_shstrndx); const stringSection = ElfSection(this, stringSectionHeader); @@ -302,37 +193,24 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) enum ELFCLASS32 = 1; enum ELFCLASS64 = 2; -version (D_LP64) alias ELFCLASS = ELFCLASS64; -else alias ELFCLASS = ELFCLASS32; - -alias NativeElfIO = ElfIO!(Elf_Ehdr, Elf_Shdr, ELFCLASS); - -// convenience aliases for native ELF files -alias ElfFile = NativeElfIO.ElfFile; -alias ElfSectionHeader = NativeElfIO.ElfSectionHeader; -alias ElfSection = NativeElfIO.ElfSection; +// convenience aliases for the target platform +version (LinuxOrBSD) +{ + alias Elf_Ehdr = ElfW!"Ehdr"; + alias Elf_Shdr = ElfW!"Shdr"; -private @nogc nothrow: + version (D_LP64) alias ELFCLASS = ELFCLASS64; + else alias ELFCLASS = ELFCLASS32; -version (linux) -{ - const(char)* getprogname() - { - import core.sys.linux.errno; - return program_invocation_name; - } -} -else -{ - extern(C) const(char)* getprogname(); + alias NativeElfIO = ElfIO!(Elf_Ehdr, Elf_Shdr, ELFCLASS); + alias ElfFile = NativeElfIO.ElfFile; + alias ElfSectionHeader = NativeElfIO.ElfSectionHeader; + alias ElfSection = NativeElfIO.ElfSection; } -struct MMapRegion(T) +private struct MMapRegion(T) { @nogc nothrow: - import core.sys.posix.sys.mman; - import core.sys.posix.unistd; - this(int fd, size_t offset, size_t length = 1) { const pageSize = sysconf(_SC_PAGESIZE); diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index ffd0dfa013..da5abd5504 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -3,7 +3,7 @@ * * Reference: http://www.dwarfstd.org/ * - * Copyright: Copyright Digital Mars 2015 - 2015. + * Copyright: Copyright Digital Mars 2015 - 2018. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: Yazan Dabain * Source: $(DRUNTIMESRC rt/backtrace/elf.d) @@ -11,17 +11,26 @@ module rt.backtrace.elf; -version (linux) version = linux_or_bsd; -else version (FreeBSD) version = linux_or_bsd; -else version (DragonFlyBSD) version = linux_or_bsd; - -version (linux_or_bsd): +version (linux) +{ + import core.sys.linux.elf; + version = LinuxOrBSD; +} +else version (FreeBSD) +{ + import core.sys.freebsd.sys.elf; + version = LinuxOrBSD; +} +else version (DragonFlyBSD) +{ + import core.sys.dragonflybsd.sys.elf; + version = LinuxOrBSD; +} -import core.elf; +version (LinuxOrBSD): -version (linux) import core.sys.linux.elf; -version (FreeBSD) import core.sys.freebsd.sys.elf; -version (DragonFlyBSD) import core.sys.dragonflybsd.sys.elf; +import core.elf.dl; +import core.elf.io; struct Image { @@ -80,7 +89,7 @@ struct Image foreach (object; SharedObjects) { // only take the first address as this will be the main binary - base = cast(size_t) object.baseAddress(); + base = cast(size_t) object.baseAddress; break; } diff --git a/src/rt/sections_elf_shared.d b/src/rt/sections_elf_shared.d index 88f907b622..2ae75cf866 100644 --- a/src/rt/sections_elf_shared.d +++ b/src/rt/sections_elf_shared.d @@ -20,7 +20,7 @@ else enum SharedELF = false; static if (SharedELF): // debug = PRINTF; -import core.elf; +import core.elf.dl; import core.memory; import core.stdc.config; import core.stdc.stdio; @@ -705,7 +705,7 @@ version (Shared) { if (phdr.p_type == PT_DYNAMIC) { - auto p = cast(ElfW!"Dyn"*)(object.baseAddress() + (phdr.p_vaddr & ~(size_t.sizeof - 1))); + auto p = cast(ElfW!"Dyn"*)(object.baseAddress + (phdr.p_vaddr & ~(size_t.sizeof - 1))); dyns = p[0 .. phdr.p_memsz / ElfW!"Dyn".sizeof]; break; } @@ -717,15 +717,15 @@ version (Shared) if (dyn.d_tag == DT_STRTAB) { version (CRuntime_Musl) - strtab = cast(const(char)*)(object.baseAddress() + dyn.d_un.d_ptr); // relocate + strtab = cast(const(char)*)(object.baseAddress + dyn.d_un.d_ptr); // relocate else version (linux) strtab = cast(const(char)*)dyn.d_un.d_ptr; else version (FreeBSD) - strtab = cast(const(char)*)(object.baseAddress() + dyn.d_un.d_ptr); // relocate + strtab = cast(const(char)*)(object.baseAddress + dyn.d_un.d_ptr); // relocate else version (NetBSD) - strtab = cast(const(char)*)(object.baseAddress() + dyn.d_un.d_ptr); // relocate + strtab = cast(const(char)*)(object.baseAddress + dyn.d_un.d_ptr); // relocate else version (DragonFlyBSD) - strtab = cast(const(char)*)(object.baseAddress() + dyn.d_un.d_ptr); // relocate + strtab = cast(const(char)*)(object.baseAddress + dyn.d_un.d_ptr); // relocate else static assert(0, "unimplemented"); break; @@ -774,12 +774,12 @@ void scanSegments(const scope ref SharedObject object, DSO* pdso) nothrow @nogc case PT_LOAD: if (phdr.p_flags & PF_W) // writeable data segment { - auto beg = object.baseAddress() + (phdr.p_vaddr & ~(size_t.sizeof - 1)); + auto beg = object.baseAddress + (phdr.p_vaddr & ~(size_t.sizeof - 1)); pdso._gcRanges.insertBack(beg[0 .. phdr.p_memsz]); } version (Shared) if (phdr.p_flags & PF_X) // code segment { - auto beg = object.baseAddress() + (phdr.p_vaddr & ~(size_t.sizeof - 1)); + auto beg = object.baseAddress + (phdr.p_vaddr & ~(size_t.sizeof - 1)); pdso._codeSegments.insertBack(beg[0 .. phdr.p_memsz]); } break; From 0fa014f03cdfd24e252ee8c0b49a5d9fe0444d8f Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 8 Dec 2018 15:58:04 +0100 Subject: [PATCH 12/16] Fix Issue 19322 (memory leak in backtrace generation with -g) --- src/rt/backtrace/dwarf.d | 101 ++++++++++++++++++++------------------- src/rt/backtrace/elf.d | 23 ++++----- src/rt/backtrace/macho.d | 4 +- 3 files changed, 63 insertions(+), 65 deletions(-) diff --git a/src/rt/backtrace/dwarf.d b/src/rt/backtrace/dwarf.d index 77feabe2d0..1d45862f55 100644 --- a/src/rt/backtrace/dwarf.d +++ b/src/rt/backtrace/dwarf.d @@ -51,77 +51,80 @@ int traceHandlerOpApplyImpl(const void*[] callstack, scope int delegate(ref size const char** frameList = backtrace_symbols(callstack.ptr, cast(int) callstack.length); scope(exit) free(cast(void*) frameList); - // find address -> file, line mapping using dwarf debug_line - Array!Location locations; auto image = Image.openSelf(); - if (image.isValid) - { - auto debugLineSectionData = image.getDebugLineSectionData(); + int processCallstack(const(ubyte)[] debugLineSectionData) + { + // find address -> file, line mapping using dwarf debug_line + Array!Location locations; if (debugLineSectionData) { - // resolve addresses locations.length = callstack.length; foreach (size_t i; 0 .. callstack.length) locations[i].address = cast(size_t) callstack[i]; resolveAddresses(debugLineSectionData, locations[], image.baseAddress); } - } - int ret = 0; - foreach (size_t i; 0 .. callstack.length) - { - char[1536] buffer = void; - size_t bufferLength = 0; - - void appendToBuffer(Args...)(const(char)* format, Args args) + int ret = 0; + foreach (size_t i; 0 .. callstack.length) { - const count = snprintf(buffer.ptr + bufferLength, buffer.length - bufferLength, format, args); - assert(count >= 0); - bufferLength += count; - if (bufferLength >= buffer.length) - bufferLength = buffer.length - 1; - } + char[1536] buffer = void; + size_t bufferLength = 0; - if (locations.length > 0 && locations[i].line != -1) - { - appendToBuffer("%.*s:%d ", cast(int) locations[i].file.length, locations[i].file.ptr, locations[i].line); - } - else - { - buffer[0 .. 5] = "??:? "; - bufferLength = 5; - } + void appendToBuffer(Args...)(const(char)* format, Args args) + { + const count = snprintf(buffer.ptr + bufferLength, buffer.length - bufferLength, format, args); + assert(count >= 0); + bufferLength += count; + if (bufferLength >= buffer.length) + bufferLength = buffer.length - 1; + } - char[1024] symbolBuffer = void; - auto symbol = getDemangledSymbol(frameList[i][0 .. strlen(frameList[i])], symbolBuffer); - if (symbol.length > 0) - appendToBuffer("%.*s ", cast(int) symbol.length, symbol.ptr); + if (locations.length > 0 && locations[i].line != -1) + { + appendToBuffer("%.*s:%d ", cast(int) locations[i].file.length, locations[i].file.ptr, locations[i].line); + } + else + { + buffer[0 .. 5] = "??:? "; + bufferLength = 5; + } - const addressLength = 20; - const maxBufferLength = buffer.length - addressLength; - if (bufferLength > maxBufferLength) - { - buffer[maxBufferLength-4 .. maxBufferLength] = "... "; - bufferLength = maxBufferLength; + char[1024] symbolBuffer = void; + auto symbol = getDemangledSymbol(frameList[i][0 .. strlen(frameList[i])], symbolBuffer); + if (symbol.length > 0) + appendToBuffer("%.*s ", cast(int) symbol.length, symbol.ptr); + + const addressLength = 20; + const maxBufferLength = buffer.length - addressLength; + if (bufferLength > maxBufferLength) + { + buffer[maxBufferLength-4 .. maxBufferLength] = "... "; + bufferLength = maxBufferLength; + } + static if (size_t.sizeof == 8) + appendToBuffer("[0x%llx]", callstack[i]); + else + appendToBuffer("[0x%x]", callstack[i]); + + auto output = buffer[0 .. bufferLength]; + auto pos = i; + ret = dg(pos, output); + if (ret || symbol == "_Dmain") break; } - static if (size_t.sizeof == 8) - appendToBuffer("[0x%llx]", callstack[i]); - else - appendToBuffer("[0x%x]", callstack[i]); - auto output = buffer[0 .. bufferLength]; - auto pos = i; - ret = dg(pos, output); - if (ret || symbol == "_Dmain") break; + return ret; } - return ret; + + return image.isValid + ? image.processDebugLineSectionData(&processCallstack) + : processCallstack(null); } private: -// the lifetime of the Location data is the lifetime of the mmapped ElfSection +// the lifetime of the Location data is bound to the lifetime of debugLineSectionData void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations, size_t baseAddress) @nogc nothrow { debug(DwarfDebugMachine) import core.stdc.stdio; diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index da5abd5504..11a136d16f 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -58,24 +58,19 @@ struct Image return file != ElfFile.init; } - const(ubyte)[] getDebugLineSectionData() + T processDebugLineSectionData(T)(scope T delegate(const(ubyte)[]) processor) { ElfSectionHeader dbgSectionHeader; - if (!file.findSectionHeaderByName(".debug_line", dbgSectionHeader)) - return null; + ElfSection dbgSection; - // we don't support compressed debug sections - if ((dbgSectionHeader.shdr.sh_flags & SHF_COMPRESSED) != 0) - return null; - - auto dbgSection = ElfSection(file, dbgSectionHeader); - const sectionData = cast(const(ubyte)[]) dbgSection.data(); - // do not munmap() the section data to be returned - import core.stdc.string; - ElfSection initialSection; - memcpy(&dbgSection, &initialSection, ElfSection.sizeof); + if (file.findSectionHeaderByName(".debug_line", dbgSectionHeader)) + { + // we don't support compressed debug sections + if (!(dbgSectionHeader.shdr.sh_flags & SHF_COMPRESSED)) + dbgSection = ElfSection(file, dbgSectionHeader); + } - return sectionData; + return processor(cast(const(ubyte)[]) dbgSection.data()); } @property size_t baseAddress() diff --git a/src/rt/backtrace/macho.d b/src/rt/backtrace/macho.d index 3d4573b1cc..dfa67b47a2 100644 --- a/src/rt/backtrace/macho.d +++ b/src/rt/backtrace/macho.d @@ -61,11 +61,11 @@ struct Image return self !is null; } - const(ubyte)[] getDebugLineSectionData() + T processDebugLineSectionData(T)(scope T delegate(const(ubyte)[]) processor) { c_ulong size; auto data = getsectiondata(self, "__DWARF", "__debug_line", &size); - return data[0 .. size]; + return processor(data[0 .. size]); } @property size_t baseAddress() From abc352d69d6455c91ae754a0a3eec5a9c84cb6db Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 8 Dec 2018 18:08:46 +0100 Subject: [PATCH 13/16] Extend documentation for core.elf.io --- src/core/elf/io.d | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/core/elf/io.d b/src/core/elf/io.d index c984a5b01f..b89f37ac78 100644 --- a/src/core/elf/io.d +++ b/src/core/elf/io.d @@ -43,15 +43,27 @@ else version (DragonFlyBSD) */ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) { + /** + * ELF file (with memory-mapped ELF header). + */ struct ElfFile { @nogc nothrow: + /** + * Tries to open the specified file as ELF file matching the ElfIO + * template parameters. + * Returns: True on success. + */ static bool open(const(char)* path, out ElfFile file) { file = ElfFile(.open(path, O_RDONLY)); return file.isValid(); } + /** + * Constructs an instance based on the specified file descriptor. + * Doesn't validate the file header. + */ this(int fd) { this.fd = fd; @@ -71,8 +83,10 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) } private int fd = -1; + /// Memory-mapped ELF header. MMapRegion!Elf_Ehdr ehdr; + /// Returns true if the ELF file header matches the ElfIO template parameters. bool isValid() const { enum EI_MAG0 = 0; @@ -118,6 +132,10 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) return true; } + /** + * Tries to find the header of the section with the specified name. + * Returns: True on success. + */ bool findSectionHeaderByName(const(char)[] sectionName, out ElfSectionHeader header) const { const index = findSectionIndexByName(sectionName); @@ -127,6 +145,10 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) return true; } + /** + * Tries to find the index of the section with the specified name. + * Returns: -1 if not found, otherwise 0-based section index. + */ size_t findSectionIndexByName(const(char)[] sectionName) const { import core.stdc.string : strlen; @@ -148,9 +170,13 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) } } + /** + * Memory-mapped ELF section header. + */ struct ElfSectionHeader { @nogc nothrow: + /// Constructs a new instance based on the specified file and section index. this(ref const ElfFile file, size_t index) { assert(Elf_Shdr.sizeof == file.ehdr.e_shentsize); @@ -163,12 +189,17 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) @disable this(this); alias shdr this; + /// Memory-mapped section header. MMapRegion!Elf_Shdr shdr; } + /** + * Memory-mapped ELF section data. + */ struct ElfSection { @nogc nothrow: + /// Constructs a new instance based on the specified file and section header. this(ref const ElfFile file, ref const ElfSectionHeader shdr) { mappedRegion = MMapRegion!void(file.fd, shdr.sh_offset, shdr.sh_size); @@ -177,6 +208,7 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) @disable this(this); + /// Returns the memory-mapped section data. const(void)[] data() const { return mappedRegion.data[0 .. size]; @@ -190,21 +222,31 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) } } +/// ELF class for 32-bit ELF files. enum ELFCLASS32 = 1; +/// ELF class for 64-bit ELF files. enum ELFCLASS64 = 2; // convenience aliases for the target platform version (LinuxOrBSD) { + /// Native ELF header type. alias Elf_Ehdr = ElfW!"Ehdr"; + /// Native ELF section header type. alias Elf_Shdr = ElfW!"Shdr"; + /// Native ELF class. version (D_LP64) alias ELFCLASS = ELFCLASS64; else alias ELFCLASS = ELFCLASS32; + /// alias NativeElfIO = ElfIO!(Elf_Ehdr, Elf_Shdr, ELFCLASS); + + /// Native ELF file. alias ElfFile = NativeElfIO.ElfFile; + /// Native ELF section header. alias ElfSectionHeader = NativeElfIO.ElfSectionHeader; + /// Native ELF section. alias ElfSection = NativeElfIO.ElfSection; } @@ -213,6 +255,9 @@ private struct MMapRegion(T) @nogc nothrow: this(int fd, size_t offset, size_t length = 1) { + if (fd == -1) + return; + const pageSize = sysconf(_SC_PAGESIZE); const pagedOffset = (offset / pageSize) * pageSize; const offsetDiff = offset - pagedOffset; From 332cf0a7e9ba25b253bf5ecc89974c3d8be7a116 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 8 Dec 2018 18:39:57 +0100 Subject: [PATCH 14/16] Minor documentation extensions --- src/core/elf/dl.d | 3 +++ src/core/elf/io.d | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/core/elf/dl.d b/src/core/elf/dl.d index 077370c810..a635df63ec 100644 --- a/src/core/elf/dl.d +++ b/src/core/elf/dl.d @@ -38,8 +38,10 @@ alias Elf_Phdr = ElfW!"Phdr"; struct SharedObjects { @nogc nothrow: + /// alias Callback = int delegate(SharedObject); + /// static int opApply(scope Callback dg) { extern(C) int nativeCallback(dl_phdr_info* info, size_t, void* data) @@ -87,6 +89,7 @@ struct SharedObject } } + /// OS-dependent info structure. dl_phdr_info info; /// Returns the base address of the object. diff --git a/src/core/elf/io.d b/src/core/elf/io.d index b89f37ac78..276b974319 100644 --- a/src/core/elf/io.d +++ b/src/core/elf/io.d @@ -63,6 +63,7 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) /** * Constructs an instance based on the specified file descriptor. * Doesn't validate the file header. + * The file is closed when destructing the instance. */ this(int fd) { @@ -76,6 +77,7 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) @disable this(this); + /// Closes the file. ~this() { if (fd != -1) @@ -209,6 +211,7 @@ template ElfIO(Elf_Ehdr, Elf_Shdr, ubyte ELFCLASS) @disable this(this); /// Returns the memory-mapped section data. + /// The data is accessible as long as this ElfSection is alive. const(void)[] data() const { return mappedRegion.data[0 .. size]; From 40370b837568adc2a02be3f6cffa46011ab9b2f5 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 8 Dec 2018 19:10:13 +0100 Subject: [PATCH 15/16] Fixup Makefiles --- mak/COPY | 3 +++ mak/DOCS | 5 +++-- mak/SRCS | 5 +++-- mak/WINDOWS | 6 ++++++ posix.mak | 3 +++ 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/mak/COPY b/mak/COPY index a23b81056e..2e4c44ed30 100644 --- a/mak/COPY +++ b/mak/COPY @@ -21,6 +21,9 @@ COPY=\ $(IMPDIR)\core\vararg.d \ $(IMPDIR)\core\volatile.d \ \ + $(IMPDIR)\core\elf\dl.d \ + $(IMPDIR)\core\elf\io.d \ + \ $(IMPDIR)\core\internal\abort.d \ $(IMPDIR)\core\internal\atomic.d \ $(IMPDIR)\core\internal\attributes.d \ diff --git a/mak/DOCS b/mak/DOCS index 3c2be9a10a..81335ef560 100644 --- a/mak/DOCS +++ b/mak/DOCS @@ -6,8 +6,6 @@ DOCS=\ $(DOCDIR)\core_checkedint.html \ $(DOCDIR)\core_cpuid.html \ $(DOCDIR)\core_demangle.html \ - $(DOCDIR)\core_elf_dl.html \ - $(DOCDIR)\core_elf_io.html \ $(DOCDIR)\core_exception.html \ $(DOCDIR)\core_lifetime.html \ $(DOCDIR)\core_math.html \ @@ -22,6 +20,9 @@ DOCS=\ $(DOCDIR)\core_gc_gcinterface.html \ $(DOCDIR)\core_gc_registry.html \ \ + $(DOCDIR)\core_elf_dl.html \ + $(DOCDIR)\core_elf_io.html \ + \ $(DOCDIR)\core_stdc_assert_.html \ $(DOCDIR)\core_stdc_config.html \ $(DOCDIR)\core_stdc_complex.html \ diff --git a/mak/SRCS b/mak/SRCS index 6deeb63475..53e29d3eca 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -7,8 +7,6 @@ SRCS=\ src\core\checkedint.d \ src\core\cpuid.d \ src\core\demangle.d \ - src\core\elf\dl.d \ - src\core\elf\io.d \ src\core\exception.d \ src\core\lifetime.d \ src\core\math.d \ @@ -23,6 +21,9 @@ SRCS=\ src\core\gc\gcinterface.d \ src\core\gc\registry.d \ \ + src\core\elf\dl.d \ + src\core\elf\io.d \ + \ src\core\internal\abort.d \ src\core\internal\atomic.d \ src\core\internal\convert.d \ diff --git a/mak/WINDOWS b/mak/WINDOWS index 5a1995e753..f779bbba9e 100644 --- a/mak/WINDOWS +++ b/mak/WINDOWS @@ -110,6 +110,12 @@ $(IMPDIR)\core\vararg.d : src\core\vararg.d $(IMPDIR)\core\volatile.d : src\core\volatile.d copy $** $@ +$(IMPDIR)\core\elf\dl.d : src\core\elf\dl.d + copy $** $@ + +$(IMPDIR)\core\elf\io.d : src\core\elf\io.d + copy $** $@ + $(IMPDIR)\core\gc\config.d : src\core\gc\config.d copy $** $@ diff --git a/posix.mak b/posix.mak index 0dd950dcd7..05a5e89e12 100644 --- a/posix.mak +++ b/posix.mak @@ -150,6 +150,9 @@ $(DOCDIR)/object.html : src/object.d $(DMD) $(DOCDIR)/core_%.html : src/core/%.d $(DMD) $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< +$(DOCDIR)/core_elf_%.html : src/core/elf/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + $(DOCDIR)/core_experimental_%.html : src/core/experimental/%.d $(DMD) $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< From cb4d513507c74011d9897c9a6ec2619a587da66d Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 21 Dec 2019 15:57:39 +0100 Subject: [PATCH 16/16] Move core.elf.* to core.internal.elf.* --- mak/COPY | 6 +++--- mak/DOCS | 3 --- mak/SRCS | 7 ++++--- mak/WINDOWS | 12 ++++++------ posix.mak | 6 +++--- src/core/{ => internal}/elf/dl.d | 2 +- src/core/{ => internal}/elf/io.d | 2 +- src/rt/backtrace/elf.d | 4 ++-- src/rt/sections_elf_shared.d | 2 +- 9 files changed, 21 insertions(+), 23 deletions(-) rename src/core/{ => internal}/elf/dl.d (99%) rename src/core/{ => internal}/elf/io.d (99%) diff --git a/mak/COPY b/mak/COPY index 2e4c44ed30..11610c0f43 100644 --- a/mak/COPY +++ b/mak/COPY @@ -21,9 +21,6 @@ COPY=\ $(IMPDIR)\core\vararg.d \ $(IMPDIR)\core\volatile.d \ \ - $(IMPDIR)\core\elf\dl.d \ - $(IMPDIR)\core\elf\io.d \ - \ $(IMPDIR)\core\internal\abort.d \ $(IMPDIR)\core\internal\atomic.d \ $(IMPDIR)\core\internal\attributes.d \ @@ -53,6 +50,9 @@ COPY=\ $(IMPDIR)\core\internal\array\operations.d \ $(IMPDIR)\core\internal\array\utils.d \ \ + $(IMPDIR)\core\internal\elf\dl.d \ + $(IMPDIR)\core\internal\elf\io.d \ + \ $(IMPDIR)\core\internal\util\array.d \ \ $(IMPDIR)\core\stdc\assert_.d \ diff --git a/mak/DOCS b/mak/DOCS index 81335ef560..0bcce15cda 100644 --- a/mak/DOCS +++ b/mak/DOCS @@ -20,9 +20,6 @@ DOCS=\ $(DOCDIR)\core_gc_gcinterface.html \ $(DOCDIR)\core_gc_registry.html \ \ - $(DOCDIR)\core_elf_dl.html \ - $(DOCDIR)\core_elf_io.html \ - \ $(DOCDIR)\core_stdc_assert_.html \ $(DOCDIR)\core_stdc_config.html \ $(DOCDIR)\core_stdc_complex.html \ diff --git a/mak/SRCS b/mak/SRCS index 53e29d3eca..92bbbe941b 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -21,9 +21,6 @@ SRCS=\ src\core\gc\gcinterface.d \ src\core\gc\registry.d \ \ - src\core\elf\dl.d \ - src\core\elf\io.d \ - \ src\core\internal\abort.d \ src\core\internal\atomic.d \ src\core\internal\convert.d \ @@ -51,6 +48,10 @@ SRCS=\ src\core\internal\array\concatenation.d \ src\core\internal\array\operations.d \ src\core\internal\array\utils.d \ + \ + src\core\internal\elf\dl.d \ + src\core\internal\elf\io.d \ + \ src\core\internal\util\array.d \ \ src\core\stdc\assert_.d \ diff --git a/mak/WINDOWS b/mak/WINDOWS index f779bbba9e..c4d2e63993 100644 --- a/mak/WINDOWS +++ b/mak/WINDOWS @@ -110,12 +110,6 @@ $(IMPDIR)\core\vararg.d : src\core\vararg.d $(IMPDIR)\core\volatile.d : src\core\volatile.d copy $** $@ -$(IMPDIR)\core\elf\dl.d : src\core\elf\dl.d - copy $** $@ - -$(IMPDIR)\core\elf\io.d : src\core\elf\io.d - copy $** $@ - $(IMPDIR)\core\gc\config.d : src\core\gc\config.d copy $** $@ @@ -206,6 +200,12 @@ $(IMPDIR)\core\internal\array\utils.d : src\core\internal\array\utils.d $(IMPDIR)\core\internal\array\operations.d : src\core\internal\array\operations.d copy $** $@ +$(IMPDIR)\core\internal\elf\dl.d : src\core\internal\elf\dl.d + copy $** $@ + +$(IMPDIR)\core\internal\elf\io.d : src\core\internal\elf\io.d + copy $** $@ + $(IMPDIR)\core\internal\util\array.d : src\core\internal\util\array.d copy $** $@ diff --git a/posix.mak b/posix.mak index 05a5e89e12..83431d6430 100644 --- a/posix.mak +++ b/posix.mak @@ -150,9 +150,6 @@ $(DOCDIR)/object.html : src/object.d $(DMD) $(DOCDIR)/core_%.html : src/core/%.d $(DMD) $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< -$(DOCDIR)/core_elf_%.html : src/core/elf/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - $(DOCDIR)/core_experimental_%.html : src/core/experimental/%.d $(DMD) $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< @@ -162,6 +159,9 @@ $(DOCDIR)/core_gc_%.html : src/core/gc/%.d $(DMD) $(DOCDIR)/core_internal_%.html : src/core/internal/%.d $(DMD) $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< +$(DOCDIR)/core_internal_elf_%.html : src/core/internal/elf/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + $(DOCDIR)/core_stdc_%.html : src/core/stdc/%.d $(DMD) $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< diff --git a/src/core/elf/dl.d b/src/core/internal/elf/dl.d similarity index 99% rename from src/core/elf/dl.d rename to src/core/internal/elf/dl.d index a635df63ec..25e720a4cb 100644 --- a/src/core/elf/dl.d +++ b/src/core/internal/elf/dl.d @@ -9,7 +9,7 @@ * Source: $(DRUNTIMESRC core/elf/dl.d) */ -module core.elf.dl; +module core.internal.elf.dl; version (linux) { diff --git a/src/core/elf/io.d b/src/core/internal/elf/io.d similarity index 99% rename from src/core/elf/io.d rename to src/core/internal/elf/io.d index 276b974319..48df1dc7c5 100644 --- a/src/core/elf/io.d +++ b/src/core/internal/elf/io.d @@ -9,7 +9,7 @@ * Source: $(DRUNTIMESRC core/elf/io.d) */ -module core.elf.io; +module core.internal.elf.io; version (Posix): diff --git a/src/rt/backtrace/elf.d b/src/rt/backtrace/elf.d index 11a136d16f..837dde877d 100644 --- a/src/rt/backtrace/elf.d +++ b/src/rt/backtrace/elf.d @@ -29,8 +29,8 @@ else version (DragonFlyBSD) version (LinuxOrBSD): -import core.elf.dl; -import core.elf.io; +import core.internal.elf.dl; +import core.internal.elf.io; struct Image { diff --git a/src/rt/sections_elf_shared.d b/src/rt/sections_elf_shared.d index 2ae75cf866..832b9e2170 100644 --- a/src/rt/sections_elf_shared.d +++ b/src/rt/sections_elf_shared.d @@ -20,7 +20,7 @@ else enum SharedELF = false; static if (SharedELF): // debug = PRINTF; -import core.elf.dl; +import core.internal.elf.dl; import core.memory; import core.stdc.config; import core.stdc.stdio;