]> Cypherpunks repositories - gostls13.git/commitdiff
libmach: support reading symbols from Windows .exe for nm
authorMateusz CzapliƄski <czapkofan@gmail.com>
Mon, 29 Aug 2011 18:25:43 +0000 (14:25 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 29 Aug 2011 18:25:43 +0000 (14:25 -0400)
Fixes #979.

R=rsc, alex.brainman
CC=golang-dev, vcc.163
https://golang.org/cl/4894051

include/mach.h
src/cmd/ld/pe.c
src/libmach/executable.c

index 5b1ce7b3a9b3441aac2db4bc98ab2f7ce6dcf779..cf7151cfd2fa1b088eabe89fa360323109e7a895 100644 (file)
@@ -142,6 +142,7 @@ enum
        FAMD64B,                /* 6.out bootable */
        FPOWER64,               /* 9.out */
        FPOWER64B,              /* 9.out bootable */
+       FWINPE,                 /* windows PE executable */
 
        ANONE = 0,              /* dissembler types */
        AMIPS,
index 334c9959fa08f85452112949206e22b65da2bed5..6379b1ad3a9d373164c4a1468b529cc5522d1e5d 100644 (file)
@@ -32,6 +32,11 @@ static char dosstub[] =
        0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
+// Note: currently only up to 8 chars plus \0.
+static char *symlabels[] = {
+       "symtab", "esymtab", "pclntab", "epclntab"
+};
+
 static Sym *rsrcsym;
 
 static char symnames[256]; 
@@ -44,6 +49,7 @@ static int pe64;
 static int nsect;
 static int nextsectoff;
 static int nextfileoff;
+static int textsect;
 
 static IMAGE_FILE_HEADER fh;
 static IMAGE_OPTIONAL_HEADER oh;
@@ -449,20 +455,29 @@ addsymtable(void)
 {
        IMAGE_SECTION_HEADER *h;
        int i, size;
+       Sym *s;
        
-       if(nextsymoff == 0)
-               return;
-       
-       size  = nextsymoff + 4 + 18;
+       fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]);
+       size = nextsymoff + 4 + 18*fh.NumberOfSymbols;
        h = addpesection(".symtab", size, size);
        h->Characteristics = IMAGE_SCN_MEM_READ|
                IMAGE_SCN_MEM_DISCARDABLE;
        chksectoff(h, cpos());
        fh.PointerToSymbolTable = cpos();
-       fh.NumberOfSymbols = 1;
-       strnput("", 18); // one empty symbol
-       // put symbol string table
-       lputl(size);
+       
+       // put COFF symbol table
+       for (i=0; i<fh.NumberOfSymbols; i++) {
+               s = rlookup(symlabels[i], 0);
+               strnput(s->name, 8);
+               lputl(datoff(s->value));
+               wputl(textsect);
+               wputl(0x0308);  // "array of structs"
+               cput(2);        // storage class: external
+               cput(0);        // no aux entries
+       }
+
+       // put COFF string table
+       lputl(nextsymoff + 4);
        for (i=0; i<nextsymoff; i++)
                cput(symnames[i]);
        strnput("", h->SizeOfRawData - size);
@@ -532,6 +547,7 @@ asmbpe(void)
                IMAGE_SCN_CNT_INITIALIZED_DATA|
                IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
        chksectseg(t, &segtext);
+       textsect = nsect;
 
        d = addpesection(".data", segdata.len, segdata.filelen);
        d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
index 1ad6e3b5d29e093a2a296399c363448f26fa77e2..fa0fa1b5fdba7852ec6c8c8590c2d10f622ee748 100644 (file)
@@ -66,6 +66,7 @@ static        int     adotout(int, Fhdr*, ExecHdr*);
 static int     elfdotout(int, Fhdr*, ExecHdr*);
 static int     machdotout(int, Fhdr*, ExecHdr*);
 static int     armdotout(int, Fhdr*, ExecHdr*);
+static int     pedotout(int, Fhdr*, ExecHdr*);
 static void    setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32);
 static void    setdata(Fhdr*, uvlong, int32, vlong, int32);
 static void    settext(Fhdr*, uvlong, uvlong, int32, vlong);
@@ -312,6 +313,15 @@ ExecTable exectab[] =
                sizeof(Exec),
                beswal,
                common },
+       { 0x4d5a9000,    /* see dosstub[] in pe.c */
+               "windows PE executable",
+               nil,
+               FWINPE,
+               0,
+               &mi386,
+               sizeof(Exec), /* TODO */
+               nil,
+               pedotout },
        { 0 },
 };
 
@@ -1249,6 +1259,164 @@ armdotout(int fd, Fhdr *fp, ExecHdr *hp)
        return 1;
 }
 
