644 changes: 644 additions & 0 deletions src/libelf.d

Large diffs are not rendered by default.

602 changes: 602 additions & 0 deletions src/libmach.d

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/posix.mak
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ else
endif

ifeq (osx,$(OS))
GLUE_OBJS += libmach.o scanmach.o
DMD_SRCS += libmach.d scanmach.d
else
GLUE_OBJS += libelf.o scanelf.o
DMD_SRCS += libelf.d scanelf.d
endif

#GLUE_OBJS=gluestub.o
Expand Down Expand Up @@ -247,7 +247,7 @@ ROOT_SRC = $(addprefix $(ROOT)/,aav.h array.h file.h filename.h \
GLUE_SRC = glue.c msc.c s2ir.c todt.c e2ir.c tocsym.c \
toobj.c toctype.c tocvdebug.c toir.h toir.c \
irstate.h irstate.c iasm.c \
toelfdebug.c libelf.c scanelf.c libmach.c scanmach.c \
toelfdebug.c libelf.d scanelf.d libmach.d scanmach.d \
tk.c eh.c gluestub.c objc_glue.c objc_glue_stubs.c

BACK_SRC = \
Expand Down
172 changes: 172 additions & 0 deletions src/scanelf.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt

module ddmd.scanelf;

version (linux)
import core.sys.linux.elf;
else version (FreeBSD)
import core.sys.freebsd.sys.elf;
else version (Solaris)
import core.sys.solaris.elf;

import core.stdc.string;
import ddmd.globals;
import ddmd.errors;

enum LOG = false;

/*****************************************************************************/
extern (C++) __gshared char* elf = [0x7F, 'E', 'L', 'F']; // ELF file signature

/*****************************************
* Reads an object module from base[0..buflen] and passes the names
* of any exported symbols to (*pAddSymbol)().
* Input:
* pctx context pointer, pass to *pAddSymbol
* pAddSymbol function to pass the names to
* base[0..buflen] contains contents of object module
* module_name name of the object module (used for error messages)
* loc location to use for error printing
*/
extern (C++) void scanElfObjModule(void* pctx, void function(void* pctx, char* name, int pickAny) pAddSymbol, void* base, size_t buflen, const(char)* module_name, Loc loc)
{
static if (LOG)
{
printf("scanElfObjModule(%s)\n", module_name);
}
ubyte* buf = cast(ubyte*)base;
int reason = 0;
if (buflen < Elf32_Ehdr.sizeof)
{
reason = __LINE__;
Lcorrupt:
error(loc, "corrupt ELF object module %s %d", module_name, reason);
return;
}
if (memcmp(buf, elf, 4))
{
reason = __LINE__;
goto Lcorrupt;
}
if (buf[EI_VERSION] != EV_CURRENT)
{
error(loc, "ELF object module %s has EI_VERSION = %d, should be %d", module_name, buf[EI_VERSION], EV_CURRENT);
return;
}
if (buf[EI_DATA] != ELFDATA2LSB)
{
error(loc, "ELF object module %s is byte swapped and unsupported", module_name);
return;
}
if (buf[EI_CLASS] == ELFCLASS32)
{
Elf32_Ehdr* eh = cast(Elf32_Ehdr*)buf;
if (eh.e_type != ET_REL)
{
error(loc, "ELF object module %s is not relocatable", module_name);
return; // not relocatable object module
}
if (eh.e_version != EV_CURRENT)
goto Lcorrupt;
/* For each Section
*/
for (uint u = 0; u < eh.e_shnum; u++)
{
Elf32_Shdr* section = cast(Elf32_Shdr*)(buf + eh.e_shoff + eh.e_shentsize * u);
if (section.sh_type == SHT_SYMTAB)
{
/* sh_link gives the particular string table section
* used for the symbol names.
*/
Elf32_Shdr* string_section = cast(Elf32_Shdr*)(buf + eh.e_shoff + eh.e_shentsize * section.sh_link);
if (string_section.sh_type != SHT_STRTAB)
{
reason = __LINE__;
goto Lcorrupt;
}
char* string_tab = cast(char*)(buf + string_section.sh_offset);
for (uint offset = 0; offset < section.sh_size; offset += Elf32_Sym.sizeof)
{
Elf32_Sym* sym = cast(Elf32_Sym*)(buf + section.sh_offset + offset);
if (((sym.st_info >> 4) == STB_GLOBAL || (sym.st_info >> 4) == STB_WEAK) && sym.st_shndx != SHN_UNDEF) // not extern
{
char* name = string_tab + sym.st_name;
//printf("sym st_name = x%x\n", sym->st_name);
(*pAddSymbol)(pctx, name, 1);
}
}
}
}
}
else if (buf[EI_CLASS] == ELFCLASS64)
{
Elf64_Ehdr* eh = cast(Elf64_Ehdr*)buf;
if (buflen < Elf64_Ehdr.sizeof)
goto Lcorrupt;
if (eh.e_type != ET_REL)
{
error(loc, "ELF object module %s is not relocatable", module_name);
return; // not relocatable object module
}
if (eh.e_version != EV_CURRENT)
{
reason = __LINE__;
goto Lcorrupt;
}
/* For each Section
*/
for (uint u = 0; u < eh.e_shnum; u++)
{
Elf64_Shdr* section = cast(Elf64_Shdr*)(buf + eh.e_shoff + eh.e_shentsize * u);
if (section.sh_type == SHT_SYMTAB)
{
/* sh_link gives the particular string table section
* used for the symbol names.
*/
Elf64_Shdr* string_section = cast(Elf64_Shdr*)(buf + eh.e_shoff + eh.e_shentsize * section.sh_link);
if (string_section.sh_type != SHT_STRTAB)
{
reason = 3;
goto Lcorrupt;
}
char* string_tab = cast(char*)(buf + string_section.sh_offset);
for (uint offset = 0; offset < section.sh_size; offset += Elf64_Sym.sizeof)
{
Elf64_Sym* sym = cast(Elf64_Sym*)(buf + section.sh_offset + offset);
if (((sym.st_info >> 4) == STB_GLOBAL || (sym.st_info >> 4) == STB_WEAK) && sym.st_shndx != SHN_UNDEF) // not extern
{
char* name = string_tab + sym.st_name;
//printf("sym st_name = x%x\n", sym->st_name);
(*pAddSymbol)(pctx, name, 1);
}
}
}
}
}
else
{
error(loc, "ELF object module %s is unrecognized class %d", module_name, buf[EI_CLASS]);
return;
}
version (none)
{
/* String table section
*/
Elf32_Shdr* string_section = cast(Elf32_Shdr*)(buf + eh.e_shoff + eh.e_shentsize * eh.e_shstrndx);
if (string_section.sh_type != SHT_STRTAB)
{
//printf("buf = %p, e_shentsize = %d, e_shstrndx = %d\n", buf, eh->e_shentsize, eh->e_shstrndx);
//printf("sh_type = %d, SHT_STRTAB = %d\n", string_section->sh_type, SHT_STRTAB);
reason = 2;
goto Lcorrupt;
}
printf("strtab sh_offset = x%x\n", string_section.sh_offset);
char* string_tab = cast(char*)(buf + string_section.sh_offset);
}
}
346 changes: 346 additions & 0 deletions src/scanmach.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,346 @@
// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt

module ddmd.scanmach;

import core.stdc.string;
import core.stdc.stdint;
import core.sys.osx.mach.loader;
import ddmd.globals;
import ddmd.errors;

enum LOG = false;

/*****************************************
* Reads an object module from base[0..buflen] and passes the names
* of any exported symbols to (*pAddSymbol)().
* Input:
* pctx context pointer, pass to *pAddSymbol
* pAddSymbol function to pass the names to
* base[0..buflen] contains contents of object module
* module_name name of the object module (used for error messages)
* loc location to use for error printing
*/
extern (C++) void scanMachObjModule(void* pctx, void function(void* pctx, char* name, int pickAny) pAddSymbol, void* base, size_t buflen, const(char)* module_name, Loc loc)
{
static if (LOG)
{
printf("scanMachObjModule(%s)\n", module_name);
}
ubyte* buf = cast(ubyte*)base;
int reason = 0;
uint32_t ncmds;
mach_header* header = cast(mach_header*)buf;
mach_header_64* header64 = null;
/* First do sanity checks on object file
*/
if (buflen < mach_header.sizeof)
{
reason = __LINE__;
Lcorrupt:
error(loc, "Mach-O object module %s corrupt, %d", module_name, reason);
return;
}
if (header.magic == MH_MAGIC)
{
if (header.cputype != CPU_TYPE_I386)
{
error(loc, "Mach-O object module %s has cputype = %d, should be %d", module_name, header.cputype, CPU_TYPE_I386);
return;
}
if (header.filetype != MH_OBJECT)
{
error(loc, "Mach-O object module %s has file type = %d, should be %d", module_name, header.filetype, MH_OBJECT);
return;
}
if (buflen < mach_header.sizeof + header.sizeofcmds)
{
reason = __LINE__;
goto Lcorrupt;
}
ncmds = header.ncmds;
}
else if (header.magic == MH_MAGIC_64)
{
header64 = cast(mach_header_64*)buf;
if (buflen < mach_header_64.sizeof)
goto Lcorrupt;
if (header64.cputype != CPU_TYPE_X86_64)
{
error(loc, "Mach-O object module %s has cputype = %d, should be %d", module_name, header64.cputype, CPU_TYPE_X86_64);
return;
}
if (header64.filetype != MH_OBJECT)
{
error(loc, "Mach-O object module %s has file type = %d, should be %d", module_name, header64.filetype, MH_OBJECT);
return;
}
if (buflen < mach_header_64.sizeof + header64.sizeofcmds)
{
reason = __LINE__;
goto Lcorrupt;
}
ncmds = header64.ncmds;
}
else
{
reason = __LINE__;
goto Lcorrupt;
}
segment_command* segment_commands = null;
segment_command_64* segment_commands64 = null;
symtab_command* symtab_commands = null;
dysymtab_command* dysymtab_commands = null;
// Commands immediately follow mach_header
char* commands = cast(char*)buf + (header.magic == MH_MAGIC_64 ? mach_header_64.sizeof : mach_header.sizeof);
for (uint32_t i = 0; i < ncmds; i++)
{
load_command* command = cast(load_command*)commands;
//printf("cmd = 0x%02x, cmdsize = %u\n", command->cmd, command->cmdsize);
switch (command.cmd)
{
case LC_SEGMENT:
segment_commands = cast(segment_command*)command;
break;
case LC_SEGMENT_64:
segment_commands64 = cast(segment_command_64*)command;
break;
case LC_SYMTAB:
symtab_commands = cast(symtab_command*)command;
break;
case LC_DYSYMTAB:
dysymtab_commands = cast(dysymtab_command*)command;
break;
default:
break;
}
commands += command.cmdsize;
}
if (symtab_commands)
{
// Get pointer to string table
char* strtab = cast(char*)buf + symtab_commands.stroff;
if (buflen < symtab_commands.stroff + symtab_commands.strsize)
{
reason = __LINE__;
goto Lcorrupt;
}
if (header.magic == MH_MAGIC_64)
{
// Get pointer to symbol table
nlist_64* symtab = cast(nlist_64*)(cast(char*)buf + symtab_commands.symoff);
if (buflen < symtab_commands.symoff + symtab_commands.nsyms * nlist_64.sizeof)
{
reason = __LINE__;
goto Lcorrupt;
}
// For each symbol
for (int i = 0; i < symtab_commands.nsyms; i++)
{
nlist_64* s = symtab + i;
char* name = strtab + s.n_strx;
if (s.n_type & N_STAB)
{
// values in /usr/include/mach-o/stab.h
//printf(" N_STAB");
}
else
{
version (none)
{
if (s.n_type & N_PEXT)
{
}
if (s.n_type & N_EXT)
{
}
}
switch (s.n_type & N_TYPE)
{
case N_UNDF:
if (s.n_type & N_EXT && s.n_value != 0) // comdef
(*pAddSymbol)(pctx, name, 1);
break;
case N_ABS:
break;
case N_SECT:
if (s.n_type & N_EXT) /*&& !(s->n_desc & N_REF_TO_WEAK)*/
(*pAddSymbol)(pctx, name, 1);
break;
case N_PBUD:
break;
case N_INDR:
break;
default:
break;
}
}
}
}
else
{
// Get pointer to symbol table
nlist* symtab = cast(nlist*)(cast(char*)buf + symtab_commands.symoff);
if (buflen < symtab_commands.symoff + symtab_commands.nsyms * nlist.sizeof)
{
reason = __LINE__;
goto Lcorrupt;
}
// For each symbol
for (int i = 0; i < symtab_commands.nsyms; i++)
{
nlist* s = symtab + i;
char* name = strtab + s.n_strx;
if (s.n_type & N_STAB)
{
// values in /usr/include/mach-o/stab.h
//printf(" N_STAB");
}
else
{
version (none)
{
if (s.n_type & N_PEXT)
{
}
if (s.n_type & N_EXT)
{
}
}
switch (s.n_type & N_TYPE)
{
case N_UNDF:
if (s.n_type & N_EXT && s.n_value != 0) // comdef
(*pAddSymbol)(pctx, name, 1);
break;
case N_ABS:
break;
case N_SECT:
if (s.n_type & N_EXT) /*&& !(s->n_desc & N_REF_TO_WEAK)*/
(*pAddSymbol)(pctx, name, 1);
break;
case N_PBUD:
break;
case N_INDR:
break;
default:
break;
}
}
}
}
}
}

enum CPU_TYPE_I386 = 7;
enum CPU_TYPE_X86_64 = CPU_TYPE_I386 | 0x1000000;

enum MH_OBJECT = 0x1;

struct segment_command
{
uint32_t cmd;
uint32_t cmdsize;
char[16] segname;
uint32_t vmaddr;
uint32_t vmsize;
uint32_t fileoff;
uint32_t filesize;
int32_t maxprot;
int32_t initprot;
uint32_t nsects;
uint32_t flags;
}

struct segment_command_64
{
uint32_t cmd;
uint32_t cmdsize;
char[16] segname;
uint64_t vmaddr;
uint64_t vmsize;
uint64_t fileoff;
uint64_t filesize;
int32_t maxprot;
int32_t initprot;
uint32_t nsects;
uint32_t flags;
}

struct symtab_command
{
uint32_t cmd;
uint32_t cmdsize;
uint32_t symoff;
uint32_t nsyms;
uint32_t stroff;
uint32_t strsize;
}

struct dysymtab_command
{
uint32_t cmd;
uint32_t cmdsize;
uint32_t ilocalsym;
uint32_t nlocalsym;
uint32_t iextdefsym;
uint32_t nextdefsym;
uint32_t iundefsym;
uint32_t nundefsym;
uint32_t tocoff;
uint32_t ntoc;
uint32_t modtaboff;
uint32_t nmodtab;
uint32_t extrefsymoff;
uint32_t nextrefsyms;
uint32_t indirectsymoff;
uint32_t nindirectsyms;
uint32_t extreloff;
uint32_t nextrel;
uint32_t locreloff;
uint32_t nlocrel;
}

enum LC_SEGMENT = 1;
enum LC_SYMTAB = 2;
enum LC_DYSYMTAB = 11;
enum LC_SEGMENT_64 = 0x19;

struct load_command
{
uint32_t cmd;
uint32_t cmdsize;
}

enum N_EXT = 1;
enum N_STAB = 0xE0;
enum N_PEXT = 0x10;
enum N_TYPE = 0x0E;
enum N_UNDF = 0;
enum N_ABS = 2;
enum N_INDR = 10;
enum N_PBUD = 12;
enum N_SECT = 14;

struct nlist
{
int32_t n_strx;
uint8_t n_type;
uint8_t n_sect;
int16_t n_desc;
uint32_t n_value;
};

struct nlist_64
{
uint32_t n_strx;
uint8_t n_type;
uint8_t n_sect;
uint16_t n_desc;
uint64_t n_value;
}
2 changes: 1 addition & 1 deletion src/win32.mak
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ SRCS = win32.mak posix.mak osmodel.mak aggregate.h aliasthis.h arraytypes.h \
GLUESRC= glue.c msc.c s2ir.c todt.c e2ir.c tocsym.c \
toobj.c toctype.c tocvdebug.c toir.h toir.c \
irstate.h irstate.c iasm.c \
toelfdebug.c libelf.c scanelf.c libmach.c scanmach.c \
toelfdebug.c libelf.d scanelf.d libmach.d scanmach.d \
tk.c eh.c objc_glue_stubs.c objc_glue.c

# D back end
Expand Down