1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _scanmscoff.d)
9  */
10 
11 module ddmd.scanmscoff;
12 
13 import core.stdc..string, core.stdc.stdlib, core.sys.windows.windows;
14 import ddmd.globals, ddmd.errors;
15 
16 enum LOG = false;
17 
18 /*****************************************
19  * Reads an object module from base[] and passes the names
20  * of any exported symbols to (*pAddSymbol)().
21  * Params:
22  *      pAddSymbol =  function to pass the names to
23  *      base =        array of contents of object module
24  *      module_name = name of the object module (used for error messages)
25  *      loc =         location to use for error printing
26  */
27 void scanMSCoffObjModule(void delegate(const(char)[] name, int pickAny) pAddSymbol,
28         const(ubyte)[] base, const(char)* module_name, Loc loc)
29 {
30     static if (LOG)
31     {
32         printf("scanMSCoffObjModule(%s)\n", module_name);
33     }
34 
35     void corrupt(int reason)
36     {
37         error(loc, "corrupt MS-Coff object module %s %d", module_name, reason);
38     }
39 
40     const buf = base.ptr;
41     const buflen = base.length;
42     /* First do sanity checks on object file
43      */
44     if (buflen < BIGOBJ_HEADER.sizeof)
45         return corrupt(__LINE__);
46 
47     BIGOBJ_HEADER* header = cast(BIGOBJ_HEADER*)buf;
48     char is_old_coff = false;
49     if (header.Sig2 != 0xFFFF && header.Version != 2)
50     {
51         is_old_coff = true;
52         IMAGE_FILE_HEADER* header_old;
53         header_old = cast(IMAGE_FILE_HEADER*)malloc(IMAGE_FILE_HEADER.sizeof);
54         memcpy(header_old, buf, IMAGE_FILE_HEADER.sizeof);
55         header = cast(BIGOBJ_HEADER*)malloc(BIGOBJ_HEADER.sizeof);
56         *header = BIGOBJ_HEADER.init;
57         header.Machine = header_old.Machine;
58         header.NumberOfSections = header_old.NumberOfSections;
59         header.TimeDateStamp = header_old.TimeDateStamp;
60         header.PointerToSymbolTable = header_old.PointerToSymbolTable;
61         header.NumberOfSymbols = header_old.NumberOfSymbols;
62         free(header_old);
63     }
64     switch (header.Machine)
65     {
66     case IMAGE_FILE_MACHINE_UNKNOWN:
67     case IMAGE_FILE_MACHINE_I386:
68     case IMAGE_FILE_MACHINE_AMD64:
69         break;
70     default:
71         if (buf[0] == 0x80)
72             error(loc, "Object module %s is 32 bit OMF, but it should be 64 bit MS-Coff", module_name);
73         else
74             error(loc, "MS-Coff object module %s has magic = %x, should be %x", module_name, header.Machine, IMAGE_FILE_MACHINE_AMD64);
75         return;
76     }
77     // Get string table:  string_table[0..string_len]
78     size_t off = header.PointerToSymbolTable;
79     if (off == 0)
80     {
81         error(loc, "MS-Coff object module %s has no string table", module_name);
82         return;
83     }
84     off += header.NumberOfSymbols * (is_old_coff ? SymbolTable.sizeof : SymbolTable32.sizeof);
85     if (off + 4 > buflen)
86         return corrupt(__LINE__);
87 
88     uint string_len = *cast(uint*)(buf + off);
89     char* string_table = cast(char*)(buf + off + 4);
90     if (off + string_len > buflen)
91         return corrupt(__LINE__);
92 
93     string_len -= 4;
94     for (int i = 0; i < header.NumberOfSymbols; i++)
95     {
96         SymbolTable32* n;
97         char[8 + 1] s;
98         char* p;
99         static if (LOG)
100         {
101             printf("Symbol %d:\n", i);
102         }
103         off = header.PointerToSymbolTable + i * (is_old_coff ? SymbolTable.sizeof : SymbolTable32.sizeof);
104         if (off > buflen)
105             return corrupt(__LINE__);
106 
107         n = cast(SymbolTable32*)(buf + off);
108         if (is_old_coff)
109         {
110             SymbolTable* n2;
111             n2 = cast(SymbolTable*)malloc(SymbolTable.sizeof);
112             memcpy(n2, (buf + off), SymbolTable.sizeof);
113             n = cast(SymbolTable32*)malloc(SymbolTable32.sizeof);
114             memcpy(n, n2, (n2.Name).sizeof);
115             n.Value = n2.Value;
116             n.SectionNumber = n2.SectionNumber;
117             n.Type = n2.Type;
118             n.StorageClass = n2.StorageClass;
119             n.NumberOfAuxSymbols = n2.NumberOfAuxSymbols;
120             free(n2);
121         }
122         if (n.Zeros)
123         {
124             strncpy(s.ptr, cast(const(char)*)n.Name, 8);
125             s[SYMNMLEN] = 0;
126             p = s.ptr;
127         }
128         else
129             p = string_table + n.Offset - 4;
130         i += n.NumberOfAuxSymbols;
131         static if (LOG)
132         {
133             printf("n_name    = '%s'\n", p);
134             printf("n_value   = x%08lx\n", n.Value);
135             printf("n_scnum   = %d\n", n.SectionNumber);
136             printf("n_type    = x%04x\n", n.Type);
137             printf("n_sclass  = %d\n", n.StorageClass);
138             printf("n_numaux  = %d\n", n.NumberOfAuxSymbols);
139         }
140         switch (n.SectionNumber)
141         {
142         case IMAGE_SYM_DEBUG:
143             continue;
144         case IMAGE_SYM_ABSOLUTE:
145             if (strcmp(p, "@comp.id") == 0)
146                 continue;
147             break;
148         case IMAGE_SYM_UNDEFINED:
149             // A non-zero value indicates a common block
150             if (n.Value)
151                 break;
152             continue;
153         default:
154             break;
155         }
156         switch (n.StorageClass)
157         {
158         case IMAGE_SYM_CLASS_EXTERNAL:
159             break;
160         case IMAGE_SYM_CLASS_STATIC:
161             if (n.Value == 0) // if it's a section name
162                 continue;
163             continue;
164         case IMAGE_SYM_CLASS_FUNCTION:
165         case IMAGE_SYM_CLASS_FILE:
166         case IMAGE_SYM_CLASS_LABEL:
167             continue;
168         default:
169             continue;
170         }
171         pAddSymbol(p[0 .. strlen(p)], 1);
172     }
173 }
174 
175 align(1)
176 struct BIGOBJ_HEADER
177 {
178     WORD Sig1;                  // IMAGE_FILE_MACHINE_UNKNOWN
179     WORD Sig2;                  // 0xFFFF
180     WORD Version;               // 2
181     WORD Machine;               // identifies type of target machine
182     DWORD TimeDateStamp;        // creation date, number of seconds since 1970
183     BYTE[16]  UUID;             //  { '\xc7', '\xa1', '\xba', '\xd1', '\xee', '\xba', '\xa9', '\x4b',
184                                 //    '\xaf', '\x20', '\xfa', '\xf6', '\x6a', '\xa4', '\xdc', '\xb8' };
185     DWORD[4] unused;            // { 0, 0, 0, 0 }
186     DWORD NumberOfSections;     // number of sections
187     DWORD PointerToSymbolTable; // file offset of symbol table
188     DWORD NumberOfSymbols;      // number of entries in the symbol table
189 }
190 
191 align(1)
192 struct IMAGE_FILE_HEADER
193 {
194     WORD  Machine;
195     WORD  NumberOfSections;
196     DWORD TimeDateStamp;
197     DWORD PointerToSymbolTable;
198     DWORD NumberOfSymbols;
199     WORD  SizeOfOptionalHeader;
200     WORD  Characteristics;
201 }
202 
203 enum SYMNMLEN = 8;
204 
205 enum IMAGE_FILE_MACHINE_UNKNOWN = 0;            // applies to any machine type
206 enum IMAGE_FILE_MACHINE_I386    = 0x14C;        // x86
207 enum IMAGE_FILE_MACHINE_AMD64   = 0x8664;       // x86_64
208 
209 enum IMAGE_SYM_DEBUG     = -2;
210 enum IMAGE_SYM_ABSOLUTE  = -1;
211 enum IMAGE_SYM_UNDEFINED = 0;
212 
213 enum IMAGE_SYM_CLASS_EXTERNAL = 2;
214 enum IMAGE_SYM_CLASS_STATIC   = 3;
215 enum IMAGE_SYM_CLASS_LABEL    = 6;
216 enum IMAGE_SYM_CLASS_FUNCTION = 101;
217 enum IMAGE_SYM_CLASS_FILE     = 103;
218 
219 align(1) struct SymbolTable32
220 {
221     union
222     {
223         BYTE[SYMNMLEN] Name;
224         struct
225         {
226             DWORD Zeros;
227             DWORD Offset;
228         }
229     }
230 
231     DWORD Value;
232     DWORD SectionNumber;
233     WORD Type;
234     BYTE StorageClass;
235     BYTE NumberOfAuxSymbols;
236 }
237 
238 align(1) struct SymbolTable
239 {
240     BYTE[SYMNMLEN] Name;
241     DWORD Value;
242     WORD SectionNumber;
243     WORD Type;
244     BYTE StorageClass;
245     BYTE NumberOfAuxSymbols;
246 }