+/*
+ * Structures needed to parse PE image.
+ */
+typedef struct {
+       uint16 Machine;
+       uint16 NumberOfSections;
+       uint32 TimeDateStamp;
+       uint32 PointerToSymbolTable;
+       uint32 NumberOfSymbols;
+       uint16 SizeOfOptionalHeader;
+       uint16 Characteristics;
+} IMAGE_FILE_HEADER;
+
+typedef struct {
+       uint8  Name[8];
+       uint32 VirtualSize;
+       uint32 VirtualAddress;
+       uint32 SizeOfRawData;
+       uint32 PointerToRawData;
+       uint32 PointerToRelocations;
+       uint32 PointerToLineNumbers;
+       uint16 NumberOfRelocations;
+       uint16 NumberOfLineNumbers;
+       uint32 Characteristics;
+} IMAGE_SECTION_HEADER;
+
+typedef struct {
+       uint32 VirtualAddress;
+       uint32 Size;
+} IMAGE_DATA_DIRECTORY;
+
+typedef struct {
+       uint16 Magic;
+       uint8  MajorLinkerVersion;
+       uint8  MinorLinkerVersion;
+       uint32 SizeOfCode;
+       uint32 SizeOfInitializedData;
+       uint32 SizeOfUninitializedData;
+       uint32 AddressOfEntryPoint;
+       uint32 BaseOfCode;
+       uint32 BaseOfData;
+       uint32 ImageBase;
+       uint32 SectionAlignment;
+       uint32 FileAlignment;
+       uint16 MajorOperatingSystemVersion;
+       uint16 MinorOperatingSystemVersion;
+       uint16 MajorImageVersion;
+       uint16 MinorImageVersion;
+       uint16 MajorSubsystemVersion;
+       uint16 MinorSubsystemVersion;
+       uint32 Win32VersionValue;
+       uint32 SizeOfImage;
+       uint32 SizeOfHeaders;
+       uint32 CheckSum;
+       uint16 Subsystem;
+       uint16 DllCharacteristics;
+       uint32 SizeOfStackReserve;
+       uint32 SizeOfStackCommit;
+       uint32 SizeOfHeapReserve;
+       uint32 SizeOfHeapCommit;
+       uint32 LoaderFlags;
+       uint32 NumberOfRvaAndSizes;
+       IMAGE_DATA_DIRECTORY DataDirectory[16];
+} IMAGE_OPTIONAL_HEADER;
+
+static int
+match8(void *buf, char *cmp)
+{
+       return strncmp((char*)buf, cmp, 8) == 0;
+}
+
+/* TODO(czaplinski): 64b windows? */
+/*
+ * Read from Windows PE/COFF .exe file image.
+ */
+static int
+pedotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+       uint32 start, magic;
+       uint32 symtab, esymtab;
+       IMAGE_FILE_HEADER fh;
+       IMAGE_SECTION_HEADER sh;
+       IMAGE_OPTIONAL_HEADER oh;
+       uint8 sym[18];
+       uint32 *valp;
+       int i;
+
+       USED(hp);
+       seek(fd, 0x3c, 0);
+       if (readn(fd, &start, sizeof(start)) != sizeof(start)) {
+               werrstr("crippled PE MSDOS header");
+               return 0;
+       }
+       start = leswal(start);
+
+       seek(fd, start, 0);
+       if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) {
+               werrstr("no PE magic number found");
+               return 0;
+       }
+       if (beswal(magic) != 0x50450000) {  /* "PE\0\0" */
+               werrstr("incorrect PE magic number");
+               return 0;
+       }
+
+       if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) {
+               werrstr("crippled PE File Header");
+               return 0;
+       }
+       if (fh.PointerToSymbolTable == 0) {
+               werrstr("zero pointer to COFF symbol table");
+               return 0;
+       }
+
+       if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) {
+               werrstr("crippled PE Optional Header");
+               return 0;
+       }
+
+       seek(fd, start+sizeof(magic)+sizeof(fh)+leswab(fh.SizeOfOptionalHeader), 0);
+       fp->txtaddr = fp->dataddr = 0;
+       for (i=0; i<leswab(fh.NumberOfSections); i++) {
+               if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) {
+                       werrstr("could not read Section Header %d", i+1);
+                       return 0;
+               }
+               if (match8(sh.Name, ".text"))
+                       settext(fp, leswal(sh.VirtualAddress), leswal(oh.AddressOfEntryPoint), leswal(sh.VirtualSize), leswal(sh.PointerToRawData));
+               if (match8(sh.Name, ".data"))
+                       setdata(fp, leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData));
+       }
+       if (fp->txtaddr==0 || fp->dataddr==0) {
+               werrstr("no .text or .data");
+               return 0;
+       }
+
+       seek(fd, leswal(fh.PointerToSymbolTable), 0);
+       symtab = esymtab = 0;
+       for (i=0; i<leswal(fh.NumberOfSymbols); i++) {
+               if (readn(fd, &sym, sizeof(sym)) != sizeof(sym)) {
+                       werrstr("crippled COFF symbol %d", i);
+                       return 0;
+               }
+               valp = (uint32 *)&sym[8];
+               if (match8(sym, "symtab"))
+                       symtab = leswal(*valp);
+               if (match8(sym, "esymtab"))
+                       esymtab = leswal(*valp);
+       }
+       if (symtab==0 || esymtab==0) {
+               werrstr("no symtab or esymtab in COFF symbol table");
+               return 0;
+       }
+       setsym(fp, symtab, esymtab-symtab, 0, 0, 0, 0);
+
+       return 1;
+}
+
 static void
 settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
 {