]>
Commit | Line | Data |
---|---|---|
b41a6533 | 1 | /* Support for generating PDB CodeView debugging files. |
d87bef3a | 2 | Copyright (C) 2022-2023 Free Software Foundation, Inc. |
b41a6533 MH |
3 | |
4 | This file is part of the GNU Binutils. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
18 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | |
19 | MA 02110-1301, USA. */ | |
20 | ||
21 | #include "pdb.h" | |
22 | #include "bfdlink.h" | |
23 | #include "ld.h" | |
8d25f5ef | 24 | #include "ldmain.h" |
b41a6533 MH |
25 | #include "ldmisc.h" |
26 | #include "libbfd.h" | |
27 | #include "libiberty.h" | |
28 | #include "coff/i386.h" | |
29 | #include "coff/external.h" | |
30 | #include "coff/internal.h" | |
31 | #include "coff/pe.h" | |
32 | #include "libcoff.h" | |
33 | #include <time.h> | |
34 | ||
35 | struct public | |
36 | { | |
37 | struct public *next; | |
38 | uint32_t offset; | |
39 | uint32_t hash; | |
40 | unsigned int index; | |
41 | uint16_t section; | |
42 | uint32_t address; | |
43 | }; | |
44 | ||
f559276d MH |
45 | struct string |
46 | { | |
47 | struct string *next; | |
48 | uint32_t hash; | |
49 | uint32_t offset; | |
803561cb | 50 | uint32_t source_file_offset; |
f559276d MH |
51 | size_t len; |
52 | char s[]; | |
53 | }; | |
54 | ||
55 | struct string_table | |
56 | { | |
57 | struct string *strings_head; | |
58 | struct string *strings_tail; | |
59 | uint32_t strings_len; | |
60 | htab_t hashmap; | |
61 | }; | |
62 | ||
803561cb MH |
63 | struct mod_source_files |
64 | { | |
65 | uint16_t files_count; | |
66 | struct string **files; | |
67 | }; | |
68 | ||
69 | struct source_files_info | |
70 | { | |
71 | uint16_t mod_count; | |
72 | struct mod_source_files *mods; | |
73 | }; | |
74 | ||
d5b4c0dd MH |
75 | struct type_entry |
76 | { | |
77 | struct type_entry *next; | |
78 | uint32_t index; | |
79 | uint32_t cv_hash; | |
81784004 | 80 | bool has_udt_src_line; |
d5b4c0dd MH |
81 | uint8_t data[]; |
82 | }; | |
83 | ||
84 | struct types | |
85 | { | |
86 | htab_t hashmap; | |
87 | uint32_t num_types; | |
88 | struct type_entry *first; | |
89 | struct type_entry *last; | |
90 | }; | |
91 | ||
81814b6f MH |
92 | struct global |
93 | { | |
94 | struct global *next; | |
95 | uint32_t offset; | |
96 | uint32_t hash; | |
97 | uint32_t refcount; | |
98 | unsigned int index; | |
99 | uint8_t data[]; | |
100 | }; | |
101 | ||
102 | struct globals | |
103 | { | |
104 | uint32_t num_entries; | |
105 | struct global *first; | |
106 | struct global *last; | |
107 | htab_t hashmap; | |
108 | }; | |
109 | ||
38395c77 MH |
110 | struct in_sc |
111 | { | |
112 | asection *s; | |
113 | uint16_t sect_num; | |
114 | uint16_t mod_index; | |
115 | }; | |
116 | ||
d5b4c0dd MH |
117 | static const uint32_t crc_table[] = |
118 | { | |
119 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, | |
120 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, | |
121 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, | |
122 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, | |
123 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, | |
124 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, | |
125 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, | |
126 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, | |
127 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, | |
128 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, | |
129 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, | |
130 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, | |
131 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, | |
132 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, | |
133 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, | |
134 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, | |
135 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, | |
136 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, | |
137 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, | |
138 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, | |
139 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, | |
140 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, | |
141 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, | |
142 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, | |
143 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, | |
144 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, | |
145 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, | |
146 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, | |
147 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, | |
148 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, | |
149 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, | |
150 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, | |
151 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, | |
152 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, | |
153 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, | |
154 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, | |
155 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, | |
156 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, | |
157 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, | |
158 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, | |
159 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, | |
160 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, | |
161 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | |
162 | }; | |
163 | ||
b41a6533 MH |
164 | /* Add a new stream to the PDB archive, and return its BFD. */ |
165 | static bfd * | |
166 | add_stream (bfd *pdb, const char *name, uint16_t *stream_num) | |
167 | { | |
168 | bfd *stream; | |
169 | uint16_t num; | |
170 | ||
171 | stream = bfd_create (name ? name : "", pdb); | |
172 | if (!stream) | |
173 | return NULL; | |
174 | ||
175 | if (!bfd_make_writable (stream)) | |
176 | { | |
177 | bfd_close (stream); | |
178 | return false; | |
179 | } | |
180 | ||
181 | if (!pdb->archive_head) | |
182 | { | |
183 | bfd_set_archive_head (pdb, stream); | |
184 | num = 0; | |
185 | } | |
186 | else | |
187 | { | |
188 | bfd *b = pdb->archive_head; | |
189 | ||
190 | num = 1; | |
191 | ||
192 | while (b->archive_next) | |
193 | { | |
194 | num++; | |
195 | b = b->archive_next; | |
196 | } | |
197 | ||
198 | b->archive_next = stream; | |
199 | } | |
200 | ||
201 | if (stream_num) | |
202 | *stream_num = num; | |
203 | ||
204 | return stream; | |
205 | } | |
206 | ||
207 | /* Stream 0 ought to be a copy of the MSF directory from the last | |
208 | time the PDB file was written. Because we don't do incremental | |
209 | writes this isn't applicable to us, but we fill it with a dummy | |
210 | value so as not to confuse radare. */ | |
211 | static bool | |
212 | create_old_directory_stream (bfd *pdb) | |
213 | { | |
214 | bfd *stream; | |
215 | char buf[sizeof (uint32_t)]; | |
216 | ||
217 | stream = add_stream (pdb, NULL, NULL); | |
218 | if (!stream) | |
219 | return false; | |
220 | ||
221 | bfd_putl32 (0, buf); | |
222 | ||
226f9f4f | 223 | return bfd_write (buf, sizeof (uint32_t), stream) == sizeof (uint32_t); |
b41a6533 MH |
224 | } |
225 | ||
226 | /* Calculate the hash of a given string. */ | |
227 | static uint32_t | |
228 | calc_hash (const char *data, size_t len) | |
229 | { | |
230 | uint32_t hash = 0; | |
231 | ||
232 | while (len >= 4) | |
233 | { | |
234 | hash ^= data[0]; | |
235 | hash ^= data[1] << 8; | |
236 | hash ^= data[2] << 16; | |
237 | hash ^= data[3] << 24; | |
238 | ||
239 | data += 4; | |
240 | len -= 4; | |
241 | } | |
242 | ||
243 | if (len >= 2) | |
244 | { | |
245 | hash ^= data[0]; | |
246 | hash ^= data[1] << 8; | |
247 | ||
248 | data += 2; | |
249 | len -= 2; | |
250 | } | |
251 | ||
252 | if (len != 0) | |
253 | hash ^= *data; | |
254 | ||
255 | hash |= 0x20202020; | |
256 | hash ^= (hash >> 11); | |
257 | ||
258 | return hash ^ (hash >> 16); | |
259 | } | |
260 | ||
261 | /* Stream 1 is the PDB info stream - see | |
262 | https://llvm.org/docs/PDB/PdbStream.html. */ | |
263 | static bool | |
264 | populate_info_stream (bfd *pdb, bfd *info_stream, const unsigned char *guid) | |
265 | { | |
266 | bool ret = false; | |
267 | struct pdb_stream_70 h; | |
268 | uint32_t num_entries, num_buckets; | |
269 | uint32_t names_length, stream_num; | |
270 | char int_buf[sizeof (uint32_t)]; | |
271 | ||
272 | struct hash_entry | |
273 | { | |
274 | uint32_t offset; | |
275 | uint32_t value; | |
276 | }; | |
277 | ||
278 | struct hash_entry **buckets = NULL; | |
279 | ||
280 | /* Write header. */ | |
281 | ||
282 | bfd_putl32 (PDB_STREAM_VERSION_VC70, &h.version); | |
283 | bfd_putl32 (time (NULL), &h.signature); | |
284 | bfd_putl32 (1, &h.age); | |
285 | ||
286 | bfd_putl32 (bfd_getb32 (guid), h.guid); | |
287 | bfd_putl16 (bfd_getb16 (&guid[4]), &h.guid[4]); | |
288 | bfd_putl16 (bfd_getb16 (&guid[6]), &h.guid[6]); | |
289 | memcpy (&h.guid[8], &guid[8], 8); | |
290 | ||
226f9f4f | 291 | if (bfd_write (&h, sizeof (h), info_stream) != sizeof (h)) |
b41a6533 MH |
292 | return false; |
293 | ||
294 | /* Write hash list of named streams. This is a "rollover" hash, i.e. | |
295 | if a bucket is filled an entry gets placed in the next free | |
296 | slot. */ | |
297 | ||
298 | num_entries = 0; | |
299 | for (bfd *b = pdb->archive_head; b; b = b->archive_next) | |
300 | { | |
301 | if (strcmp (b->filename, "")) | |
302 | num_entries++; | |
303 | } | |
304 | ||
305 | num_buckets = num_entries * 2; | |
306 | ||
307 | names_length = 0; | |
308 | stream_num = 0; | |
309 | ||
310 | if (num_buckets > 0) | |
311 | { | |
312 | buckets = xmalloc (sizeof (struct hash_entry *) * num_buckets); | |
313 | memset (buckets, 0, sizeof (struct hash_entry *) * num_buckets); | |
314 | ||
315 | for (bfd *b = pdb->archive_head; b; b = b->archive_next) | |
316 | { | |
317 | if (strcmp (b->filename, "")) | |
318 | { | |
319 | size_t len = strlen (b->filename); | |
320 | uint32_t hash = (uint16_t) calc_hash (b->filename, len); | |
321 | uint32_t bucket_num = hash % num_buckets; | |
322 | ||
323 | while (buckets[bucket_num]) | |
324 | { | |
325 | bucket_num++; | |
326 | ||
327 | if (bucket_num == num_buckets) | |
328 | bucket_num = 0; | |
329 | } | |
330 | ||
331 | buckets[bucket_num] = xmalloc (sizeof (struct hash_entry)); | |
332 | ||
333 | buckets[bucket_num]->offset = names_length; | |
334 | buckets[bucket_num]->value = stream_num; | |
335 | ||
336 | names_length += len + 1; | |
337 | } | |
338 | ||
339 | stream_num++; | |
340 | } | |
341 | } | |
342 | ||
343 | /* Write the strings list - the hash keys are indexes into this. */ | |
344 | ||
345 | bfd_putl32 (names_length, int_buf); | |
346 | ||
226f9f4f | 347 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
348 | sizeof (uint32_t)) |
349 | goto end; | |
350 | ||
351 | for (bfd *b = pdb->archive_head; b; b = b->archive_next) | |
352 | { | |
353 | if (!strcmp (b->filename, "")) | |
354 | continue; | |
355 | ||
356 | size_t len = strlen (b->filename) + 1; | |
357 | ||
226f9f4f | 358 | if (bfd_write (b->filename, len, info_stream) != len) |
b41a6533 MH |
359 | goto end; |
360 | } | |
361 | ||
362 | /* Write the number of entries and buckets. */ | |
363 | ||
364 | bfd_putl32 (num_entries, int_buf); | |
365 | ||
226f9f4f | 366 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
367 | sizeof (uint32_t)) |
368 | goto end; | |
369 | ||
370 | bfd_putl32 (num_buckets, int_buf); | |
371 | ||
226f9f4f | 372 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
373 | sizeof (uint32_t)) |
374 | goto end; | |
375 | ||
376 | /* Write the present bitmap. */ | |
377 | ||
378 | bfd_putl32 ((num_buckets + 31) / 32, int_buf); | |
379 | ||
226f9f4f | 380 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
381 | sizeof (uint32_t)) |
382 | goto end; | |
383 | ||
384 | for (unsigned int i = 0; i < num_buckets; i += 32) | |
385 | { | |
386 | uint32_t v = 0; | |
387 | ||
388 | for (unsigned int j = 0; j < 32; j++) | |
389 | { | |
390 | if (i + j >= num_buckets) | |
391 | break; | |
392 | ||
393 | if (buckets[i + j]) | |
394 | v |= 1 << j; | |
395 | } | |
396 | ||
397 | bfd_putl32 (v, int_buf); | |
398 | ||
226f9f4f | 399 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
400 | sizeof (uint32_t)) |
401 | goto end; | |
402 | } | |
403 | ||
404 | /* Write the (empty) deleted bitmap. */ | |
405 | ||
406 | bfd_putl32 (0, int_buf); | |
407 | ||
226f9f4f | 408 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
409 | sizeof (uint32_t)) |
410 | goto end; | |
411 | ||
412 | /* Write the buckets. */ | |
413 | ||
414 | for (unsigned int i = 0; i < num_buckets; i++) | |
415 | { | |
416 | if (buckets[i]) | |
417 | { | |
418 | bfd_putl32 (buckets[i]->offset, int_buf); | |
419 | ||
226f9f4f | 420 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
421 | sizeof (uint32_t)) |
422 | goto end; | |
423 | ||
424 | bfd_putl32 (buckets[i]->value, int_buf); | |
425 | ||
226f9f4f | 426 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
427 | sizeof (uint32_t)) |
428 | goto end; | |
429 | } | |
430 | } | |
431 | ||
432 | bfd_putl32 (0, int_buf); | |
433 | ||
226f9f4f | 434 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
435 | sizeof (uint32_t)) |
436 | goto end; | |
437 | ||
438 | bfd_putl32 (PDB_STREAM_VERSION_VC140, int_buf); | |
439 | ||
226f9f4f | 440 | if (bfd_write (int_buf, sizeof (uint32_t), info_stream) != |
b41a6533 MH |
441 | sizeof (uint32_t)) |
442 | goto end; | |
443 | ||
444 | ret = true; | |
445 | ||
446 | end: | |
447 | for (unsigned int i = 0; i < num_buckets; i++) | |
448 | { | |
449 | if (buckets[i]) | |
450 | free (buckets[i]); | |
451 | } | |
452 | ||
453 | free (buckets); | |
454 | ||
455 | return ret; | |
456 | } | |
457 | ||
d5b4c0dd MH |
458 | /* Calculate the CRC32 used for type hashes. */ |
459 | static uint32_t | |
460 | crc32 (const uint8_t *data, size_t len) | |
461 | { | |
462 | uint32_t crc = 0; | |
463 | ||
464 | while (len > 0) | |
465 | { | |
466 | crc = (crc >> 8) ^ crc_table[(crc & 0xff) ^ *data]; | |
467 | ||
468 | data++; | |
469 | len--; | |
470 | } | |
471 | ||
472 | return crc; | |
473 | } | |
474 | ||
b41a6533 MH |
475 | /* Stream 2 is the type information (TPI) stream, and stream 4 is |
476 | the ID information (IPI) stream. They differ only in which records | |
477 | go in which stream. */ | |
478 | static bool | |
d5b4c0dd | 479 | populate_type_stream (bfd *pdb, bfd *stream, struct types *types) |
b41a6533 | 480 | { |
b41a6533 | 481 | struct pdb_tpi_stream_header h; |
d5b4c0dd MH |
482 | struct type_entry *e; |
483 | uint32_t len = 0, index_offset_len, off; | |
484 | struct bfd *hash_stream = NULL; | |
485 | uint16_t hash_stream_index; | |
b41a6533 | 486 | |
d5b4c0dd MH |
487 | static const uint32_t index_skip = 0x2000; |
488 | ||
489 | e = types->first; | |
490 | ||
491 | index_offset_len = 0; | |
492 | ||
493 | while (e) | |
494 | { | |
495 | uint32_t old_len = len; | |
496 | ||
497 | len += sizeof (uint16_t) + bfd_getl16 (e->data); | |
498 | ||
499 | if (old_len == 0 || old_len / index_skip != len / index_skip) | |
500 | index_offset_len += sizeof (uint32_t) * 2; | |
501 | ||
502 | e = e->next; | |
503 | } | |
504 | ||
505 | /* Each type stream also has a stream which holds the hash value for each | |
506 | type, along with a skip list to speed up searching. */ | |
507 | ||
508 | hash_stream = add_stream (pdb, "", &hash_stream_index); | |
509 | ||
510 | if (!hash_stream) | |
b41a6533 MH |
511 | return false; |
512 | ||
513 | bfd_putl32 (TPI_STREAM_VERSION_80, &h.version); | |
514 | bfd_putl32 (sizeof (h), &h.header_size); | |
515 | bfd_putl32 (TPI_FIRST_INDEX, &h.type_index_begin); | |
d5b4c0dd MH |
516 | bfd_putl32 (TPI_FIRST_INDEX + types->num_types, &h.type_index_end); |
517 | bfd_putl32 (len, &h.type_record_bytes); | |
518 | bfd_putl16 (hash_stream_index, &h.hash_stream_index); | |
b41a6533 | 519 | bfd_putl16 (0xffff, &h.hash_aux_stream_index); |
d5b4c0dd MH |
520 | bfd_putl32 (sizeof (uint32_t), &h.hash_key_size); |
521 | bfd_putl32 (NUM_TPI_HASH_BUCKETS, &h.num_hash_buckets); | |
b41a6533 | 522 | bfd_putl32 (0, &h.hash_value_buffer_offset); |
d5b4c0dd MH |
523 | bfd_putl32 (types->num_types * sizeof (uint32_t), |
524 | &h.hash_value_buffer_length); | |
525 | bfd_putl32 (types->num_types * sizeof (uint32_t), | |
526 | &h.index_offset_buffer_offset); | |
527 | bfd_putl32 (index_offset_len, &h.index_offset_buffer_length); | |
528 | bfd_putl32 ((types->num_types * sizeof (uint32_t)) + index_offset_len, | |
529 | &h.hash_adj_buffer_offset); | |
b41a6533 MH |
530 | bfd_putl32 (0, &h.hash_adj_buffer_length); |
531 | ||
226f9f4f | 532 | if (bfd_write (&h, sizeof (h), stream) != sizeof (h)) |
b41a6533 MH |
533 | return false; |
534 | ||
d5b4c0dd MH |
535 | /* Write the type definitions into the main stream, and the hashes |
536 | into the hash stream. The hashes have already been calculated | |
537 | in handle_type. */ | |
538 | ||
539 | e = types->first; | |
540 | ||
541 | while (e) | |
542 | { | |
543 | uint8_t buf[sizeof (uint32_t)]; | |
544 | uint16_t size; | |
545 | ||
546 | size = bfd_getl16 (e->data); | |
547 | ||
226f9f4f | 548 | if (bfd_write (e->data, size + sizeof (uint16_t), stream) |
d5b4c0dd MH |
549 | != size + sizeof (uint16_t)) |
550 | return false; | |
551 | ||
552 | bfd_putl32 (e->cv_hash % NUM_TPI_HASH_BUCKETS, buf); | |
553 | ||
226f9f4f | 554 | if (bfd_write (buf, sizeof (uint32_t), hash_stream) |
d5b4c0dd MH |
555 | != sizeof (uint32_t)) |
556 | return false; | |
557 | ||
558 | e = e->next; | |
559 | } | |
560 | ||
561 | /* Write the index offsets, i.e. the skip list, into the hash stream. We | |
562 | copy MSVC here by writing a new entry for every 8192 bytes. */ | |
563 | ||
564 | e = types->first; | |
565 | off = 0; | |
566 | ||
567 | while (e) | |
568 | { | |
569 | uint32_t old_off = off; | |
570 | uint16_t size = bfd_getl16 (e->data); | |
571 | ||
572 | off += size + sizeof (uint16_t); | |
573 | ||
574 | if (old_off == 0 || old_off / index_skip != len / index_skip) | |
575 | { | |
576 | uint8_t buf[sizeof (uint32_t)]; | |
577 | ||
578 | bfd_putl32 (TPI_FIRST_INDEX + e->index, buf); | |
579 | ||
226f9f4f | 580 | if (bfd_write (buf, sizeof (uint32_t), hash_stream) |
d5b4c0dd MH |
581 | != sizeof (uint32_t)) |
582 | return false; | |
583 | ||
584 | bfd_putl32 (old_off, buf); | |
585 | ||
226f9f4f | 586 | if (bfd_write (buf, sizeof (uint32_t), hash_stream) |
d5b4c0dd MH |
587 | != sizeof (uint32_t)) |
588 | return false; | |
589 | } | |
590 | ||
591 | e = e->next; | |
592 | } | |
593 | ||
b41a6533 MH |
594 | return true; |
595 | } | |
596 | ||
597 | /* Return the PE architecture number for the image. */ | |
598 | static uint16_t | |
599 | get_arch_number (bfd *abfd) | |
600 | { | |
9a02fbd1 MH |
601 | switch (abfd->arch_info->arch) |
602 | { | |
603 | case bfd_arch_i386: | |
604 | if (abfd->arch_info->mach & bfd_mach_x86_64) | |
605 | return IMAGE_FILE_MACHINE_AMD64; | |
606 | else | |
607 | return IMAGE_FILE_MACHINE_I386; | |
b41a6533 | 608 | |
9a02fbd1 MH |
609 | case bfd_arch_aarch64: |
610 | return IMAGE_FILE_MACHINE_ARM64; | |
b41a6533 | 611 | |
9a02fbd1 MH |
612 | default: |
613 | return 0; | |
614 | } | |
b41a6533 MH |
615 | } |
616 | ||
803561cb MH |
617 | /* Validate the DEBUG_S_FILECHKSMS entry within a module's .debug$S |
618 | section, and copy it to the module's symbol stream. */ | |
619 | static bool | |
620 | copy_filechksms (uint8_t *data, uint32_t size, char *string_table, | |
621 | struct string_table *strings, uint8_t *out, | |
622 | struct mod_source_files *mod_source) | |
623 | { | |
624 | uint8_t *orig_data = data; | |
625 | uint32_t orig_size = size; | |
626 | uint16_t num_files = 0; | |
627 | struct string **strptr; | |
628 | ||
629 | bfd_putl32 (DEBUG_S_FILECHKSMS, out); | |
630 | out += sizeof (uint32_t); | |
631 | ||
632 | bfd_putl32 (size, out); | |
633 | out += sizeof (uint32_t); | |
634 | ||
635 | /* Calculate the number of files, and check for any overflows. */ | |
636 | ||
637 | while (size > 0) | |
638 | { | |
639 | struct file_checksum *fc = (struct file_checksum *) data; | |
640 | uint8_t padding; | |
641 | size_t len; | |
642 | ||
643 | if (size < sizeof (struct file_checksum)) | |
644 | { | |
645 | bfd_set_error (bfd_error_bad_value); | |
646 | return false; | |
647 | } | |
648 | ||
649 | len = sizeof (struct file_checksum) + fc->checksum_length; | |
650 | ||
651 | if (size < len) | |
652 | { | |
653 | bfd_set_error (bfd_error_bad_value); | |
654 | return false; | |
655 | } | |
656 | ||
657 | data += len; | |
658 | size -= len; | |
659 | ||
660 | if (len % sizeof (uint32_t)) | |
661 | padding = sizeof (uint32_t) - (len % sizeof (uint32_t)); | |
662 | else | |
663 | padding = 0; | |
664 | ||
665 | if (size < padding) | |
666 | { | |
667 | bfd_set_error (bfd_error_bad_value); | |
668 | return false; | |
669 | } | |
670 | ||
671 | num_files++; | |
672 | ||
673 | data += padding; | |
674 | size -= padding; | |
675 | } | |
676 | ||
677 | /* Add the files to mod_source, so that they'll appear in the source | |
678 | info substream. */ | |
679 | ||
680 | strptr = NULL; | |
681 | if (num_files > 0) | |
682 | { | |
683 | uint16_t new_count = num_files + mod_source->files_count; | |
684 | ||
685 | mod_source->files = xrealloc (mod_source->files, | |
686 | sizeof (struct string *) * new_count); | |
687 | ||
688 | strptr = mod_source->files + mod_source->files_count; | |
689 | ||
690 | mod_source->files_count += num_files; | |
691 | } | |
692 | ||
693 | /* Actually copy the data. */ | |
694 | ||
695 | data = orig_data; | |
696 | size = orig_size; | |
697 | ||
698 | while (size > 0) | |
699 | { | |
700 | struct file_checksum *fc = (struct file_checksum *) data; | |
701 | uint32_t string_off; | |
702 | uint8_t padding; | |
703 | size_t len; | |
704 | struct string *str = NULL; | |
705 | ||
706 | string_off = bfd_getl32 (&fc->file_id); | |
707 | len = sizeof (struct file_checksum) + fc->checksum_length; | |
708 | ||
709 | if (len % sizeof (uint32_t)) | |
710 | padding = sizeof (uint32_t) - (len % sizeof (uint32_t)); | |
711 | else | |
712 | padding = 0; | |
713 | ||
714 | /* Remap the "file ID", i.e. the offset in the module's string table, | |
715 | so it points to the right place in the main string table. */ | |
716 | ||
717 | if (string_table) | |
718 | { | |
719 | char *fn = string_table + string_off; | |
720 | size_t fn_len = strlen (fn); | |
721 | uint32_t hash = calc_hash (fn, fn_len); | |
722 | void **slot; | |
723 | ||
724 | slot = htab_find_slot_with_hash (strings->hashmap, fn, hash, | |
725 | NO_INSERT); | |
726 | ||
727 | if (slot) | |
728 | str = (struct string *) *slot; | |
729 | } | |
730 | ||
731 | *strptr = str; | |
732 | strptr++; | |
733 | ||
734 | bfd_putl32 (str ? str->offset : 0, &fc->file_id); | |
735 | ||
736 | memcpy (out, data, len + padding); | |
737 | ||
738 | data += len + padding; | |
739 | size -= len + padding; | |
740 | out += len + padding; | |
741 | } | |
742 | ||
743 | return true; | |
744 | } | |
745 | ||
81784004 MH |
746 | /* Add a string to the strings table, if it's not already there. Returns its |
747 | offset within the string table. */ | |
748 | static uint32_t | |
f559276d MH |
749 | add_string (char *str, size_t len, struct string_table *strings) |
750 | { | |
751 | uint32_t hash = calc_hash (str, len); | |
81784004 | 752 | struct string *s; |
f559276d MH |
753 | void **slot; |
754 | ||
755 | slot = htab_find_slot_with_hash (strings->hashmap, str, hash, INSERT); | |
756 | ||
757 | if (!*slot) | |
758 | { | |
f559276d MH |
759 | *slot = xmalloc (offsetof (struct string, s) + len); |
760 | ||
761 | s = (struct string *) *slot; | |
762 | ||
763 | s->next = NULL; | |
764 | s->hash = hash; | |
765 | s->offset = strings->strings_len; | |
803561cb | 766 | s->source_file_offset = 0xffffffff; |
f559276d MH |
767 | s->len = len; |
768 | memcpy (s->s, str, len); | |
769 | ||
770 | if (strings->strings_tail) | |
771 | strings->strings_tail->next = s; | |
772 | else | |
773 | strings->strings_head = s; | |
774 | ||
775 | strings->strings_tail = s; | |
776 | ||
777 | strings->strings_len += len + 1; | |
778 | } | |
81784004 MH |
779 | else |
780 | { | |
781 | s = (struct string *) *slot; | |
782 | } | |
783 | ||
784 | return s->offset; | |
f559276d MH |
785 | } |
786 | ||
787 | /* Return the hash of an entry in the string table. */ | |
788 | static hashval_t | |
789 | hash_string_table_entry (const void *p) | |
790 | { | |
791 | const struct string *s = (const struct string *) p; | |
792 | ||
81814b6f MH |
793 | return s->hash; |
794 | } | |
795 | ||
796 | /* Compare an entry in the string table with a string. */ | |
797 | static int | |
798 | eq_string_table_entry (const void *a, const void *b) | |
799 | { | |
800 | const struct string *s1 = (const struct string *) a; | |
801 | const char *s2 = (const char *) b; | |
802 | size_t s2_len = strlen (s2); | |
803 | ||
804 | if (s2_len != s1->len) | |
805 | return 0; | |
806 | ||
807 | return memcmp (s1->s, s2, s2_len) == 0; | |
808 | } | |
809 | ||
810 | /* Parse the string table within the .debug$S section. */ | |
811 | static void | |
812 | parse_string_table (bfd_byte *data, size_t size, | |
813 | struct string_table *strings) | |
814 | { | |
815 | while (true) | |
816 | { | |
817 | size_t len = strnlen ((char *) data, size); | |
818 | ||
819 | add_string ((char *) data, len, strings); | |
820 | ||
821 | data += len + 1; | |
822 | ||
823 | if (size <= len + 1) | |
824 | break; | |
825 | ||
826 | size -= len + 1; | |
827 | } | |
828 | } | |
829 | ||
830 | /* Remap a type reference within a CodeView symbol. */ | |
831 | static bool | |
832 | remap_symbol_type (void *data, struct type_entry **map, uint32_t num_types) | |
833 | { | |
834 | uint32_t type = bfd_getl32 (data); | |
835 | ||
836 | /* Ignore builtin types (those with IDs below 0x1000). */ | |
837 | if (type < TPI_FIRST_INDEX) | |
838 | return true; | |
839 | ||
840 | if (type >= TPI_FIRST_INDEX + num_types) | |
841 | { | |
842 | einfo (_("%P: CodeView symbol references out of range type %v\n"), | |
843 | type); | |
844 | return false; | |
845 | } | |
846 | ||
847 | type = TPI_FIRST_INDEX + map[type - TPI_FIRST_INDEX]->index; | |
848 | bfd_putl32 (type, data); | |
849 | ||
850 | return true; | |
851 | } | |
852 | ||
853 | /* Add an entry into the globals stream. If it already exists, increase | |
854 | the refcount. */ | |
855 | static bool | |
856 | add_globals_ref (struct globals *glob, bfd *sym_rec_stream, const char *name, | |
857 | size_t name_len, uint8_t *data, size_t len) | |
858 | { | |
859 | void **slot; | |
860 | uint32_t hash; | |
861 | struct global *g; | |
862 | ||
863 | slot = htab_find_slot_with_hash (glob->hashmap, data, | |
864 | iterative_hash (data, len, 0), INSERT); | |
865 | ||
866 | if (*slot) | |
867 | { | |
868 | g = *slot; | |
869 | g->refcount++; | |
870 | return true; | |
871 | } | |
872 | ||
873 | *slot = xmalloc (offsetof (struct global, data) + len); | |
874 | ||
875 | hash = crc32 ((const uint8_t *) name, name_len); | |
876 | hash %= NUM_GLOBALS_HASH_BUCKETS; | |
877 | ||
878 | g = *slot; | |
879 | g->next = NULL; | |
880 | g->offset = bfd_tell (sym_rec_stream); | |
881 | g->hash = hash; | |
882 | g->refcount = 1; | |
eb70d820 | 883 | memcpy (g->data, data, len); |
81814b6f MH |
884 | |
885 | glob->num_entries++; | |
886 | ||
887 | if (glob->last) | |
888 | glob->last->next = g; | |
889 | else | |
890 | glob->first = g; | |
891 | ||
892 | glob->last = g; | |
893 | ||
226f9f4f | 894 | return bfd_write (data, len, sym_rec_stream) == len; |
81814b6f MH |
895 | } |
896 | ||
897 | /* Find the end of the current scope within symbols data. */ | |
898 | static uint8_t * | |
899 | find_end_of_scope (uint8_t *data, uint32_t size) | |
900 | { | |
901 | unsigned int scope_level = 1; | |
902 | uint16_t len; | |
903 | ||
904 | len = bfd_getl16 (data) + sizeof (uint16_t); | |
905 | ||
906 | data += len; | |
907 | size -= len; | |
908 | ||
909 | while (true) | |
910 | { | |
911 | uint16_t type; | |
912 | ||
913 | if (size < sizeof (uint32_t)) | |
914 | return NULL; | |
915 | ||
916 | len = bfd_getl16 (data) + sizeof (uint16_t); | |
917 | type = bfd_getl16 (data + sizeof (uint16_t)); | |
918 | ||
919 | if (size < len) | |
920 | return NULL; | |
921 | ||
922 | switch (type) | |
923 | { | |
924 | case S_GPROC32: | |
925 | case S_LPROC32: | |
5d9c0336 MH |
926 | case S_BLOCK32: |
927 | case S_INLINESITE: | |
928 | case S_THUNK32: | |
81814b6f MH |
929 | scope_level++; |
930 | break; | |
931 | ||
932 | case S_END: | |
933 | case S_PROC_ID_END: | |
5d9c0336 | 934 | case S_INLINESITE_END: |
81814b6f MH |
935 | scope_level--; |
936 | ||
937 | if (scope_level == 0) | |
938 | return data; | |
939 | ||
940 | break; | |
941 | } | |
942 | ||
943 | data += len; | |
944 | size -= len; | |
945 | } | |
946 | } | |
947 | ||
948 | /* Return the size of an extended value parameter, as used in | |
949 | LF_ENUMERATE etc. */ | |
950 | static unsigned int | |
951 | extended_value_len (uint16_t type) | |
952 | { | |
953 | switch (type) | |
954 | { | |
955 | case LF_CHAR: | |
956 | return 1; | |
957 | ||
958 | case LF_SHORT: | |
959 | case LF_USHORT: | |
960 | return 2; | |
961 | ||
962 | case LF_LONG: | |
963 | case LF_ULONG: | |
964 | return 4; | |
965 | ||
966 | case LF_QUADWORD: | |
967 | case LF_UQUADWORD: | |
968 | return 8; | |
969 | } | |
970 | ||
971 | return 0; | |
972 | } | |
973 | ||
974 | /* Parse the symbols in a .debug$S section, and copy them to the module's | |
975 | symbol stream. */ | |
976 | static bool | |
977 | parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf, | |
978 | struct type_entry **map, uint32_t num_types, | |
979 | bfd *sym_rec_stream, struct globals *glob, uint16_t mod_num) | |
980 | { | |
981 | uint8_t *orig_buf = *buf; | |
982 | unsigned int scope_level = 0; | |
5d9c0336 | 983 | uint8_t *scope = NULL; |
81814b6f MH |
984 | |
985 | while (size >= sizeof (uint16_t)) | |
986 | { | |
987 | uint16_t len, type; | |
988 | ||
989 | len = bfd_getl16 (data) + sizeof (uint16_t); | |
990 | ||
991 | if (len > size) | |
992 | { | |
993 | bfd_set_error (bfd_error_bad_value); | |
994 | return false; | |
995 | } | |
996 | ||
997 | type = bfd_getl16 (data + sizeof (uint16_t)); | |
998 | ||
999 | switch (type) | |
1000 | { | |
1001 | case S_LDATA32: | |
1002 | case S_GDATA32: | |
1003 | case S_LTHREAD32: | |
1004 | case S_GTHREAD32: | |
1005 | { | |
1006 | struct datasym *d = (struct datasym *) data; | |
1007 | size_t name_len; | |
1008 | ||
1009 | if (len < offsetof (struct datasym, name)) | |
1010 | { | |
1011 | einfo (_("%P: warning: truncated CodeView record" | |
1012 | " S_LDATA32/S_GDATA32/S_LTHREAD32/S_GTHREAD32\n")); | |
1013 | bfd_set_error (bfd_error_bad_value); | |
1014 | return false; | |
1015 | } | |
1016 | ||
1017 | if (scope_level == 0) | |
1018 | { | |
1019 | uint16_t section = bfd_getl16 (&d->section); | |
1020 | ||
1021 | if (section == 0) /* GC'd, ignore */ | |
1022 | break; | |
1023 | } | |
1024 | ||
1025 | name_len = | |
1026 | strnlen (d->name, len - offsetof (struct datasym, name)); | |
1027 | ||
1028 | if (name_len == len - offsetof (struct datasym, name)) | |
1029 | { | |
1030 | einfo (_("%P: warning: name for S_LDATA32/S_GDATA32/" | |
1031 | "S_LTHREAD32/S_GTHREAD32 has no terminating" | |
1032 | " zero\n")); | |
1033 | bfd_set_error (bfd_error_bad_value); | |
1034 | return false; | |
1035 | } | |
1036 | ||
1037 | if (!remap_symbol_type (&d->type, map, num_types)) | |
1038 | { | |
1039 | bfd_set_error (bfd_error_bad_value); | |
1040 | return false; | |
1041 | } | |
1042 | ||
1043 | /* If S_LDATA32 or S_LTHREAD32, copy into module symbols. */ | |
1044 | ||
1045 | if (type == S_LDATA32 || type == S_LTHREAD32) | |
1046 | { | |
1047 | memcpy (*buf, d, len); | |
1048 | *buf += len; | |
1049 | } | |
1050 | ||
1051 | /* S_LDATA32 and S_LTHREAD32 only go in globals if | |
1052 | not in function scope. */ | |
1053 | if (type == S_GDATA32 || type == S_GTHREAD32 || scope_level == 0) | |
1054 | { | |
1055 | if (!add_globals_ref (glob, sym_rec_stream, d->name, | |
1056 | name_len, data, len)) | |
1057 | return false; | |
1058 | } | |
1059 | ||
1060 | break; | |
1061 | } | |
1062 | ||
1063 | case S_GPROC32: | |
1064 | case S_LPROC32: | |
1065 | case S_GPROC32_ID: | |
1066 | case S_LPROC32_ID: | |
1067 | { | |
1068 | struct procsym *proc = (struct procsym *) data; | |
1069 | size_t name_len; | |
1070 | uint16_t section; | |
1071 | uint32_t end; | |
1072 | uint8_t *endptr; | |
1073 | size_t ref_size, padding; | |
1074 | struct refsym *ref; | |
1075 | ||
1076 | if (len < offsetof (struct procsym, name)) | |
1077 | { | |
1078 | einfo (_("%P: warning: truncated CodeView record" | |
1079 | " S_GPROC32/S_LPROC32\n")); | |
1080 | bfd_set_error (bfd_error_bad_value); | |
1081 | return false; | |
1082 | } | |
1083 | ||
1084 | section = bfd_getl16 (&proc->section); | |
1085 | ||
1086 | endptr = find_end_of_scope (data, size); | |
1087 | ||
1088 | if (!endptr) | |
1089 | { | |
1090 | einfo (_("%P: warning: could not find end of" | |
1091 | " S_GPROC32/S_LPROC32 record\n")); | |
1092 | bfd_set_error (bfd_error_bad_value); | |
1093 | return false; | |
1094 | } | |
1095 | ||
1096 | if (section == 0) /* skip if GC'd */ | |
1097 | { | |
1098 | /* Skip to after S_END. */ | |
1099 | ||
1100 | size -= endptr - data; | |
1101 | data = endptr; | |
1102 | ||
1103 | len = bfd_getl16 (data) + sizeof (uint16_t); | |
1104 | ||
1105 | data += len; | |
1106 | size -= len; | |
1107 | ||
1108 | continue; | |
1109 | } | |
1110 | ||
1111 | name_len = | |
1112 | strnlen (proc->name, len - offsetof (struct procsym, name)); | |
1113 | ||
1114 | if (name_len == len - offsetof (struct procsym, name)) | |
1115 | { | |
1116 | einfo (_("%P: warning: name for S_GPROC32/S_LPROC32 has no" | |
1117 | " terminating zero\n")); | |
1118 | bfd_set_error (bfd_error_bad_value); | |
1119 | return false; | |
1120 | } | |
1121 | ||
1122 | if (type == S_GPROC32_ID || type == S_LPROC32_ID) | |
1123 | { | |
1124 | /* Transform into S_GPROC32 / S_LPROC32. */ | |
1125 | ||
1126 | uint32_t t_idx = bfd_getl32 (&proc->type); | |
1127 | struct type_entry *t; | |
1128 | uint16_t t_type; | |
1129 | ||
1130 | if (t_idx < TPI_FIRST_INDEX | |
1131 | || t_idx >= TPI_FIRST_INDEX + num_types) | |
1132 | { | |
1133 | einfo (_("%P: CodeView symbol references out of range" | |
1134 | " type %v\n"), type); | |
1135 | bfd_set_error (bfd_error_bad_value); | |
1136 | return false; | |
1137 | } | |
1138 | ||
1139 | t = map[t_idx - TPI_FIRST_INDEX]; | |
1140 | ||
1141 | t_type = bfd_getl16 (t->data + sizeof (uint16_t)); | |
1142 | ||
1143 | switch (t_type) | |
1144 | { | |
1145 | case LF_FUNC_ID: | |
1146 | { | |
1147 | struct lf_func_id *t_data = | |
1148 | (struct lf_func_id *) t->data; | |
1149 | ||
1150 | /* Replace proc->type with function type. */ | |
1151 | ||
1152 | memcpy (&proc->type, &t_data->function_type, | |
1153 | sizeof (uint32_t)); | |
1154 | ||
1155 | break; | |
1156 | } | |
1157 | ||
1158 | case LF_MFUNC_ID: | |
1159 | { | |
1160 | struct lf_mfunc_id *t_data = | |
1161 | (struct lf_mfunc_id *) t->data; | |
1162 | ||
1163 | /* Replace proc->type with function type. */ | |
1164 | ||
1165 | memcpy (&proc->type, &t_data->function_type, | |
1166 | sizeof (uint32_t)); | |
1167 | ||
1168 | break; | |
1169 | } | |
1170 | ||
1171 | default: | |
1172 | einfo (_("%P: CodeView S_GPROC32_ID/S_LPROC32_ID symbol" | |
1173 | " referenced unknown type as ID\n")); | |
1174 | bfd_set_error (bfd_error_bad_value); | |
1175 | return false; | |
1176 | } | |
1177 | ||
1178 | /* Change record type. */ | |
1179 | ||
1180 | if (type == S_GPROC32_ID) | |
1181 | bfd_putl32 (S_GPROC32, &proc->kind); | |
1182 | else | |
1183 | bfd_putl32 (S_LPROC32, &proc->kind); | |
1184 | } | |
1185 | else | |
1186 | { | |
1187 | if (!remap_symbol_type (&proc->type, map, num_types)) | |
1188 | { | |
1189 | bfd_set_error (bfd_error_bad_value); | |
1190 | return false; | |
1191 | } | |
1192 | } | |
1193 | ||
1194 | end = *buf - orig_buf + sizeof (uint32_t) + endptr - data; | |
1195 | bfd_putl32 (end, &proc->end); | |
1196 | ||
1197 | /* Add S_PROCREF / S_LPROCREF to globals stream. */ | |
1198 | ||
1199 | ref_size = offsetof (struct refsym, name) + name_len + 1; | |
1200 | ||
1201 | if (ref_size % sizeof (uint32_t)) | |
1202 | padding = sizeof (uint32_t) - (ref_size % sizeof (uint32_t)); | |
1203 | else | |
1204 | padding = 0; | |
1205 | ||
1206 | ref = xmalloc (ref_size + padding); | |
1207 | ||
1208 | bfd_putl16 (ref_size + padding - sizeof (uint16_t), &ref->size); | |
1209 | bfd_putl16 (type == S_GPROC32 || type == S_GPROC32_ID ? | |
1210 | S_PROCREF : S_LPROCREF, &ref->kind); | |
1211 | bfd_putl32 (0, &ref->sum_name); | |
1212 | bfd_putl32 (*buf - orig_buf + sizeof (uint32_t), | |
1213 | &ref->symbol_offset); | |
1214 | bfd_putl16 (mod_num + 1, &ref->mod); | |
1215 | ||
1216 | memcpy (ref->name, proc->name, name_len + 1); | |
1217 | ||
1218 | memset (ref->name + name_len + 1, 0, padding); | |
1219 | ||
1220 | if (!add_globals_ref (glob, sym_rec_stream, proc->name, name_len, | |
1221 | (uint8_t *) ref, ref_size + padding)) | |
1222 | { | |
1223 | free (ref); | |
1224 | return false; | |
1225 | } | |
1226 | ||
1227 | free (ref); | |
1228 | ||
5d9c0336 MH |
1229 | scope = *buf; |
1230 | ||
81814b6f MH |
1231 | memcpy (*buf, proc, len); |
1232 | *buf += len; | |
1233 | ||
1234 | scope_level++; | |
1235 | ||
1236 | break; | |
1237 | } | |
1238 | ||
1239 | case S_UDT: | |
1240 | { | |
1241 | struct udtsym *udt = (struct udtsym *) data; | |
1242 | size_t name_len; | |
1243 | ||
1244 | if (len < offsetof (struct udtsym, name)) | |
1245 | { | |
1246 | einfo (_("%P: warning: truncated CodeView record" | |
1247 | " S_UDT\n")); | |
1248 | bfd_set_error (bfd_error_bad_value); | |
1249 | return false; | |
1250 | } | |
1251 | ||
1252 | name_len = | |
1253 | strnlen (udt->name, len - offsetof (struct udtsym, name)); | |
1254 | ||
1255 | if (name_len == len - offsetof (struct udtsym, name)) | |
1256 | { | |
1257 | einfo (_("%P: warning: name for S_UDT has no" | |
1258 | " terminating zero\n")); | |
1259 | bfd_set_error (bfd_error_bad_value); | |
1260 | return false; | |
1261 | } | |
1262 | ||
1263 | if (!remap_symbol_type (&udt->type, map, num_types)) | |
1264 | { | |
1265 | bfd_set_error (bfd_error_bad_value); | |
1266 | return false; | |
1267 | } | |
1268 | ||
1269 | /* S_UDT goes in the symbols stream if within a procedure, | |
1270 | otherwise it goes in the globals stream. */ | |
1271 | if (scope_level == 0) | |
1272 | { | |
1273 | if (!add_globals_ref (glob, sym_rec_stream, udt->name, | |
1274 | name_len, data, len)) | |
1275 | return false; | |
1276 | } | |
1277 | else | |
1278 | { | |
1279 | memcpy (*buf, udt, len); | |
1280 | *buf += len; | |
1281 | } | |
1282 | ||
1283 | break; | |
1284 | } | |
1285 | ||
1286 | case S_CONSTANT: | |
1287 | { | |
1288 | struct constsym *c = (struct constsym *) data; | |
1289 | size_t name_len, rec_size; | |
1290 | uint16_t val; | |
1291 | ||
1292 | if (len < offsetof (struct constsym, name)) | |
1293 | { | |
1294 | einfo (_("%P: warning: truncated CodeView record" | |
1295 | " S_CONSTANT\n")); | |
1296 | bfd_set_error (bfd_error_bad_value); | |
1297 | return false; | |
1298 | } | |
1299 | ||
1300 | rec_size = offsetof (struct constsym, name); | |
1301 | ||
1302 | val = bfd_getl16 (&c->value); | |
1303 | ||
1304 | /* If val >= 0x8000, actual value follows. */ | |
1305 | if (val >= 0x8000) | |
1306 | { | |
1307 | unsigned int param_len = extended_value_len (val); | |
1308 | ||
1309 | if (param_len == 0) | |
1310 | { | |
1311 | einfo (_("%P: warning: unhandled type %v within" | |
1312 | " S_CONSTANT\n"), val); | |
1313 | bfd_set_error (bfd_error_bad_value); | |
1314 | return false; | |
1315 | } | |
1316 | ||
1317 | rec_size += param_len; | |
1318 | } | |
1319 | ||
1320 | name_len = | |
1321 | strnlen ((const char *) data + rec_size, len - rec_size); | |
1322 | ||
1323 | if (name_len == len - rec_size) | |
1324 | { | |
1325 | einfo (_("%P: warning: name for S_CONSTANT has no" | |
1326 | " terminating zero\n")); | |
1327 | bfd_set_error (bfd_error_bad_value); | |
1328 | return false; | |
1329 | } | |
1330 | ||
1331 | if (!remap_symbol_type (&c->type, map, num_types)) | |
1332 | { | |
1333 | bfd_set_error (bfd_error_bad_value); | |
1334 | return false; | |
1335 | } | |
1336 | ||
1337 | if (!add_globals_ref (glob, sym_rec_stream, | |
1338 | (const char *) data + rec_size, name_len, | |
1339 | data, len)) | |
1340 | return false; | |
1341 | ||
1342 | break; | |
1343 | } | |
1344 | ||
1345 | case S_END: | |
5d9c0336 | 1346 | case S_INLINESITE_END: |
81814b6f MH |
1347 | case S_PROC_ID_END: |
1348 | memcpy (*buf, data, len); | |
1349 | ||
1350 | if (type == S_PROC_ID_END) /* transform to S_END */ | |
1351 | bfd_putl16 (S_END, *buf + sizeof (uint16_t)); | |
1352 | ||
5d9c0336 MH |
1353 | /* Reset scope variable back to the address of the previous |
1354 | scope start. */ | |
1355 | if (scope) | |
1356 | { | |
1357 | uint32_t parent; | |
1358 | uint16_t scope_start_type = | |
1359 | bfd_getl16 (scope + sizeof (uint16_t)); | |
1360 | ||
1361 | switch (scope_start_type) | |
1362 | { | |
1363 | case S_GPROC32: | |
1364 | case S_LPROC32: | |
1365 | parent = bfd_getl32 (scope + offsetof (struct procsym, | |
1366 | parent)); | |
1367 | break; | |
1368 | ||
1369 | case S_BLOCK32: | |
1370 | parent = bfd_getl32 (scope + offsetof (struct blocksym, | |
1371 | parent)); | |
1372 | break; | |
1373 | ||
1374 | case S_INLINESITE: | |
1375 | parent = bfd_getl32 (scope + offsetof (struct inline_site, | |
1376 | parent)); | |
1377 | break; | |
1378 | ||
1379 | case S_THUNK32: | |
1380 | parent = bfd_getl32 (scope + offsetof (struct thunk, | |
1381 | parent)); | |
1382 | break; | |
1383 | ||
1384 | default: | |
1385 | einfo (_("%P: warning: unexpected CodeView scope start" | |
1386 | " record %v\n"), scope_start_type); | |
1387 | bfd_set_error (bfd_error_bad_value); | |
1388 | return false; | |
1389 | } | |
1390 | ||
1391 | if (parent == 0) | |
1392 | scope = NULL; | |
1393 | else | |
1394 | scope = orig_buf + parent - sizeof (uint32_t); | |
1395 | } | |
1396 | ||
81814b6f MH |
1397 | *buf += len; |
1398 | scope_level--; | |
1399 | break; | |
1400 | ||
5d9c0336 MH |
1401 | case S_BUILDINFO: |
1402 | { | |
1403 | struct buildinfosym *bi = (struct buildinfosym *) data; | |
1404 | ||
1405 | if (len < sizeof (struct buildinfosym)) | |
1406 | { | |
1407 | einfo (_("%P: warning: truncated CodeView record" | |
1408 | " S_BUILDINFO\n")); | |
1409 | bfd_set_error (bfd_error_bad_value); | |
1410 | return false; | |
1411 | } | |
1412 | ||
1413 | if (!remap_symbol_type (&bi->type, map, num_types)) | |
1414 | { | |
1415 | bfd_set_error (bfd_error_bad_value); | |
1416 | return false; | |
1417 | } | |
1418 | ||
1419 | memcpy (*buf, data, len); | |
1420 | *buf += len; | |
1421 | ||
1422 | break; | |
1423 | } | |
1424 | ||
1425 | case S_BLOCK32: | |
1426 | { | |
1427 | struct blocksym *bl = (struct blocksym *) data; | |
1428 | uint8_t *endptr; | |
1429 | uint32_t end; | |
1430 | ||
1431 | if (len < offsetof (struct blocksym, name)) | |
1432 | { | |
1433 | einfo (_("%P: warning: truncated CodeView record" | |
1434 | " S_BLOCK32\n")); | |
1435 | bfd_set_error (bfd_error_bad_value); | |
1436 | return false; | |
1437 | } | |
1438 | ||
1439 | bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &bl->parent); | |
1440 | ||
1441 | endptr = find_end_of_scope (data, size); | |
1442 | ||
1443 | if (!endptr) | |
1444 | { | |
1445 | einfo (_("%P: warning: could not find end of" | |
1446 | " S_BLOCK32 record\n")); | |
1447 | bfd_set_error (bfd_error_bad_value); | |
1448 | return false; | |
1449 | } | |
1450 | ||
1451 | end = *buf - orig_buf + sizeof (uint32_t) + endptr - data; | |
1452 | bfd_putl32 (end, &bl->end); | |
1453 | ||
1454 | scope = *buf; | |
1455 | ||
1456 | memcpy (*buf, data, len); | |
1457 | *buf += len; | |
1458 | ||
1459 | scope_level++; | |
1460 | ||
1461 | break; | |
1462 | } | |
1463 | ||
1464 | case S_BPREL32: | |
1465 | { | |
1466 | struct bprelsym *bp = (struct bprelsym *) data; | |
1467 | ||
1468 | if (len < offsetof (struct bprelsym, name)) | |
1469 | { | |
1470 | einfo (_("%P: warning: truncated CodeView record" | |
1471 | " S_BPREL32\n")); | |
1472 | bfd_set_error (bfd_error_bad_value); | |
1473 | return false; | |
1474 | } | |
1475 | ||
1476 | if (!remap_symbol_type (&bp->type, map, num_types)) | |
1477 | { | |
1478 | bfd_set_error (bfd_error_bad_value); | |
1479 | return false; | |
1480 | } | |
1481 | ||
1482 | memcpy (*buf, data, len); | |
1483 | *buf += len; | |
1484 | ||
1485 | break; | |
1486 | } | |
1487 | ||
1488 | case S_REGISTER: | |
1489 | { | |
1490 | struct regsym *reg = (struct regsym *) data; | |
1491 | ||
1492 | if (len < offsetof (struct regsym, name)) | |
1493 | { | |
1494 | einfo (_("%P: warning: truncated CodeView record" | |
1495 | " S_REGISTER\n")); | |
1496 | bfd_set_error (bfd_error_bad_value); | |
1497 | return false; | |
1498 | } | |
1499 | ||
1500 | if (!remap_symbol_type (®->type, map, num_types)) | |
1501 | { | |
1502 | bfd_set_error (bfd_error_bad_value); | |
1503 | return false; | |
1504 | } | |
1505 | ||
1506 | memcpy (*buf, data, len); | |
1507 | *buf += len; | |
1508 | ||
1509 | break; | |
1510 | } | |
1511 | ||
1512 | case S_REGREL32: | |
1513 | { | |
1514 | struct regrel *rr = (struct regrel *) data; | |
1515 | ||
1516 | if (len < offsetof (struct regrel, name)) | |
1517 | { | |
1518 | einfo (_("%P: warning: truncated CodeView record" | |
1519 | " S_REGREL32\n")); | |
1520 | bfd_set_error (bfd_error_bad_value); | |
1521 | return false; | |
1522 | } | |
1523 | ||
1524 | if (!remap_symbol_type (&rr->type, map, num_types)) | |
1525 | { | |
1526 | bfd_set_error (bfd_error_bad_value); | |
1527 | return false; | |
1528 | } | |
1529 | ||
1530 | memcpy (*buf, data, len); | |
1531 | *buf += len; | |
1532 | ||
1533 | break; | |
1534 | } | |
1535 | ||
1536 | case S_LOCAL: | |
1537 | { | |
1538 | struct localsym *l = (struct localsym *) data; | |
1539 | ||
1540 | if (len < offsetof (struct localsym, name)) | |
1541 | { | |
1542 | einfo (_("%P: warning: truncated CodeView record" | |
1543 | " S_LOCAL\n")); | |
1544 | bfd_set_error (bfd_error_bad_value); | |
1545 | return false; | |
1546 | } | |
1547 | ||
1548 | if (!remap_symbol_type (&l->type, map, num_types)) | |
1549 | { | |
1550 | bfd_set_error (bfd_error_bad_value); | |
1551 | return false; | |
1552 | } | |
1553 | ||
1554 | memcpy (*buf, data, len); | |
1555 | *buf += len; | |
1556 | ||
1557 | break; | |
1558 | } | |
1559 | ||
1560 | case S_INLINESITE: | |
1561 | { | |
1562 | struct inline_site *is = (struct inline_site *) data; | |
1563 | uint8_t *endptr; | |
1564 | uint32_t end; | |
1565 | ||
1566 | if (len < offsetof (struct inline_site, binary_annotations)) | |
1567 | { | |
1568 | einfo (_("%P: warning: truncated CodeView record" | |
1569 | " S_INLINESITE\n")); | |
1570 | bfd_set_error (bfd_error_bad_value); | |
1571 | return false; | |
1572 | } | |
1573 | ||
1574 | bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &is->parent); | |
1575 | ||
1576 | endptr = find_end_of_scope (data, size); | |
1577 | ||
1578 | if (!endptr) | |
1579 | { | |
1580 | einfo (_("%P: warning: could not find end of" | |
1581 | " S_INLINESITE record\n")); | |
1582 | bfd_set_error (bfd_error_bad_value); | |
1583 | return false; | |
1584 | } | |
1585 | ||
1586 | end = *buf - orig_buf + sizeof (uint32_t) + endptr - data; | |
1587 | bfd_putl32 (end, &is->end); | |
1588 | ||
1589 | if (!remap_symbol_type (&is->inlinee, map, num_types)) | |
1590 | { | |
1591 | bfd_set_error (bfd_error_bad_value); | |
1592 | return false; | |
1593 | } | |
1594 | ||
1595 | scope = *buf; | |
1596 | ||
1597 | memcpy (*buf, data, len); | |
1598 | *buf += len; | |
1599 | ||
1600 | scope_level++; | |
1601 | ||
1602 | break; | |
1603 | } | |
1604 | ||
1605 | case S_THUNK32: | |
1606 | { | |
1607 | struct thunk *th = (struct thunk *) data; | |
1608 | uint8_t *endptr; | |
1609 | uint32_t end; | |
1610 | ||
1611 | if (len < offsetof (struct thunk, name)) | |
1612 | { | |
1613 | einfo (_("%P: warning: truncated CodeView record" | |
1614 | " S_THUNK32\n")); | |
1615 | bfd_set_error (bfd_error_bad_value); | |
1616 | return false; | |
1617 | } | |
1618 | ||
1619 | bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &th->parent); | |
1620 | ||
1621 | endptr = find_end_of_scope (data, size); | |
1622 | ||
1623 | if (!endptr) | |
1624 | { | |
1625 | einfo (_("%P: warning: could not find end of" | |
1626 | " S_THUNK32 record\n")); | |
1627 | bfd_set_error (bfd_error_bad_value); | |
1628 | return false; | |
1629 | } | |
1630 | ||
1631 | end = *buf - orig_buf + sizeof (uint32_t) + endptr - data; | |
1632 | bfd_putl32 (end, &th->end); | |
1633 | ||
1634 | scope = *buf; | |
1635 | ||
1636 | memcpy (*buf, data, len); | |
1637 | *buf += len; | |
1638 | ||
1639 | scope_level++; | |
1640 | ||
1641 | break; | |
1642 | } | |
1643 | ||
1644 | case S_HEAPALLOCSITE: | |
1645 | { | |
1646 | struct heap_alloc_site *has = (struct heap_alloc_site *) data; | |
1647 | ||
1648 | if (len < sizeof (struct heap_alloc_site)) | |
1649 | { | |
1650 | einfo (_("%P: warning: truncated CodeView record" | |
1651 | " S_HEAPALLOCSITE\n")); | |
1652 | bfd_set_error (bfd_error_bad_value); | |
1653 | return false; | |
1654 | } | |
1655 | ||
1656 | if (!remap_symbol_type (&has->type, map, num_types)) | |
1657 | { | |
1658 | bfd_set_error (bfd_error_bad_value); | |
1659 | return false; | |
1660 | } | |
1661 | ||
1662 | memcpy (*buf, data, len); | |
1663 | *buf += len; | |
1664 | ||
1665 | break; | |
1666 | } | |
1667 | ||
1668 | case S_OBJNAME: /* just copy */ | |
1669 | case S_COMPILE3: | |
1670 | case S_UNAMESPACE: | |
1671 | case S_FRAMEPROC: | |
1672 | case S_FRAMECOOKIE: | |
1673 | case S_LABEL32: | |
1674 | case S_DEFRANGE_REGISTER_REL: | |
1675 | case S_DEFRANGE_FRAMEPOINTER_REL: | |
1676 | case S_DEFRANGE_SUBFIELD_REGISTER: | |
1677 | case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: | |
1678 | case S_DEFRANGE_REGISTER: | |
1679 | memcpy (*buf, data, len); | |
1680 | *buf += len; | |
1681 | break; | |
1682 | ||
81814b6f MH |
1683 | default: |
1684 | einfo (_("%P: warning: unrecognized CodeView record %v\n"), type); | |
1685 | bfd_set_error (bfd_error_bad_value); | |
1686 | return false; | |
1687 | } | |
1688 | ||
1689 | data += len; | |
1690 | size -= len; | |
1691 | } | |
1692 | ||
1693 | return true; | |
1694 | } | |
1695 | ||
1696 | /* For a given symbol subsection, work out how much space to allocate in the | |
1697 | result module stream. This is different because we don't copy certain | |
1698 | symbols, such as S_CONSTANT, and we skip over any procedures or data that | |
1699 | have been GC'd out. */ | |
1700 | static bool | |
1701 | calculate_symbols_size (uint8_t *data, uint32_t size, uint32_t *sym_size) | |
1702 | { | |
1703 | unsigned int scope_level = 0; | |
1704 | ||
1705 | while (size >= sizeof (uint32_t)) | |
1706 | { | |
1707 | uint16_t len = bfd_getl16 (data) + sizeof (uint16_t); | |
1708 | uint16_t type = bfd_getl16 (data + sizeof (uint16_t)); | |
1709 | ||
1710 | switch (type) | |
1711 | { | |
1712 | case S_LDATA32: | |
1713 | case S_LTHREAD32: | |
1714 | { | |
1715 | struct datasym *d = (struct datasym *) data; | |
1716 | uint16_t section; | |
1717 | ||
1718 | if (len < offsetof (struct datasym, name)) | |
1719 | { | |
1720 | einfo (_("%P: warning: truncated CodeView record" | |
1721 | " S_LDATA32/S_LTHREAD32\n")); | |
1722 | return false; | |
1723 | } | |
1724 | ||
1725 | section = bfd_getl16 (&d->section); | |
1726 | ||
1727 | /* copy if not GC'd or within function */ | |
1728 | if (scope_level != 0 || section != 0) | |
1729 | *sym_size += len; | |
1730 | } | |
1731 | ||
1732 | case S_GDATA32: | |
1733 | case S_GTHREAD32: | |
1734 | case S_CONSTANT: | |
1735 | /* Not copied into symbols stream. */ | |
1736 | break; | |
1737 | ||
1738 | case S_GPROC32: | |
1739 | case S_LPROC32: | |
1740 | case S_GPROC32_ID: | |
1741 | case S_LPROC32_ID: | |
1742 | { | |
1743 | struct procsym *proc = (struct procsym *) data; | |
1744 | uint16_t section; | |
1745 | ||
1746 | if (len < offsetof (struct procsym, name)) | |
1747 | { | |
1748 | einfo (_("%P: warning: truncated CodeView record" | |
1749 | " S_GPROC32/S_LPROC32\n")); | |
1750 | return false; | |
1751 | } | |
1752 | ||
1753 | section = bfd_getl16 (&proc->section); | |
f559276d | 1754 | |
81814b6f MH |
1755 | if (section != 0) |
1756 | { | |
1757 | *sym_size += len; | |
1758 | } | |
1759 | else | |
1760 | { | |
1761 | uint8_t *endptr = find_end_of_scope (data, size); | |
f559276d | 1762 | |
81814b6f MH |
1763 | if (!endptr) |
1764 | { | |
1765 | einfo (_("%P: warning: could not find end of" | |
1766 | " S_GPROC32/S_LPROC32 record\n")); | |
1767 | return false; | |
1768 | } | |
f559276d | 1769 | |
81814b6f | 1770 | /* Skip to after S_END. */ |
f559276d | 1771 | |
81814b6f MH |
1772 | size -= endptr - data; |
1773 | data = endptr; | |
f559276d | 1774 | |
81814b6f | 1775 | len = bfd_getl16 (data) + sizeof (uint16_t); |
f559276d | 1776 | |
81814b6f MH |
1777 | data += len; |
1778 | size -= len; | |
f559276d | 1779 | |
81814b6f MH |
1780 | continue; |
1781 | } | |
f559276d | 1782 | |
81814b6f | 1783 | scope_level++; |
f559276d | 1784 | |
81814b6f MH |
1785 | break; |
1786 | } | |
d5b4c0dd | 1787 | |
81814b6f MH |
1788 | case S_UDT: |
1789 | if (scope_level != 0) /* only goes in symbols if local */ | |
1790 | *sym_size += len; | |
1791 | break; | |
d5b4c0dd | 1792 | |
5d9c0336 MH |
1793 | case S_BLOCK32: /* always copied */ |
1794 | case S_INLINESITE: | |
1795 | case S_THUNK32: | |
1796 | *sym_size += len; | |
1797 | scope_level++; | |
1798 | break; | |
1799 | ||
81814b6f MH |
1800 | case S_END: /* always copied */ |
1801 | case S_PROC_ID_END: | |
5d9c0336 | 1802 | case S_INLINESITE_END: |
81814b6f MH |
1803 | *sym_size += len; |
1804 | scope_level--; | |
1805 | break; | |
d5b4c0dd | 1806 | |
5d9c0336 MH |
1807 | case S_OBJNAME: /* always copied */ |
1808 | case S_COMPILE3: | |
1809 | case S_UNAMESPACE: | |
1810 | case S_FRAMEPROC: | |
1811 | case S_FRAMECOOKIE: | |
1812 | case S_LABEL32: | |
1813 | case S_BUILDINFO: | |
1814 | case S_BPREL32: | |
1815 | case S_REGISTER: | |
1816 | case S_REGREL32: | |
1817 | case S_LOCAL: | |
1818 | case S_DEFRANGE_REGISTER_REL: | |
1819 | case S_DEFRANGE_FRAMEPOINTER_REL: | |
1820 | case S_DEFRANGE_SUBFIELD_REGISTER: | |
1821 | case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: | |
1822 | case S_DEFRANGE_REGISTER: | |
1823 | case S_HEAPALLOCSITE: | |
1824 | *sym_size += len; | |
1825 | break; | |
1826 | ||
81814b6f MH |
1827 | default: |
1828 | einfo (_("%P: warning: unrecognized CodeView record %v\n"), type); | |
1829 | return false; | |
1830 | } | |
1831 | ||
1832 | data += len; | |
1833 | size -= len; | |
d5b4c0dd MH |
1834 | } |
1835 | ||
81814b6f | 1836 | return true; |
d5b4c0dd MH |
1837 | } |
1838 | ||
f559276d MH |
1839 | /* Parse the .debug$S section within an object file. */ |
1840 | static bool | |
803561cb MH |
1841 | handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, |
1842 | uint8_t **dataptr, uint32_t *sizeptr, | |
598c1ae6 | 1843 | struct mod_source_files *mod_source, |
81814b6f MH |
1844 | bfd *abfd, uint8_t **syms, uint32_t *sym_byte_size, |
1845 | struct type_entry **map, uint32_t num_types, | |
1846 | bfd *sym_rec_stream, struct globals *glob, | |
1847 | uint16_t mod_num) | |
f559276d MH |
1848 | { |
1849 | bfd_byte *data = NULL; | |
1850 | size_t off; | |
803561cb MH |
1851 | uint32_t c13_size = 0; |
1852 | char *string_table = NULL; | |
81814b6f MH |
1853 | uint8_t *buf, *bufptr, *symbuf, *symbufptr; |
1854 | uint32_t sym_size = 0; | |
f559276d MH |
1855 | |
1856 | if (!bfd_get_full_section_contents (mod, s, &data)) | |
1857 | return false; | |
1858 | ||
1859 | if (!data) | |
1860 | return false; | |
1861 | ||
598c1ae6 MH |
1862 | /* Resolve relocations. Addresses are stored within the .debug$S section as |
1863 | a .secidx, .secrel32 pair. */ | |
1864 | ||
1865 | if (s->flags & SEC_RELOC) | |
1866 | { | |
1867 | struct internal_reloc *relocs; | |
1868 | struct internal_syment *symbols; | |
1869 | asection **sectlist; | |
1870 | unsigned int syment_count; | |
1871 | int sect_num; | |
1872 | struct external_syment *ext; | |
1873 | ||
1874 | syment_count = obj_raw_syment_count (mod); | |
1875 | ||
1876 | relocs = | |
1877 | _bfd_coff_read_internal_relocs (mod, s, false, NULL, true, NULL); | |
1878 | ||
1879 | symbols = xmalloc (sizeof (struct internal_syment) * syment_count); | |
1880 | sectlist = xmalloc (sizeof (asection *) * syment_count); | |
1881 | ||
1882 | ext = (struct external_syment *) (coff_data (mod)->external_syms); | |
1883 | ||
1884 | for (unsigned int i = 0; i < syment_count; i++) | |
1885 | { | |
1886 | bfd_coff_swap_sym_in (mod, &ext[i], &symbols[i]); | |
1887 | } | |
1888 | ||
1889 | sect_num = 1; | |
1890 | ||
1891 | for (asection *sect = mod->sections; sect; sect = sect->next) | |
1892 | { | |
1893 | for (unsigned int i = 0; i < syment_count; i++) | |
1894 | { | |
1895 | if (symbols[i].n_scnum == sect_num) | |
1896 | sectlist[i] = sect; | |
1897 | } | |
1898 | ||
1899 | sect_num++; | |
1900 | } | |
1901 | ||
1902 | if (!bfd_coff_relocate_section (abfd, coff_data (abfd)->link_info, mod, | |
1903 | s, data, relocs, symbols, sectlist)) | |
1904 | { | |
1905 | free (sectlist); | |
1906 | free (symbols); | |
1907 | free (data); | |
1908 | return false; | |
1909 | } | |
1910 | ||
1911 | free (sectlist); | |
1912 | free (symbols); | |
1913 | } | |
1914 | ||
f559276d MH |
1915 | if (bfd_getl32 (data) != CV_SIGNATURE_C13) |
1916 | { | |
1917 | free (data); | |
1918 | return true; | |
1919 | } | |
1920 | ||
1921 | off = sizeof (uint32_t); | |
1922 | ||
803561cb MH |
1923 | /* calculate size */ |
1924 | ||
f559276d MH |
1925 | while (off + sizeof (uint32_t) <= s->size) |
1926 | { | |
1927 | uint32_t type, size; | |
1928 | ||
1929 | type = bfd_getl32 (data + off); | |
1930 | ||
1931 | off += sizeof (uint32_t); | |
1932 | ||
1933 | if (off + sizeof (uint32_t) > s->size) | |
1934 | { | |
1935 | free (data); | |
1936 | bfd_set_error (bfd_error_bad_value); | |
1937 | return false; | |
1938 | } | |
1939 | ||
1940 | size = bfd_getl32 (data + off); | |
1941 | ||
1942 | off += sizeof (uint32_t); | |
1943 | ||
1944 | if (off + size > s->size) | |
1945 | { | |
1946 | free (data); | |
1947 | bfd_set_error (bfd_error_bad_value); | |
1948 | return false; | |
1949 | } | |
1950 | ||
1951 | switch (type) | |
1952 | { | |
803561cb MH |
1953 | case DEBUG_S_FILECHKSMS: |
1954 | c13_size += sizeof (uint32_t) + sizeof (uint32_t) + size; | |
1955 | ||
1956 | if (c13_size % sizeof (uint32_t)) | |
1957 | c13_size += sizeof (uint32_t) - (c13_size % sizeof (uint32_t)); | |
1958 | ||
1959 | break; | |
1960 | ||
f559276d MH |
1961 | case DEBUG_S_STRINGTABLE: |
1962 | parse_string_table (data + off, size, strings); | |
1963 | ||
803561cb MH |
1964 | string_table = (char *) data + off; |
1965 | ||
1966 | break; | |
598c1ae6 MH |
1967 | |
1968 | case DEBUG_S_LINES: | |
1969 | { | |
1970 | uint16_t sect; | |
1971 | ||
1972 | if (size < sizeof (uint32_t) + sizeof (uint16_t)) | |
1973 | { | |
1974 | free (data); | |
1975 | bfd_set_error (bfd_error_bad_value); | |
1976 | return false; | |
1977 | } | |
1978 | ||
1979 | sect = bfd_getl16 (data + off + sizeof (uint32_t)); | |
1980 | ||
1981 | /* Skip GC'd symbols. */ | |
1982 | if (sect != 0) | |
1983 | { | |
1984 | c13_size += sizeof (uint32_t) + sizeof (uint32_t) + size; | |
1985 | ||
1986 | if (c13_size % sizeof (uint32_t)) | |
1987 | c13_size += | |
1988 | sizeof (uint32_t) - (c13_size % sizeof (uint32_t)); | |
1989 | } | |
1990 | ||
1991 | break; | |
1992 | } | |
81814b6f MH |
1993 | |
1994 | case DEBUG_S_SYMBOLS: | |
1995 | if (!calculate_symbols_size (data + off, size, &sym_size)) | |
1996 | { | |
1997 | free (data); | |
1998 | bfd_set_error (bfd_error_bad_value); | |
1999 | return false; | |
2000 | } | |
2001 | ||
2002 | break; | |
803561cb MH |
2003 | } |
2004 | ||
2005 | off += size; | |
2006 | ||
2007 | if (off % sizeof (uint32_t)) | |
2008 | off += sizeof (uint32_t) - (off % sizeof (uint32_t)); | |
2009 | } | |
2010 | ||
81814b6f MH |
2011 | if (sym_size % sizeof (uint32_t)) |
2012 | sym_size += sizeof (uint32_t) - (sym_size % sizeof (uint32_t)); | |
2013 | ||
2014 | if (c13_size == 0 && sym_size == 0) | |
803561cb MH |
2015 | { |
2016 | free (data); | |
2017 | return true; | |
2018 | } | |
2019 | ||
2020 | /* copy data */ | |
2021 | ||
81814b6f MH |
2022 | buf = NULL; |
2023 | if (c13_size != 0) | |
2024 | buf = xmalloc (c13_size); | |
803561cb MH |
2025 | bufptr = buf; |
2026 | ||
81814b6f MH |
2027 | symbuf = NULL; |
2028 | if (sym_size != 0) | |
2029 | symbuf = xmalloc (sym_size); | |
2030 | symbufptr = symbuf; | |
2031 | ||
803561cb MH |
2032 | off = sizeof (uint32_t); |
2033 | ||
2034 | while (off + sizeof (uint32_t) <= s->size) | |
2035 | { | |
2036 | uint32_t type, size; | |
2037 | ||
2038 | type = bfd_getl32 (data + off); | |
2039 | off += sizeof (uint32_t); | |
2040 | ||
2041 | size = bfd_getl32 (data + off); | |
2042 | off += sizeof (uint32_t); | |
2043 | ||
2044 | switch (type) | |
2045 | { | |
2046 | case DEBUG_S_FILECHKSMS: | |
2047 | if (!copy_filechksms (data + off, size, string_table, | |
2048 | strings, bufptr, mod_source)) | |
2049 | { | |
2050 | free (data); | |
81814b6f | 2051 | free (symbuf); |
803561cb MH |
2052 | return false; |
2053 | } | |
2054 | ||
2055 | bufptr += sizeof (uint32_t) + sizeof (uint32_t) + size; | |
2056 | ||
f559276d | 2057 | break; |
598c1ae6 MH |
2058 | |
2059 | case DEBUG_S_LINES: | |
2060 | { | |
2061 | uint16_t sect; | |
2062 | ||
2063 | sect = bfd_getl16 (data + off + sizeof (uint32_t)); | |
2064 | ||
2065 | /* Skip if GC'd. */ | |
2066 | if (sect != 0) | |
2067 | { | |
2068 | bfd_putl32 (type, bufptr); | |
2069 | bufptr += sizeof (uint32_t); | |
2070 | ||
2071 | bfd_putl32 (size, bufptr); | |
2072 | bufptr += sizeof (uint32_t); | |
2073 | ||
2074 | memcpy (bufptr, data + off, size); | |
2075 | bufptr += size; | |
2076 | } | |
2077 | ||
2078 | break; | |
2079 | } | |
81814b6f MH |
2080 | |
2081 | case DEBUG_S_SYMBOLS: | |
2082 | if (!parse_symbols (data + off, size, &symbufptr, map, num_types, | |
2083 | sym_rec_stream, glob, mod_num)) | |
2084 | { | |
2085 | free (data); | |
2086 | free (symbuf); | |
2087 | return false; | |
2088 | } | |
2089 | ||
2090 | break; | |
f559276d MH |
2091 | } |
2092 | ||
2093 | off += size; | |
2094 | ||
2095 | if (off % sizeof (uint32_t)) | |
2096 | off += sizeof (uint32_t) - (off % sizeof (uint32_t)); | |
2097 | } | |
2098 | ||
2099 | free (data); | |
2100 | ||
81814b6f | 2101 | if (buf) |
803561cb | 2102 | { |
81814b6f MH |
2103 | if (*dataptr) |
2104 | { | |
2105 | /* Append the C13 info to what's already there, if the module has | |
2106 | multiple .debug$S sections. */ | |
803561cb | 2107 | |
81814b6f MH |
2108 | *dataptr = xrealloc (*dataptr, *sizeptr + c13_size); |
2109 | memcpy (*dataptr + *sizeptr, buf, c13_size); | |
803561cb | 2110 | |
81814b6f MH |
2111 | free (buf); |
2112 | } | |
2113 | else | |
2114 | { | |
2115 | *dataptr = buf; | |
2116 | } | |
2117 | ||
2118 | *sizeptr += c13_size; | |
803561cb | 2119 | } |
81814b6f MH |
2120 | |
2121 | if (symbuf) | |
803561cb | 2122 | { |
81814b6f MH |
2123 | if (*syms) |
2124 | { | |
2125 | *syms = xrealloc (*syms, *sym_byte_size + sym_size); | |
2126 | memcpy (*syms + *sym_byte_size, symbuf, sym_size); | |
2127 | ||
2128 | free (symbuf); | |
2129 | } | |
2130 | else | |
2131 | { | |
2132 | *syms = symbuf; | |
2133 | } | |
803561cb | 2134 | |
81814b6f MH |
2135 | *sym_byte_size += sym_size; |
2136 | } | |
803561cb | 2137 | |
f559276d MH |
2138 | return true; |
2139 | } | |
2140 | ||
d5b4c0dd MH |
2141 | /* Remap the type number stored in data from the per-module numbering to |
2142 | that of the deduplicated output list. */ | |
2143 | static bool | |
2144 | remap_type (void *data, struct type_entry **map, | |
2145 | uint32_t type_num, uint32_t num_types) | |
2146 | { | |
2147 | uint32_t type = bfd_getl32 (data); | |
2148 | ||
2149 | /* Ignore builtin types (those with IDs below 0x1000). */ | |
2150 | if (type < TPI_FIRST_INDEX) | |
2151 | return true; | |
2152 | ||
2153 | if (type >= TPI_FIRST_INDEX + type_num) | |
2154 | { | |
2155 | einfo (_("%P: CodeView type %v references other type %v not yet " | |
2156 | "declared\n"), TPI_FIRST_INDEX + type_num, type); | |
2157 | return false; | |
2158 | } | |
2159 | ||
2160 | if (type >= TPI_FIRST_INDEX + num_types) | |
2161 | { | |
2162 | einfo (_("%P: CodeView type %v references out of range type %v\n"), | |
2163 | TPI_FIRST_INDEX + type_num, type); | |
2164 | return false; | |
2165 | } | |
2166 | ||
2167 | type = TPI_FIRST_INDEX + map[type - TPI_FIRST_INDEX]->index; | |
2168 | bfd_putl32 (type, data); | |
2169 | ||
2170 | return true; | |
2171 | } | |
2172 | ||
2173 | /* Determines whether the name of a struct, class, or union counts as | |
2174 | "anonymous". Non-anonymous types have a hash based on just the name, | |
2175 | rather than the whole structure. */ | |
2176 | static bool | |
2177 | is_name_anonymous (char *name, size_t len) | |
2178 | { | |
2179 | static const char tag1[] = "<unnamed-tag>"; | |
2180 | static const char tag2[] = "__unnamed"; | |
2181 | static const char tag3[] = "::<unnamed-tag>"; | |
2182 | static const char tag4[] = "::__unnamed"; | |
2183 | ||
2184 | if (len == sizeof (tag1) - 1 && !memcmp (name, tag1, sizeof (tag1) - 1)) | |
2185 | return true; | |
2186 | ||
2187 | if (len == sizeof (tag2) - 1 && !memcmp (name, tag2, sizeof (tag2) - 1)) | |
2188 | return true; | |
2189 | ||
2190 | if (len >= sizeof (tag3) - 1 | |
2191 | && !memcmp (name + len - sizeof (tag3) + 1, tag3, sizeof (tag3) - 1)) | |
2192 | return true; | |
2193 | ||
2194 | if (len >= sizeof (tag4) - 1 | |
2195 | && !memcmp (name + len - sizeof (tag4) + 1, tag4, sizeof (tag4) - 1)) | |
2196 | return true; | |
2197 | ||
2198 | return false; | |
2199 | } | |
2200 | ||
81784004 MH |
2201 | /* Handle LF_UDT_SRC_LINE type entries, which are a special case. These |
2202 | give the source file and line number for each user-defined type that is | |
2203 | declared. We parse these and emit instead an LF_UDT_MOD_SRC_LINE entry, | |
2204 | which also includes the module number. */ | |
2205 | static bool | |
2206 | handle_udt_src_line (uint8_t *data, uint16_t size, struct type_entry **map, | |
2207 | uint32_t type_num, uint32_t num_types, | |
2208 | struct types *ids, uint16_t mod_num, | |
2209 | struct string_table *strings) | |
2210 | { | |
2211 | struct lf_udt_src_line *usl = (struct lf_udt_src_line *) data; | |
2212 | uint32_t orig_type, source_file_type; | |
2213 | void **slot; | |
2214 | hashval_t hash; | |
2215 | struct type_entry *e, *type_e, *str_e; | |
2216 | struct lf_udt_mod_src_line *umsl; | |
2217 | struct lf_string_id *str; | |
2218 | uint32_t source_file_offset; | |
2219 | ||
2220 | if (size < sizeof (struct lf_udt_src_line)) | |
2221 | { | |
2222 | einfo (_("%P: warning: truncated CodeView type record" | |
2223 | " LF_UDT_SRC_LINE\n")); | |
2224 | return false; | |
2225 | } | |
2226 | ||
2227 | /* Check if LF_UDT_MOD_SRC_LINE already present for type, and return. */ | |
2228 | ||
2229 | orig_type = bfd_getl32 (&usl->type); | |
2230 | ||
2231 | if (orig_type < TPI_FIRST_INDEX || | |
2232 | orig_type >= TPI_FIRST_INDEX + num_types || | |
2233 | !map[orig_type - TPI_FIRST_INDEX]) | |
2234 | { | |
2235 | einfo (_("%P: warning: CodeView type record LF_UDT_SRC_LINE" | |
2236 | " referred to unknown type %v\n"), orig_type); | |
2237 | return false; | |
2238 | } | |
2239 | ||
2240 | type_e = map[orig_type - TPI_FIRST_INDEX]; | |
2241 | ||
2242 | /* Skip if type already declared in other module. */ | |
2243 | if (type_e->has_udt_src_line) | |
2244 | return true; | |
2245 | ||
2246 | if (!remap_type (&usl->type, map, type_num, num_types)) | |
2247 | return false; | |
2248 | ||
2249 | /* Extract string from source_file_type. */ | |
2250 | ||
2251 | source_file_type = bfd_getl32 (&usl->source_file_type); | |
2252 | ||
2253 | if (source_file_type < TPI_FIRST_INDEX || | |
2254 | source_file_type >= TPI_FIRST_INDEX + num_types || | |
2255 | !map[source_file_type - TPI_FIRST_INDEX]) | |
2256 | { | |
2257 | einfo (_("%P: warning: CodeView type record LF_UDT_SRC_LINE" | |
2258 | " referred to unknown string %v\n"), source_file_type); | |
2259 | return false; | |
2260 | } | |
2261 | ||
2262 | str_e = map[source_file_type - TPI_FIRST_INDEX]; | |
2263 | ||
2264 | if (bfd_getl16 (str_e->data + sizeof (uint16_t)) != LF_STRING_ID) | |
2265 | { | |
2266 | einfo (_("%P: warning: CodeView type record LF_UDT_SRC_LINE" | |
2267 | " pointed to unexpected record type\n")); | |
2268 | return false; | |
2269 | } | |
2270 | ||
2271 | str = (struct lf_string_id *) str_e->data; | |
2272 | ||
2273 | /* Add string to string table. */ | |
2274 | ||
2275 | source_file_offset = add_string (str->string, strlen (str->string), | |
2276 | strings); | |
2277 | ||
2278 | /* Add LF_UDT_MOD_SRC_LINE entry. */ | |
2279 | ||
2280 | size = sizeof (struct lf_udt_mod_src_line); | |
2281 | ||
2282 | e = xmalloc (offsetof (struct type_entry, data) + size); | |
2283 | ||
2284 | e->next = NULL; | |
2285 | e->index = ids->num_types; | |
2286 | e->has_udt_src_line = false; | |
2287 | ||
2288 | /* LF_UDT_MOD_SRC_LINE use calc_hash on the type number, rather than | |
2289 | the crc32 used for type hashes elsewhere. */ | |
2290 | e->cv_hash = calc_hash ((char *) &usl->type, sizeof (uint32_t)); | |
2291 | ||
2292 | type_e->has_udt_src_line = true; | |
2293 | ||
2294 | umsl = (struct lf_udt_mod_src_line *) e->data; | |
2295 | ||
2296 | bfd_putl16 (size - sizeof (uint16_t), &umsl->size); | |
2297 | bfd_putl16 (LF_UDT_MOD_SRC_LINE, &umsl->kind); | |
2298 | memcpy (&umsl->type, &usl->type, sizeof (uint32_t)); | |
2299 | bfd_putl32 (source_file_offset, &umsl->source_file_string); | |
2300 | memcpy (&umsl->line_no, &usl->line_no, sizeof (uint32_t)); | |
2301 | bfd_putl16 (mod_num + 1, &umsl->module_no); | |
2302 | ||
2303 | hash = iterative_hash (e->data, size, 0); | |
2304 | ||
2305 | slot = htab_find_slot_with_hash (ids->hashmap, data, hash, INSERT); | |
2306 | if (!slot) | |
2307 | { | |
2308 | free (e); | |
2309 | return false; | |
2310 | } | |
2311 | ||
2312 | if (*slot) | |
2313 | { | |
2314 | free (e); | |
2315 | einfo (_("%P: warning: duplicate CodeView type record " | |
2316 | "LF_UDT_MOD_SRC_LINE\n")); | |
2317 | return false; | |
2318 | } | |
2319 | ||
2320 | *slot = e; | |
2321 | ||
2322 | if (ids->last) | |
2323 | ids->last->next = e; | |
2324 | else | |
2325 | ids->first = e; | |
2326 | ||
2327 | ids->last = e; | |
2328 | ||
2329 | map[type_num] = e; | |
2330 | ||
2331 | ids->num_types++; | |
2332 | ||
2333 | return true; | |
2334 | } | |
2335 | ||
d5b4c0dd MH |
2336 | /* Parse a type definition in the .debug$T section. We remap the numbers |
2337 | of any referenced types, and if the type is not a duplicate of one | |
2338 | already seen add it to types (for TPI types) or ids (for IPI types). */ | |
2339 | static bool | |
2340 | handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, | |
fca9096a | 2341 | uint32_t num_types, struct types *types, |
81784004 MH |
2342 | struct types *ids, uint16_t mod_num, |
2343 | struct string_table *strings) | |
d5b4c0dd MH |
2344 | { |
2345 | uint16_t size, type; | |
2346 | void **slot; | |
2347 | hashval_t hash; | |
2348 | bool other_hash = false; | |
2349 | uint32_t cv_hash; | |
fca9096a MH |
2350 | struct types *t; |
2351 | bool ipi = false; | |
d5b4c0dd MH |
2352 | |
2353 | size = bfd_getl16 (data) + sizeof (uint16_t); | |
2354 | type = bfd_getl16 (data + sizeof (uint16_t)); | |
2355 | ||
2356 | switch (type) | |
2357 | { | |
2358 | case LF_MODIFIER: | |
2359 | { | |
2360 | struct lf_modifier *mod = (struct lf_modifier *) data; | |
2361 | ||
2362 | if (size < offsetof (struct lf_modifier, modifier)) | |
2363 | { | |
2364 | einfo (_("%P: warning: truncated CodeView type record " | |
2365 | "LF_MODIFIER\n")); | |
2366 | return false; | |
2367 | } | |
2368 | ||
2369 | if (!remap_type (&mod->base_type, map, type_num, num_types)) | |
2370 | return false; | |
2371 | ||
2372 | break; | |
2373 | } | |
2374 | ||
2375 | case LF_POINTER: | |
2376 | { | |
2377 | struct lf_pointer *ptr = (struct lf_pointer *) data; | |
2378 | ||
2379 | if (size < offsetof (struct lf_pointer, attributes)) | |
2380 | { | |
2381 | einfo (_("%P: warning: truncated CodeView type record" | |
2382 | " LF_POINTER\n")); | |
2383 | return false; | |
2384 | } | |
2385 | ||
2386 | if (!remap_type (&ptr->base_type, map, type_num, num_types)) | |
2387 | return false; | |
2388 | ||
2389 | break; | |
2390 | } | |
2391 | ||
2392 | case LF_PROCEDURE: | |
2393 | { | |
2394 | struct lf_procedure *proc = (struct lf_procedure *) data; | |
2395 | ||
2396 | if (size < sizeof (struct lf_procedure)) | |
2397 | { | |
2398 | einfo (_("%P: warning: truncated CodeView type record" | |
2399 | " LF_PROCEDURE\n")); | |
2400 | return false; | |
2401 | } | |
2402 | ||
2403 | if (!remap_type (&proc->return_type, map, type_num, num_types)) | |
2404 | return false; | |
2405 | ||
2406 | if (!remap_type (&proc->arglist, map, type_num, num_types)) | |
2407 | return false; | |
2408 | ||
2409 | break; | |
2410 | } | |
2411 | ||
2412 | case LF_MFUNCTION: | |
2413 | { | |
2414 | struct lf_mfunction *func = (struct lf_mfunction *) data; | |
2415 | ||
2416 | if (size < sizeof (struct lf_procedure)) | |
2417 | { | |
2418 | einfo (_("%P: warning: truncated CodeView type record" | |
2419 | " LF_MFUNCTION\n")); | |
2420 | return false; | |
2421 | } | |
2422 | ||
2423 | if (!remap_type (&func->return_type, map, type_num, num_types)) | |
2424 | return false; | |
2425 | ||
2426 | if (!remap_type (&func->containing_class_type, map, type_num, | |
2427 | num_types)) | |
2428 | return false; | |
2429 | ||
2430 | if (!remap_type (&func->this_type, map, type_num, num_types)) | |
2431 | return false; | |
2432 | ||
2433 | if (!remap_type (&func->arglist, map, type_num, num_types)) | |
2434 | return false; | |
2435 | ||
2436 | break; | |
2437 | } | |
2438 | ||
2439 | case LF_ARGLIST: | |
2440 | { | |
2441 | uint32_t num_entries; | |
2442 | struct lf_arglist *al = (struct lf_arglist *) data; | |
2443 | ||
2444 | if (size < offsetof (struct lf_arglist, args)) | |
2445 | { | |
2446 | einfo (_("%P: warning: truncated CodeView type record" | |
2447 | " LF_ARGLIST\n")); | |
2448 | return false; | |
2449 | } | |
2450 | ||
2451 | num_entries = bfd_getl32 (&al->num_entries); | |
2452 | ||
2453 | if (size < offsetof (struct lf_arglist, args) | |
2454 | + (num_entries * sizeof (uint32_t))) | |
2455 | { | |
2456 | einfo (_("%P: warning: truncated CodeView type record" | |
2457 | " LF_ARGLIST\n")); | |
2458 | return false; | |
2459 | } | |
2460 | ||
2461 | for (uint32_t i = 0; i < num_entries; i++) | |
2462 | { | |
2463 | if (!remap_type (&al->args[i], map, type_num, num_types)) | |
2464 | return false; | |
2465 | } | |
2466 | ||
2467 | break; | |
2468 | } | |
2469 | ||
2470 | case LF_FIELDLIST: | |
2471 | { | |
2472 | uint16_t left = size - sizeof (uint16_t) - sizeof (uint16_t); | |
2473 | uint8_t *ptr = data + sizeof (uint16_t) + sizeof (uint16_t); | |
2474 | ||
2475 | while (left > 0) | |
2476 | { | |
2477 | uint16_t subtype; | |
2478 | ||
2479 | if (left < sizeof (uint16_t)) | |
2480 | { | |
2481 | einfo (_("%P: warning: truncated CodeView type record" | |
2482 | " LF_FIELDLIST\n")); | |
2483 | return false; | |
2484 | } | |
2485 | ||
2486 | subtype = bfd_getl16 (ptr); | |
2487 | ||
2488 | switch (subtype) | |
2489 | { | |
2490 | case LF_MEMBER: | |
2491 | { | |
2492 | struct lf_member *mem = (struct lf_member *) ptr; | |
fdf591c4 | 2493 | uint16_t offset; |
d5b4c0dd MH |
2494 | size_t name_len, subtype_len; |
2495 | ||
2496 | if (left < offsetof (struct lf_member, name)) | |
2497 | { | |
2498 | einfo (_("%P: warning: truncated CodeView type record" | |
2499 | " LF_MEMBER\n")); | |
2500 | return false; | |
2501 | } | |
2502 | ||
2503 | if (!remap_type (&mem->type, map, type_num, num_types)) | |
2504 | return false; | |
2505 | ||
fdf591c4 MH |
2506 | subtype_len = offsetof (struct lf_member, name); |
2507 | ||
2508 | offset = bfd_getl16 (&mem->offset); | |
2509 | ||
2510 | /* If offset >= 0x8000, actual value follows. */ | |
2511 | if (offset >= 0x8000) | |
2512 | { | |
2513 | unsigned int param_len = extended_value_len (offset); | |
2514 | ||
2515 | if (param_len == 0) | |
2516 | { | |
2517 | einfo (_("%P: warning: unhandled type %v within" | |
2518 | " LF_MEMBER\n"), offset); | |
2519 | return false; | |
2520 | } | |
2521 | ||
2522 | subtype_len += param_len; | |
2523 | ||
2524 | if (left < subtype_len) | |
2525 | { | |
2526 | einfo (_("%P: warning: truncated CodeView type record" | |
2527 | " LF_MEMBER\n")); | |
2528 | return false; | |
2529 | } | |
2530 | } | |
2531 | ||
d5b4c0dd | 2532 | name_len = |
fdf591c4 | 2533 | strnlen ((char *) mem + subtype_len, left - subtype_len); |
d5b4c0dd MH |
2534 | |
2535 | if (name_len == left - offsetof (struct lf_member, name)) | |
2536 | { | |
2537 | einfo (_("%P: warning: name for LF_MEMBER has no" | |
2538 | " terminating zero\n")); | |
2539 | return false; | |
2540 | } | |
2541 | ||
2542 | name_len++; | |
2543 | ||
fdf591c4 | 2544 | subtype_len += name_len; |
d5b4c0dd MH |
2545 | |
2546 | if (subtype_len % 4 != 0) | |
2547 | subtype_len += 4 - (subtype_len % 4); | |
2548 | ||
2549 | if (left < subtype_len) | |
2550 | { | |
2551 | einfo (_("%P: warning: truncated CodeView type record" | |
2552 | " LF_FIELDLIST\n")); | |
2553 | return false; | |
2554 | } | |
2555 | ||
2556 | ptr += subtype_len; | |
2557 | left -= subtype_len; | |
2558 | ||
2559 | break; | |
2560 | } | |
2561 | ||
2562 | case LF_ENUMERATE: | |
2563 | { | |
2564 | struct lf_enumerate *en = (struct lf_enumerate *) ptr; | |
2565 | size_t name_len, subtype_len; | |
2566 | uint16_t val; | |
2567 | ||
2568 | if (left < offsetof (struct lf_enumerate, name)) | |
2569 | { | |
2570 | einfo (_("%P: warning: truncated CodeView type record" | |
2571 | " LF_ENUMERATE\n")); | |
2572 | return false; | |
2573 | } | |
2574 | ||
2575 | subtype_len = offsetof (struct lf_enumerate, name); | |
2576 | ||
2577 | val = bfd_getl16 (&en->value); | |
2578 | ||
2579 | /* If val >= 0x8000, the actual value immediately follows. */ | |
2580 | if (val >= 0x8000) | |
2581 | { | |
2582 | unsigned int param_len = extended_value_len (val); | |
2583 | ||
2584 | if (param_len == 0) | |
2585 | { | |
2586 | einfo (_("%P: warning: unhandled type %v within" | |
2587 | " LF_ENUMERATE\n"), val); | |
2588 | return false; | |
2589 | } | |
2590 | ||
2591 | if (left < subtype_len + param_len) | |
2592 | { | |
2593 | einfo (_("%P: warning: truncated CodeView type" | |
2594 | " record LF_ENUMERATE\n")); | |
2595 | return false; | |
2596 | } | |
2597 | ||
2598 | subtype_len += param_len; | |
2599 | } | |
2600 | ||
2601 | name_len = strnlen ((char *) ptr + subtype_len, | |
2602 | left - subtype_len); | |
2603 | ||
2604 | if (name_len == left - offsetof (struct lf_enumerate, name)) | |
2605 | { | |
2606 | einfo (_("%P: warning: name for LF_ENUMERATE has no" | |
2607 | " terminating zero\n")); | |
2608 | return false; | |
2609 | } | |
2610 | ||
2611 | name_len++; | |
2612 | ||
2613 | subtype_len += name_len; | |
2614 | ||
2615 | if (subtype_len % 4 != 0) | |
2616 | subtype_len += 4 - (subtype_len % 4); | |
2617 | ||
2618 | if (left < subtype_len) | |
2619 | { | |
2620 | einfo (_("%P: warning: truncated CodeView type record" | |
2621 | " LF_ENUMERATE\n")); | |
2622 | return false; | |
2623 | } | |
2624 | ||
2625 | ptr += subtype_len; | |
2626 | left -= subtype_len; | |
2627 | ||
2628 | break; | |
2629 | } | |
2630 | ||
2631 | case LF_INDEX: | |
2632 | { | |
2633 | struct lf_index *ind = (struct lf_index *) ptr; | |
2634 | ||
2635 | if (left < sizeof (struct lf_index)) | |
2636 | { | |
2637 | einfo (_("%P: warning: truncated CodeView type record" | |
2638 | " LF_INDEX\n")); | |
2639 | return false; | |
2640 | } | |
2641 | ||
2642 | if (!remap_type (&ind->index, map, type_num, num_types)) | |
2643 | return false; | |
2644 | ||
2645 | ptr += sizeof (struct lf_index); | |
2646 | left -= sizeof (struct lf_index); | |
2647 | ||
2648 | break; | |
2649 | } | |
2650 | ||
2651 | case LF_ONEMETHOD: | |
2652 | { | |
2653 | struct lf_onemethod *meth = (struct lf_onemethod *) ptr; | |
2654 | size_t name_len, subtype_len; | |
2655 | ||
2656 | if (left < offsetof (struct lf_onemethod, name)) | |
2657 | { | |
2658 | einfo (_("%P: warning: truncated CodeView type record" | |
2659 | " LF_ONEMETHOD\n")); | |
2660 | return false; | |
2661 | } | |
2662 | ||
2663 | if (!remap_type (&meth->method_type, map, type_num, | |
2664 | num_types)) | |
2665 | return false; | |
2666 | ||
2667 | name_len = | |
2668 | strnlen (meth->name, | |
2669 | left - offsetof (struct lf_onemethod, name)); | |
2670 | ||
2671 | if (name_len == left - offsetof (struct lf_onemethod, name)) | |
2672 | { | |
2673 | einfo (_("%P: warning: name for LF_ONEMETHOD has no" | |
2674 | " terminating zero\n")); | |
2675 | return false; | |
2676 | } | |
2677 | ||
2678 | name_len++; | |
2679 | ||
2680 | subtype_len = offsetof (struct lf_onemethod, name) | |
2681 | + name_len; | |
2682 | ||
2683 | if (subtype_len % 4 != 0) | |
2684 | subtype_len += 4 - (subtype_len % 4); | |
2685 | ||
2686 | if (left < subtype_len) | |
2687 | { | |
2688 | einfo (_("%P: warning: truncated CodeView type record" | |
2689 | " LF_FIELDLIST\n")); | |
2690 | return false; | |
2691 | } | |
2692 | ||
2693 | ptr += subtype_len; | |
2694 | left -= subtype_len; | |
2695 | ||
2696 | break; | |
2697 | } | |
2698 | ||
2699 | case LF_METHOD: | |
2700 | { | |
2701 | struct lf_method *meth = (struct lf_method *) ptr; | |
2702 | size_t name_len, subtype_len; | |
2703 | ||
2704 | if (left < offsetof (struct lf_method, name)) | |
2705 | { | |
2706 | einfo (_("%P: warning: truncated CodeView type record" | |
2707 | " LF_METHOD\n")); | |
2708 | return false; | |
2709 | } | |
2710 | ||
2711 | if (!remap_type (&meth->method_list, map, type_num, | |
2712 | num_types)) | |
2713 | return false; | |
2714 | ||
2715 | name_len = | |
2716 | strnlen (meth->name, | |
2717 | left - offsetof (struct lf_method, name)); | |
2718 | ||
2719 | if (name_len == left - offsetof (struct lf_method, name)) | |
2720 | { | |
2721 | einfo (_("%P: warning: name for LF_METHOD has no" | |
2722 | " terminating zero\n")); | |
2723 | return false; | |
2724 | } | |
2725 | ||
2726 | name_len++; | |
2727 | ||
2728 | subtype_len = offsetof (struct lf_method, name) + name_len; | |
2729 | ||
2730 | if (subtype_len % 4 != 0) | |
2731 | subtype_len += 4 - (subtype_len % 4); | |
2732 | ||
2733 | if (left < subtype_len) | |
2734 | { | |
2735 | einfo (_("%P: warning: truncated CodeView type record" | |
2736 | " LF_FIELDLIST\n")); | |
2737 | return false; | |
2738 | } | |
2739 | ||
2740 | ptr += subtype_len; | |
2741 | left -= subtype_len; | |
2742 | ||
2743 | break; | |
2744 | } | |
2745 | ||
2746 | case LF_BCLASS: | |
2747 | { | |
2748 | struct lf_bclass *bc = (struct lf_bclass *) ptr; | |
fdf591c4 MH |
2749 | size_t subtype_len; |
2750 | uint16_t offset; | |
d5b4c0dd MH |
2751 | |
2752 | if (left < sizeof (struct lf_bclass)) | |
2753 | { | |
2754 | einfo (_("%P: warning: truncated CodeView type record" | |
2755 | " LF_BCLASS\n")); | |
2756 | return false; | |
2757 | } | |
2758 | ||
2759 | if (!remap_type (&bc->base_class_type, map, type_num, | |
2760 | num_types)) | |
2761 | return false; | |
2762 | ||
fdf591c4 MH |
2763 | subtype_len = sizeof (struct lf_bclass); |
2764 | ||
2765 | offset = bfd_getl16 (&bc->offset); | |
2766 | ||
2767 | /* If offset >= 0x8000, actual value follows. */ | |
2768 | if (offset >= 0x8000) | |
2769 | { | |
2770 | unsigned int param_len = extended_value_len (offset); | |
2771 | ||
2772 | if (param_len == 0) | |
2773 | { | |
2774 | einfo (_("%P: warning: unhandled type %v within" | |
2775 | " LF_BCLASS\n"), offset); | |
2776 | return false; | |
2777 | } | |
2778 | ||
2779 | subtype_len += param_len; | |
2780 | ||
2781 | if (left < subtype_len) | |
2782 | { | |
2783 | einfo (_("%P: warning: truncated CodeView type record" | |
2784 | " LF_BCLASS\n")); | |
2785 | return false; | |
2786 | } | |
2787 | } | |
2788 | ||
2789 | if (subtype_len % 4 != 0) | |
2790 | subtype_len += 4 - (subtype_len % 4); | |
2791 | ||
2792 | if (left < subtype_len) | |
2793 | { | |
2794 | einfo (_("%P: warning: truncated CodeView type record" | |
2795 | " LF_BCLASS\n")); | |
2796 | return false; | |
2797 | } | |
2798 | ||
2799 | ptr += subtype_len; | |
2800 | left -= subtype_len; | |
d5b4c0dd MH |
2801 | |
2802 | break; | |
2803 | } | |
2804 | ||
2805 | case LF_VFUNCTAB: | |
2806 | { | |
2807 | struct lf_vfunctab *vft = (struct lf_vfunctab *) ptr; | |
2808 | ||
2809 | if (left < sizeof (struct lf_vfunctab)) | |
2810 | { | |
2811 | einfo (_("%P: warning: truncated CodeView type record" | |
2812 | " LF_VFUNCTAB\n")); | |
2813 | return false; | |
2814 | } | |
2815 | ||
2816 | if (!remap_type (&vft->type, map, type_num, num_types)) | |
2817 | return false; | |
2818 | ||
2819 | ptr += sizeof (struct lf_vfunctab); | |
2820 | left -= sizeof (struct lf_vfunctab); | |
2821 | ||
2822 | break; | |
2823 | } | |
2824 | ||
2825 | case LF_VBCLASS: | |
2826 | case LF_IVBCLASS: | |
2827 | { | |
2828 | struct lf_vbclass *vbc = (struct lf_vbclass *) ptr; | |
fdf591c4 MH |
2829 | size_t subtype_len; |
2830 | uint16_t offset; | |
d5b4c0dd MH |
2831 | |
2832 | if (left < sizeof (struct lf_vbclass)) | |
2833 | { | |
2834 | einfo (_("%P: warning: truncated CodeView type record" | |
2835 | " LF_VBCLASS/LF_IVBCLASS\n")); | |
2836 | return false; | |
2837 | } | |
2838 | ||
2839 | if (!remap_type (&vbc->base_class_type, map, type_num, | |
2840 | num_types)) | |
2841 | return false; | |
2842 | ||
2843 | if (!remap_type (&vbc->virtual_base_pointer_type, map, | |
2844 | type_num, num_types)) | |
2845 | return false; | |
2846 | ||
fdf591c4 MH |
2847 | subtype_len = offsetof (struct lf_vbclass, |
2848 | virtual_base_vbtable_offset); | |
2849 | ||
2850 | offset = bfd_getl16 (&vbc->virtual_base_pointer_offset); | |
2851 | ||
2852 | /* If offset >= 0x8000, actual value follows. */ | |
2853 | if (offset >= 0x8000) | |
2854 | { | |
2855 | unsigned int param_len = extended_value_len (offset); | |
2856 | ||
2857 | if (param_len == 0) | |
2858 | { | |
2859 | einfo (_("%P: warning: unhandled type %v within" | |
2860 | " LF_VBCLASS/LF_IVBCLASS\n"), offset); | |
2861 | return false; | |
2862 | } | |
2863 | ||
2864 | subtype_len += param_len; | |
2865 | ||
2866 | if (left < subtype_len) | |
2867 | { | |
2868 | einfo (_("%P: warning: truncated CodeView type record" | |
2869 | " LF_VBCLASS/LF_IVBCLASS\n")); | |
2870 | return false; | |
2871 | } | |
2872 | } | |
2873 | ||
2874 | offset = bfd_getl16 ((char *)vbc + subtype_len); | |
2875 | subtype_len += sizeof (uint16_t); | |
2876 | ||
2877 | /* If offset >= 0x8000, actual value follows. */ | |
2878 | if (offset >= 0x8000) | |
2879 | { | |
2880 | unsigned int param_len = extended_value_len (offset); | |
2881 | ||
2882 | if (param_len == 0) | |
2883 | { | |
2884 | einfo (_("%P: warning: unhandled type %v within" | |
2885 | " LF_VBCLASS/LF_IVBCLASS\n"), offset); | |
2886 | return false; | |
2887 | } | |
2888 | ||
2889 | subtype_len += param_len; | |
2890 | ||
2891 | if (left < subtype_len) | |
2892 | { | |
2893 | einfo (_("%P: warning: truncated CodeView type record" | |
2894 | " LF_VBCLASS/LF_IVBCLASS\n")); | |
2895 | return false; | |
2896 | } | |
2897 | } | |
2898 | ||
2899 | if (subtype_len % 4 != 0) | |
2900 | subtype_len += 4 - (subtype_len % 4); | |
2901 | ||
2902 | if (left < subtype_len) | |
2903 | { | |
2904 | einfo (_("%P: warning: truncated CodeView type record" | |
2905 | " LF_VBCLASS/LF_IVBCLASS\n")); | |
2906 | return false; | |
2907 | } | |
2908 | ||
2909 | ptr += subtype_len; | |
2910 | left -= subtype_len; | |
d5b4c0dd MH |
2911 | |
2912 | break; | |
2913 | } | |
2914 | ||
2915 | case LF_STMEMBER: | |
2916 | { | |
2917 | struct lf_static_member *st = | |
2918 | (struct lf_static_member *) ptr; | |
2919 | size_t name_len, subtype_len; | |
2920 | ||
2921 | if (left < offsetof (struct lf_static_member, name)) | |
2922 | { | |
2923 | einfo (_("%P: warning: truncated CodeView type record" | |
2924 | " LF_STMEMBER\n")); | |
2925 | return false; | |
2926 | } | |
2927 | ||
2928 | if (!remap_type (&st->type, map, type_num, num_types)) | |
2929 | return false; | |
2930 | ||
2931 | name_len = | |
2932 | strnlen (st->name, | |
2933 | left - offsetof (struct lf_static_member, name)); | |
2934 | ||
2935 | if (name_len == left | |
2936 | - offsetof (struct lf_static_member, name)) | |
2937 | { | |
2938 | einfo (_("%P: warning: name for LF_STMEMBER has no" | |
2939 | " terminating zero\n")); | |
2940 | return false; | |
2941 | } | |
2942 | ||
2943 | name_len++; | |
2944 | ||
2945 | subtype_len = offsetof (struct lf_static_member, name) | |
2946 | + name_len; | |
2947 | ||
2948 | if (subtype_len % 4 != 0) | |
2949 | subtype_len += 4 - (subtype_len % 4); | |
2950 | ||
2951 | if (left < subtype_len) | |
2952 | { | |
2953 | einfo (_("%P: warning: truncated CodeView type record" | |
2954 | " LF_FIELDLIST\n")); | |
2955 | return false; | |
2956 | } | |
2957 | ||
2958 | ptr += subtype_len; | |
2959 | left -= subtype_len; | |
2960 | ||
2961 | break; | |
2962 | } | |
2963 | ||
2964 | case LF_NESTTYPE: | |
2965 | { | |
2966 | struct lf_nest_type *nest = (struct lf_nest_type *) ptr; | |
2967 | size_t name_len, subtype_len; | |
2968 | ||
2969 | if (left < offsetof (struct lf_nest_type, name)) | |
2970 | { | |
2971 | einfo (_("%P: warning: truncated CodeView type record" | |
2972 | " LF_NESTTYPE\n")); | |
2973 | return false; | |
2974 | } | |
2975 | ||
2976 | if (!remap_type (&nest->type, map, type_num, num_types)) | |
2977 | return false; | |
2978 | ||
2979 | name_len = | |
2980 | strnlen (nest->name, | |
2981 | left - offsetof (struct lf_nest_type, name)); | |
2982 | ||
2983 | if (name_len == left - offsetof (struct lf_nest_type, name)) | |
2984 | { | |
2985 | einfo (_("%P: warning: name for LF_NESTTYPE has no" | |
2986 | " terminating zero\n")); | |
2987 | return false; | |
2988 | } | |
2989 | ||
2990 | name_len++; | |
2991 | ||
2992 | subtype_len = offsetof (struct lf_nest_type, name) | |
2993 | + name_len; | |
2994 | ||
2995 | if (subtype_len % 4 != 0) | |
2996 | subtype_len += 4 - (subtype_len % 4); | |
2997 | ||
2998 | if (left < subtype_len) | |
2999 | { | |
3000 | einfo (_("%P: warning: truncated CodeView type record" | |
3001 | " LF_FIELDLIST\n")); | |
3002 | return false; | |
3003 | } | |
3004 | ||
3005 | ptr += subtype_len; | |
3006 | left -= subtype_len; | |
3007 | ||
3008 | break; | |
3009 | } | |
3010 | ||
3011 | default: | |
3012 | einfo (_("%P: warning: unrecognized CodeView subtype %v\n"), | |
3013 | subtype); | |
3014 | return false; | |
3015 | } | |
3016 | } | |
3017 | ||
3018 | break; | |
3019 | } | |
3020 | ||
3021 | case LF_BITFIELD: | |
3022 | { | |
3023 | struct lf_bitfield *bf = (struct lf_bitfield *) data; | |
3024 | ||
3025 | if (size < offsetof (struct lf_bitfield, length)) | |
3026 | { | |
3027 | einfo (_("%P: warning: truncated CodeView type record" | |
3028 | " LF_BITFIELD\n")); | |
3029 | return false; | |
3030 | } | |
3031 | ||
3032 | if (!remap_type (&bf->base_type, map, type_num, num_types)) | |
3033 | return false; | |
3034 | ||
3035 | break; | |
3036 | } | |
3037 | ||
3038 | case LF_METHODLIST: | |
3039 | { | |
3040 | struct lf_methodlist *ml = (struct lf_methodlist *) data; | |
3041 | unsigned int num_entries; | |
3042 | ||
3043 | if (size < offsetof (struct lf_methodlist, entries)) | |
3044 | { | |
3045 | einfo (_("%P: warning: truncated CodeView type record" | |
3046 | " LF_METHODLIST\n")); | |
3047 | return false; | |
3048 | } | |
3049 | ||
3050 | if ((size - offsetof (struct lf_methodlist, entries)) | |
3051 | % sizeof (struct lf_methodlist_entry)) | |
3052 | { | |
3053 | einfo (_("%P: warning: malformed CodeView type record" | |
3054 | " LF_METHODLIST\n")); | |
3055 | return false; | |
3056 | } | |
3057 | ||
3058 | num_entries = (size - offsetof (struct lf_methodlist, entries)) | |
3059 | / sizeof (struct lf_methodlist_entry); | |
3060 | ||
3061 | for (unsigned int i = 0; i < num_entries; i++) | |
3062 | { | |
3063 | if (!remap_type (&ml->entries[i].method_type, map, | |
3064 | type_num, num_types)) | |
3065 | return false; | |
3066 | } | |
3067 | ||
3068 | break; | |
3069 | } | |
3070 | ||
3071 | case LF_ARRAY: | |
3072 | { | |
3073 | struct lf_array *arr = (struct lf_array *) data; | |
3074 | ||
3075 | if (size < offsetof (struct lf_array, length_in_bytes)) | |
3076 | { | |
3077 | einfo (_("%P: warning: truncated CodeView type record" | |
3078 | " LF_ARRAY\n")); | |
3079 | return false; | |
3080 | } | |
3081 | ||
3082 | if (!remap_type (&arr->element_type, map, type_num, num_types)) | |
3083 | return false; | |
3084 | ||
3085 | if (!remap_type (&arr->index_type, map, type_num, num_types)) | |
3086 | return false; | |
3087 | ||
3088 | break; | |
3089 | } | |
3090 | ||
3091 | case LF_CLASS: | |
3092 | case LF_STRUCTURE: | |
3093 | { | |
3094 | struct lf_class *cl = (struct lf_class *) data; | |
fdf591c4 MH |
3095 | uint16_t prop, num_bytes; |
3096 | size_t name_len, name_off; | |
d5b4c0dd MH |
3097 | |
3098 | if (size < offsetof (struct lf_class, name)) | |
3099 | { | |
3100 | einfo (_("%P: warning: truncated CodeView type record" | |
3101 | " LF_CLASS/LF_STRUCTURE\n")); | |
3102 | return false; | |
3103 | } | |
3104 | ||
3105 | if (!remap_type (&cl->field_list, map, type_num, num_types)) | |
3106 | return false; | |
3107 | ||
3108 | if (!remap_type (&cl->derived_from, map, type_num, num_types)) | |
3109 | return false; | |
3110 | ||
3111 | if (!remap_type (&cl->vshape, map, type_num, num_types)) | |
3112 | return false; | |
3113 | ||
fdf591c4 MH |
3114 | name_off = offsetof (struct lf_class, name); |
3115 | ||
3116 | num_bytes = bfd_getl16 (&cl->length); | |
d5b4c0dd | 3117 | |
fdf591c4 MH |
3118 | /* If num_bytes >= 0x8000, actual value follows. */ |
3119 | if (num_bytes >= 0x8000) | |
3120 | { | |
3121 | unsigned int param_len = extended_value_len (num_bytes); | |
3122 | ||
3123 | if (param_len == 0) | |
3124 | { | |
3125 | einfo (_("%P: warning: unhandled type %v within" | |
3126 | " LF_CLASS/LF_STRUCTURE\n"), num_bytes); | |
3127 | return false; | |
3128 | } | |
3129 | ||
3130 | name_off += param_len; | |
3131 | ||
3132 | if (size < name_off) | |
3133 | { | |
3134 | einfo (_("%P: warning: truncated CodeView type record" | |
3135 | " LF_CLASS/LF_STRUCTURE\n")); | |
3136 | return false; | |
3137 | } | |
3138 | } | |
3139 | ||
3140 | name_len = strnlen ((char *) cl + name_off, size - name_off); | |
3141 | ||
3142 | if (name_len == size - name_off) | |
d5b4c0dd MH |
3143 | { |
3144 | einfo (_("%P: warning: name for LF_CLASS/LF_STRUCTURE has no" | |
3145 | " terminating zero\n")); | |
3146 | return false; | |
3147 | } | |
3148 | ||
3149 | prop = bfd_getl16 (&cl->properties); | |
3150 | ||
3151 | if (prop & CV_PROP_HAS_UNIQUE_NAME) | |
3152 | { | |
3153 | /* Structure has another name following first one. */ | |
3154 | ||
fdf591c4 | 3155 | size_t len = name_off + name_len + 1; |
d5b4c0dd MH |
3156 | size_t unique_name_len; |
3157 | ||
fdf591c4 MH |
3158 | unique_name_len = strnlen ((char *) cl + name_off + name_len + 1, |
3159 | size - len); | |
d5b4c0dd MH |
3160 | |
3161 | if (unique_name_len == size - len) | |
3162 | { | |
3163 | einfo (_("%P: warning: unique name for LF_CLASS/LF_STRUCTURE" | |
3164 | " has no terminating zero\n")); | |
3165 | return false; | |
3166 | } | |
3167 | } | |
3168 | ||
3169 | if (!(prop & (CV_PROP_FORWARD_REF | CV_PROP_SCOPED)) | |
fdf591c4 | 3170 | && !is_name_anonymous ((char *) cl + name_off, name_len)) |
d5b4c0dd MH |
3171 | { |
3172 | other_hash = true; | |
fdf591c4 | 3173 | cv_hash = crc32 ((uint8_t *) cl + name_off, name_len); |
d5b4c0dd MH |
3174 | } |
3175 | ||
3176 | break; | |
3177 | } | |
3178 | ||
3179 | case LF_UNION: | |
3180 | { | |
3181 | struct lf_union *un = (struct lf_union *) data; | |
fdf591c4 MH |
3182 | uint16_t prop, num_bytes; |
3183 | size_t name_len, name_off; | |
d5b4c0dd MH |
3184 | |
3185 | if (size < offsetof (struct lf_union, name)) | |
3186 | { | |
3187 | einfo (_("%P: warning: truncated CodeView type record" | |
3188 | " LF_UNION\n")); | |
3189 | return false; | |
3190 | } | |
3191 | ||
3192 | if (!remap_type (&un->field_list, map, type_num, num_types)) | |
3193 | return false; | |
3194 | ||
fdf591c4 MH |
3195 | name_off = offsetof (struct lf_union, name); |
3196 | ||
3197 | num_bytes = bfd_getl16 (&un->length); | |
3198 | ||
3199 | /* If num_bytes >= 0x8000, actual value follows. */ | |
3200 | if (num_bytes >= 0x8000) | |
3201 | { | |
3202 | unsigned int param_len = extended_value_len (num_bytes); | |
3203 | ||
3204 | if (param_len == 0) | |
3205 | { | |
3206 | einfo (_("%P: warning: unhandled type %v within" | |
3207 | " LF_UNION\n"), num_bytes); | |
3208 | return false; | |
3209 | } | |
3210 | ||
3211 | name_off += param_len; | |
3212 | ||
3213 | if (size < name_off) | |
3214 | { | |
3215 | einfo (_("%P: warning: truncated CodeView type record" | |
3216 | " LF_UNION\n")); | |
3217 | return false; | |
3218 | } | |
3219 | } | |
3220 | ||
3221 | name_len = strnlen ((char *) un + name_off, size - name_off); | |
d5b4c0dd | 3222 | |
fdf591c4 | 3223 | if (name_len == size - name_off) |
d5b4c0dd MH |
3224 | { |
3225 | einfo (_("%P: warning: name for LF_UNION has no" | |
3226 | " terminating zero\n")); | |
3227 | return false; | |
3228 | } | |
3229 | ||
3230 | prop = bfd_getl16 (&un->properties); | |
3231 | ||
3232 | if (prop & CV_PROP_HAS_UNIQUE_NAME) | |
3233 | { | |
3234 | /* Structure has another name following first one. */ | |
3235 | ||
fdf591c4 | 3236 | size_t len = name_off + name_len + 1; |
d5b4c0dd MH |
3237 | size_t unique_name_len; |
3238 | ||
fdf591c4 MH |
3239 | unique_name_len = strnlen ((char *) un + name_off + name_len + 1, |
3240 | size - len); | |
d5b4c0dd MH |
3241 | |
3242 | if (unique_name_len == size - len) | |
3243 | { | |
3244 | einfo (_("%P: warning: unique name for LF_UNION has" | |
3245 | " no terminating zero\n")); | |
3246 | return false; | |
3247 | } | |
3248 | } | |
3249 | ||
3250 | if (!(prop & (CV_PROP_FORWARD_REF | CV_PROP_SCOPED)) | |
fdf591c4 | 3251 | && !is_name_anonymous ((char *) un + name_off, name_len)) |
d5b4c0dd MH |
3252 | { |
3253 | other_hash = true; | |
fdf591c4 | 3254 | cv_hash = crc32 ((uint8_t *) un + name_off, name_len); |
d5b4c0dd MH |
3255 | } |
3256 | ||
3257 | break; | |
3258 | } | |
3259 | ||
3260 | case LF_ENUM: | |
3261 | { | |
3262 | struct lf_enum *en = (struct lf_enum *) data; | |
3263 | uint16_t prop; | |
3264 | size_t name_len; | |
3265 | ||
3266 | if (size < offsetof (struct lf_enum, name)) | |
3267 | { | |
3268 | einfo (_("%P: warning: truncated CodeView type record" | |
3269 | " LF_ENUM\n")); | |
3270 | return false; | |
3271 | } | |
3272 | ||
3273 | if (!remap_type (&en->underlying_type, map, type_num, num_types)) | |
3274 | return false; | |
3275 | ||
3276 | if (!remap_type (&en->field_list, map, type_num, num_types)) | |
3277 | return false; | |
3278 | ||
3279 | name_len = strnlen (en->name, size - offsetof (struct lf_enum, name)); | |
3280 | ||
3281 | if (name_len == size - offsetof (struct lf_enum, name)) | |
3282 | { | |
3283 | einfo (_("%P: warning: name for LF_ENUM has no" | |
3284 | " terminating zero\n")); | |
3285 | return false; | |
3286 | } | |
3287 | ||
3288 | prop = bfd_getl16 (&en->properties); | |
3289 | ||
3290 | if (prop & CV_PROP_HAS_UNIQUE_NAME) | |
3291 | { | |
3292 | /* Structure has another name following first one. */ | |
3293 | ||
3294 | size_t len = offsetof (struct lf_enum, name) + name_len + 1; | |
3295 | size_t unique_name_len; | |
3296 | ||
3297 | unique_name_len = strnlen (en->name + name_len + 1, size - len); | |
3298 | ||
3299 | if (unique_name_len == size - len) | |
3300 | { | |
3301 | einfo (_("%P: warning: unique name for LF_ENUM has" | |
3302 | " no terminating zero\n")); | |
3303 | return false; | |
3304 | } | |
3305 | } | |
3306 | ||
3307 | break; | |
3308 | } | |
3309 | ||
3310 | case LF_VTSHAPE: | |
3311 | /* Does not reference any types, nothing to be done. */ | |
3312 | break; | |
3313 | ||
5c9e42e0 MH |
3314 | case LF_VFTABLE: |
3315 | { | |
3316 | struct lf_vftable *vft = (struct lf_vftable *) data; | |
3317 | ||
3318 | if (size < offsetof (struct lf_vftable, names)) | |
3319 | { | |
3320 | einfo (_("%P: warning: truncated CodeView type record" | |
3321 | " LF_VFTABLE\n")); | |
3322 | return false; | |
3323 | } | |
3324 | ||
3325 | if (!remap_type (&vft->type, map, type_num, num_types)) | |
3326 | return false; | |
3327 | ||
3328 | if (!remap_type (&vft->base_vftable, map, type_num, num_types)) | |
3329 | return false; | |
3330 | ||
3331 | break; | |
3332 | } | |
3333 | ||
fca9096a MH |
3334 | case LF_STRING_ID: |
3335 | { | |
3336 | struct lf_string_id *str = (struct lf_string_id *) data; | |
3337 | size_t string_len; | |
3338 | ||
3339 | if (size < offsetof (struct lf_string_id, string)) | |
3340 | { | |
3341 | einfo (_("%P: warning: truncated CodeView type record" | |
3342 | " LF_STRING_ID\n")); | |
3343 | return false; | |
3344 | } | |
3345 | ||
3346 | if (!remap_type (&str->substring, map, type_num, num_types)) | |
3347 | return false; | |
3348 | ||
3349 | string_len = strnlen (str->string, | |
3350 | size - offsetof (struct lf_string_id, string)); | |
3351 | ||
3352 | if (string_len == size - offsetof (struct lf_string_id, string)) | |
3353 | { | |
3354 | einfo (_("%P: warning: string for LF_STRING_ID has no" | |
3355 | " terminating zero\n")); | |
3356 | return false; | |
3357 | } | |
3358 | ||
3359 | ipi = true; | |
3360 | ||
3361 | break; | |
3362 | } | |
3363 | ||
3364 | case LF_SUBSTR_LIST: | |
3365 | { | |
3366 | uint32_t num_entries; | |
3367 | struct lf_arglist *ssl = (struct lf_arglist *) data; | |
3368 | ||
3369 | if (size < offsetof (struct lf_arglist, args)) | |
3370 | { | |
3371 | einfo (_("%P: warning: truncated CodeView type record" | |
3372 | " LF_SUBSTR_LIST\n")); | |
3373 | return false; | |
3374 | } | |
3375 | ||
3376 | num_entries = bfd_getl32 (&ssl->num_entries); | |
3377 | ||
3378 | if (size < offsetof (struct lf_arglist, args) | |
3379 | + (num_entries * sizeof (uint32_t))) | |
3380 | { | |
3381 | einfo (_("%P: warning: truncated CodeView type record" | |
3382 | " LF_SUBSTR_LIST\n")); | |
3383 | return false; | |
3384 | } | |
3385 | ||
3386 | for (uint32_t i = 0; i < num_entries; i++) | |
3387 | { | |
3388 | if (!remap_type (&ssl->args[i], map, type_num, num_types)) | |
3389 | return false; | |
3390 | } | |
3391 | ||
3392 | ipi = true; | |
3393 | ||
3394 | break; | |
3395 | } | |
3396 | ||
3397 | case LF_BUILDINFO: | |
3398 | { | |
3399 | uint16_t num_entries; | |
3400 | struct lf_build_info *bi = (struct lf_build_info *) data; | |
3401 | ||
3402 | if (size < offsetof (struct lf_build_info, strings)) | |
3403 | { | |
3404 | einfo (_("%P: warning: truncated CodeView type record" | |
3405 | " LF_BUILDINFO\n")); | |
3406 | return false; | |
3407 | } | |
3408 | ||
3409 | num_entries = bfd_getl16 (&bi->count); | |
3410 | ||
3411 | if (size < offsetof (struct lf_build_info, strings) | |
3412 | + (num_entries * sizeof (uint32_t))) | |
3413 | { | |
3414 | einfo (_("%P: warning: truncated CodeView type record" | |
3415 | " LF_BUILDINFO\n")); | |
3416 | return false; | |
3417 | } | |
3418 | ||
3419 | for (uint32_t i = 0; i < num_entries; i++) | |
3420 | { | |
3421 | if (!remap_type (&bi->strings[i], map, type_num, num_types)) | |
3422 | return false; | |
3423 | } | |
3424 | ||
3425 | ipi = true; | |
3426 | ||
3427 | break; | |
3428 | } | |
3429 | ||
3430 | case LF_FUNC_ID: | |
3431 | { | |
3432 | struct lf_func_id *func = (struct lf_func_id *) data; | |
3433 | size_t name_len; | |
3434 | ||
3435 | if (size < offsetof (struct lf_func_id, name)) | |
3436 | { | |
3437 | einfo (_("%P: warning: truncated CodeView type record" | |
3438 | " LF_FUNC_ID\n")); | |
3439 | return false; | |
3440 | } | |
3441 | ||
3442 | if (!remap_type (&func->parent_scope, map, type_num, num_types)) | |
3443 | return false; | |
3444 | ||
3445 | if (!remap_type (&func->function_type, map, type_num, num_types)) | |
3446 | return false; | |
3447 | ||
3448 | name_len = strnlen (func->name, | |
3449 | size - offsetof (struct lf_func_id, name)); | |
3450 | ||
3451 | if (name_len == size - offsetof (struct lf_func_id, name)) | |
3452 | { | |
3453 | einfo (_("%P: warning: string for LF_FUNC_ID has no" | |
3454 | " terminating zero\n")); | |
3455 | return false; | |
3456 | } | |
3457 | ||
3458 | ipi = true; | |
3459 | ||
3460 | break; | |
3461 | } | |
3462 | ||
3463 | case LF_MFUNC_ID: | |
3464 | { | |
3465 | struct lf_mfunc_id *mfunc = (struct lf_mfunc_id *) data; | |
3466 | size_t name_len; | |
3467 | ||
3468 | if (size < offsetof (struct lf_mfunc_id, name)) | |
3469 | { | |
3470 | einfo (_("%P: warning: truncated CodeView type record" | |
3471 | " LF_MFUNC_ID\n")); | |
3472 | return false; | |
3473 | } | |
3474 | ||
3475 | if (!remap_type (&mfunc->parent_type, map, type_num, num_types)) | |
3476 | return false; | |
3477 | ||
3478 | if (!remap_type (&mfunc->function_type, map, type_num, num_types)) | |
3479 | return false; | |
3480 | ||
3481 | name_len = strnlen (mfunc->name, | |
3482 | size - offsetof (struct lf_mfunc_id, name)); | |
3483 | ||
3484 | if (name_len == size - offsetof (struct lf_mfunc_id, name)) | |
3485 | { | |
3486 | einfo (_("%P: warning: string for LF_MFUNC_ID has no" | |
3487 | " terminating zero\n")); | |
3488 | return false; | |
3489 | } | |
3490 | ||
3491 | ipi = true; | |
3492 | ||
3493 | break; | |
3494 | } | |
3495 | ||
81784004 MH |
3496 | case LF_UDT_SRC_LINE: |
3497 | return handle_udt_src_line (data, size, map, type_num, num_types, | |
3498 | ids, mod_num, strings); | |
3499 | ||
d5b4c0dd MH |
3500 | default: |
3501 | einfo (_("%P: warning: unrecognized CodeView type %v\n"), type); | |
3502 | return false; | |
3503 | } | |
3504 | ||
3505 | hash = iterative_hash (data, size, 0); | |
3506 | ||
fca9096a MH |
3507 | t = ipi ? ids : types; |
3508 | ||
3509 | slot = htab_find_slot_with_hash (t->hashmap, data, hash, INSERT); | |
d5b4c0dd MH |
3510 | if (!slot) |
3511 | return false; | |
3512 | ||
3513 | if (!*slot) /* new entry */ | |
3514 | { | |
3515 | struct type_entry *e; | |
3516 | ||
3517 | *slot = xmalloc (offsetof (struct type_entry, data) + size); | |
3518 | ||
3519 | e = (struct type_entry *) *slot; | |
3520 | ||
3521 | e->next = NULL; | |
fca9096a | 3522 | e->index = t->num_types; |
d5b4c0dd MH |
3523 | |
3524 | if (other_hash) | |
3525 | e->cv_hash = cv_hash; | |
3526 | else | |
3527 | e->cv_hash = crc32 (data, size); | |
3528 | ||
81784004 MH |
3529 | e->has_udt_src_line = false; |
3530 | ||
d5b4c0dd MH |
3531 | memcpy (e->data, data, size); |
3532 | ||
fca9096a MH |
3533 | if (t->last) |
3534 | t->last->next = e; | |
d5b4c0dd | 3535 | else |
fca9096a | 3536 | t->first = e; |
d5b4c0dd | 3537 | |
fca9096a | 3538 | t->last = e; |
d5b4c0dd MH |
3539 | |
3540 | map[type_num] = e; | |
3541 | ||
fca9096a | 3542 | t->num_types++; |
d5b4c0dd MH |
3543 | } |
3544 | else /* duplicate */ | |
3545 | { | |
3546 | map[type_num] = (struct type_entry *) *slot; | |
3547 | } | |
3548 | ||
3549 | return true; | |
3550 | } | |
3551 | ||
3552 | /* Parse the .debug$T section of a module, and pass any type definitions | |
3553 | found to handle_type. */ | |
3554 | static bool | |
fca9096a | 3555 | handle_debugt_section (asection *s, bfd *mod, struct types *types, |
81784004 | 3556 | struct types *ids, uint16_t mod_num, |
81814b6f MH |
3557 | struct string_table *strings, |
3558 | struct type_entry ***map, uint32_t *num_types) | |
d5b4c0dd MH |
3559 | { |
3560 | bfd_byte *data = NULL; | |
3561 | size_t off; | |
d5b4c0dd MH |
3562 | uint32_t type_num; |
3563 | ||
3564 | if (!bfd_get_full_section_contents (mod, s, &data)) | |
3565 | return false; | |
3566 | ||
3567 | if (!data) | |
3568 | return false; | |
3569 | ||
3570 | if (bfd_getl32 (data) != CV_SIGNATURE_C13) | |
3571 | { | |
3572 | free (data); | |
3573 | return true; | |
3574 | } | |
3575 | ||
3576 | off = sizeof (uint32_t); | |
3577 | ||
3578 | while (off + sizeof (uint16_t) <= s->size) | |
3579 | { | |
3580 | uint16_t size; | |
3581 | ||
3582 | size = bfd_getl16 (data + off); | |
3583 | off += sizeof (uint16_t); | |
3584 | ||
3585 | if (size + off > s->size || size <= sizeof (uint16_t)) | |
3586 | { | |
3587 | free (data); | |
3588 | bfd_set_error (bfd_error_bad_value); | |
3589 | return false; | |
3590 | } | |
3591 | ||
81814b6f | 3592 | (*num_types)++; |
d5b4c0dd MH |
3593 | off += size; |
3594 | } | |
3595 | ||
81814b6f | 3596 | if (*num_types == 0) |
d5b4c0dd MH |
3597 | { |
3598 | free (data); | |
3599 | return true; | |
3600 | } | |
3601 | ||
81814b6f | 3602 | *map = xcalloc (*num_types, sizeof (struct type_entry *)); |
d5b4c0dd MH |
3603 | |
3604 | off = sizeof (uint32_t); | |
3605 | type_num = 0; | |
3606 | ||
3607 | while (off + sizeof (uint16_t) <= s->size) | |
3608 | { | |
3609 | uint16_t size; | |
3610 | ||
3611 | size = bfd_getl16 (data + off); | |
3612 | ||
81814b6f | 3613 | if (!handle_type (data + off, *map, type_num, *num_types, types, ids, |
81784004 | 3614 | mod_num, strings)) |
d5b4c0dd MH |
3615 | { |
3616 | free (data); | |
81814b6f | 3617 | free (*map); |
d5b4c0dd MH |
3618 | bfd_set_error (bfd_error_bad_value); |
3619 | return false; | |
3620 | } | |
3621 | ||
3622 | off += sizeof (uint16_t) + size; | |
3623 | type_num++; | |
3624 | } | |
3625 | ||
3626 | free (data); | |
d5b4c0dd MH |
3627 | |
3628 | return true; | |
3629 | } | |
3630 | ||
8d25f5ef MH |
3631 | /* Return the CodeView constant for the selected architecture. */ |
3632 | static uint16_t | |
3633 | target_processor (bfd *abfd) | |
3634 | { | |
9a02fbd1 MH |
3635 | switch (abfd->arch_info->arch) |
3636 | { | |
3637 | case bfd_arch_i386: | |
3638 | if (abfd->arch_info->mach & bfd_mach_x86_64) | |
3639 | return CV_CFL_X64; | |
3640 | else | |
3641 | return CV_CFL_80386; | |
8d25f5ef | 3642 | |
9a02fbd1 MH |
3643 | case bfd_arch_aarch64: |
3644 | return CV_CFL_ARM64; | |
3645 | ||
3646 | default: | |
3647 | return 0; | |
3648 | } | |
8d25f5ef MH |
3649 | } |
3650 | ||
3651 | /* Create the symbols that go in "* Linker *", the dummy module created | |
3652 | for the linker itself. */ | |
3653 | static bool | |
3654 | create_linker_symbols (bfd *abfd, uint8_t **syms, uint32_t *sym_byte_size, | |
3655 | const char *pdb_name) | |
3656 | { | |
3657 | uint8_t *ptr; | |
3658 | struct objname *name; | |
3659 | struct compile3 *comp; | |
3660 | struct envblock *env; | |
3661 | size_t padding1, padding2, env_size; | |
3662 | char *cwdval, *exeval, *pdbval; | |
3663 | ||
3664 | /* extra NUL for padding */ | |
3665 | static const char linker_fn[] = "* Linker *\0"; | |
3666 | static const char linker_name[] = "GNU LD " VERSION; | |
3667 | ||
3668 | static const char cwd[] = "cwd"; | |
3669 | static const char exe[] = "exe"; | |
3670 | static const char pdb[] = "pdb"; | |
3671 | ||
3672 | cwdval = getcwd (NULL, 0); | |
3673 | if (!cwdval) | |
3674 | { | |
3675 | einfo (_("%P: warning: unable to get working directory\n")); | |
3676 | return false; | |
3677 | } | |
3678 | ||
3679 | exeval = lrealpath (program_name); | |
3680 | ||
3681 | if (!exeval) | |
3682 | { | |
3683 | einfo (_("%P: warning: unable to get program name\n")); | |
3684 | free (cwdval); | |
3685 | return false; | |
3686 | } | |
3687 | ||
3688 | pdbval = lrealpath (pdb_name); | |
3689 | ||
3690 | if (!pdbval) | |
3691 | { | |
3692 | einfo (_("%P: warning: unable to get full path to PDB\n")); | |
3693 | free (exeval); | |
3694 | free (cwdval); | |
3695 | return false; | |
3696 | } | |
3697 | ||
3698 | *sym_byte_size += offsetof (struct objname, name) + sizeof (linker_fn); | |
3699 | *sym_byte_size += offsetof (struct compile3, compiler) + sizeof (linker_name); | |
3700 | ||
3701 | if (*sym_byte_size % 4) | |
3702 | padding1 = 4 - (*sym_byte_size % 4); | |
3703 | else | |
3704 | padding1 = 0; | |
3705 | ||
3706 | *sym_byte_size += padding1; | |
3707 | ||
3708 | env_size = offsetof (struct envblock, strings); | |
3709 | env_size += sizeof (cwd); | |
3710 | env_size += strlen (cwdval) + 1; | |
3711 | env_size += sizeof (exe); | |
3712 | env_size += strlen (exeval) + 1; | |
3713 | env_size += sizeof (pdb); | |
3714 | env_size += strlen (pdbval) + 1; | |
3715 | ||
3716 | if (env_size % 4) | |
3717 | padding2 = 4 - (env_size % 4); | |
3718 | else | |
3719 | padding2 = 0; | |
3720 | ||
3721 | env_size += padding2; | |
3722 | ||
3723 | *sym_byte_size += env_size; | |
3724 | ||
3725 | *syms = xmalloc (*sym_byte_size); | |
3726 | ptr = *syms; | |
3727 | ||
3728 | /* Write S_OBJNAME */ | |
3729 | ||
3730 | name = (struct objname *) ptr; | |
3731 | bfd_putl16 (offsetof (struct objname, name) | |
3732 | + sizeof (linker_fn) - sizeof (uint16_t), &name->size); | |
3733 | bfd_putl16 (S_OBJNAME, &name->kind); | |
3734 | bfd_putl32 (0, &name->signature); | |
3735 | memcpy (name->name, linker_fn, sizeof (linker_fn)); | |
3736 | ||
3737 | ptr += offsetof (struct objname, name) + sizeof (linker_fn); | |
3738 | ||
3739 | /* Write S_COMPILE3 */ | |
3740 | ||
3741 | comp = (struct compile3 *) ptr; | |
3742 | ||
3743 | bfd_putl16 (offsetof (struct compile3, compiler) + sizeof (linker_name) | |
3744 | + padding1 - sizeof (uint16_t), &comp->size); | |
3745 | bfd_putl16 (S_COMPILE3, &comp->kind); | |
3746 | bfd_putl32 (CV_CFL_LINK, &comp->flags); | |
3747 | bfd_putl16 (target_processor (abfd), &comp->machine); | |
3748 | bfd_putl16 (0, &comp->frontend_major); | |
3749 | bfd_putl16 (0, &comp->frontend_minor); | |
3750 | bfd_putl16 (0, &comp->frontend_build); | |
3751 | bfd_putl16 (0, &comp->frontend_qfe); | |
3752 | bfd_putl16 (0, &comp->backend_major); | |
3753 | bfd_putl16 (0, &comp->backend_minor); | |
3754 | bfd_putl16 (0, &comp->backend_build); | |
3755 | bfd_putl16 (0, &comp->backend_qfe); | |
3756 | memcpy (comp->compiler, linker_name, sizeof (linker_name)); | |
3757 | ||
3758 | memset (comp->compiler + sizeof (linker_name), 0, padding1); | |
3759 | ||
3760 | ptr += offsetof (struct compile3, compiler) + sizeof (linker_name) + padding1; | |
3761 | ||
3762 | /* Write S_ENVBLOCK */ | |
3763 | ||
3764 | env = (struct envblock *) ptr; | |
3765 | ||
3766 | bfd_putl16 (env_size - sizeof (uint16_t), &env->size); | |
3767 | bfd_putl16 (S_ENVBLOCK, &env->kind); | |
3768 | env->flags = 0; | |
3769 | ||
3770 | ptr += offsetof (struct envblock, strings); | |
3771 | ||
3772 | memcpy (ptr, cwd, sizeof (cwd)); | |
3773 | ptr += sizeof (cwd); | |
3774 | memcpy (ptr, cwdval, strlen (cwdval) + 1); | |
3775 | ptr += strlen (cwdval) + 1; | |
3776 | ||
3777 | memcpy (ptr, exe, sizeof (exe)); | |
3778 | ptr += sizeof (exe); | |
3779 | memcpy (ptr, exeval, strlen (exeval) + 1); | |
3780 | ptr += strlen (exeval) + 1; | |
3781 | ||
3782 | memcpy (ptr, pdb, sizeof (pdb)); | |
3783 | ptr += sizeof (pdb); | |
3784 | memcpy (ptr, pdbval, strlen (pdbval) + 1); | |
3785 | ptr += strlen (pdbval) + 1; | |
3786 | ||
3787 | /* Microsoft's LINK also includes "cmd", the command-line options passed | |
3788 | to the linker, but unfortunately we don't have access to argc and argv | |
3789 | at this stage. */ | |
3790 | ||
3791 | memset (ptr, 0, padding2); | |
3792 | ||
3793 | free (pdbval); | |
3794 | free (exeval); | |
3795 | free (cwdval); | |
3796 | ||
3797 | return true; | |
3798 | } | |
3799 | ||
5967ca92 MH |
3800 | /* Populate the module stream, which consists of the transformed .debug$S |
3801 | data for each object file. */ | |
3802 | static bool | |
f559276d | 3803 | populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, |
803561cb MH |
3804 | struct string_table *strings, |
3805 | uint32_t *c13_info_size, | |
598c1ae6 | 3806 | struct mod_source_files *mod_source, |
fca9096a | 3807 | bfd *abfd, struct types *types, |
81814b6f | 3808 | struct types *ids, uint16_t mod_num, |
8d25f5ef MH |
3809 | bfd *sym_rec_stream, struct globals *glob, |
3810 | const char *pdb_name) | |
5967ca92 MH |
3811 | { |
3812 | uint8_t int_buf[sizeof (uint32_t)]; | |
803561cb | 3813 | uint8_t *c13_info = NULL; |
81814b6f | 3814 | uint8_t *syms = NULL; |
5967ca92 | 3815 | |
81814b6f | 3816 | *sym_byte_size = 0; |
803561cb | 3817 | *c13_info_size = 0; |
5967ca92 | 3818 | |
8d25f5ef | 3819 | if (!strcmp (bfd_get_filename (mod), "dll stuff")) |
f559276d | 3820 | { |
8d25f5ef MH |
3821 | if (!create_linker_symbols (mod, &syms, sym_byte_size, pdb_name)) |
3822 | return false; | |
3823 | } | |
3824 | else | |
3825 | { | |
3826 | struct type_entry **map = NULL; | |
3827 | uint32_t num_types = 0; | |
3828 | ||
3829 | /* Process .debug$T section. */ | |
3830 | ||
3831 | for (asection *s = mod->sections; s; s = s->next) | |
f559276d | 3832 | { |
8d25f5ef | 3833 | if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) |
803561cb | 3834 | { |
8d25f5ef MH |
3835 | if (!handle_debugt_section (s, mod, types, ids, mod_num, strings, |
3836 | &map, &num_types)) | |
3837 | { | |
3838 | free (mod_source->files); | |
3839 | return false; | |
3840 | } | |
81814b6f | 3841 | |
8d25f5ef MH |
3842 | break; |
3843 | } | |
f559276d | 3844 | } |
81814b6f | 3845 | |
8d25f5ef | 3846 | /* Process .debug$S section(s). */ |
81814b6f | 3847 | |
8d25f5ef | 3848 | for (asection *s = mod->sections; s; s = s->next) |
d5b4c0dd | 3849 | { |
8d25f5ef | 3850 | if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) |
d5b4c0dd | 3851 | { |
8d25f5ef MH |
3852 | if (!handle_debugs_section (s, mod, strings, &c13_info, |
3853 | c13_info_size, mod_source, abfd, | |
3854 | &syms, sym_byte_size, map, num_types, | |
3855 | sym_rec_stream, glob, mod_num)) | |
3856 | { | |
3857 | free (c13_info); | |
3858 | free (syms); | |
3859 | free (mod_source->files); | |
3860 | free (map); | |
3861 | return false; | |
3862 | } | |
d5b4c0dd MH |
3863 | } |
3864 | } | |
f559276d | 3865 | |
8d25f5ef MH |
3866 | free (map); |
3867 | } | |
81814b6f | 3868 | |
5967ca92 MH |
3869 | /* Write the signature. */ |
3870 | ||
3871 | bfd_putl32 (CV_SIGNATURE_C13, int_buf); | |
3872 | ||
226f9f4f | 3873 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) |
803561cb MH |
3874 | { |
3875 | free (c13_info); | |
81814b6f | 3876 | free (syms); |
803561cb MH |
3877 | return false; |
3878 | } | |
3879 | ||
81814b6f MH |
3880 | if (syms) |
3881 | { | |
226f9f4f | 3882 | if (bfd_write (syms, *sym_byte_size, stream) != *sym_byte_size) |
81814b6f MH |
3883 | { |
3884 | free (c13_info); | |
3885 | free (syms); | |
3886 | return false; | |
3887 | } | |
3888 | ||
3889 | free (syms); | |
3890 | } | |
3891 | ||
803561cb MH |
3892 | if (c13_info) |
3893 | { | |
226f9f4f | 3894 | if (bfd_write (c13_info, *c13_info_size, stream) != *c13_info_size) |
803561cb MH |
3895 | { |
3896 | free (c13_info); | |
3897 | return false; | |
3898 | } | |
3899 | ||
3900 | free (c13_info); | |
3901 | } | |
5967ca92 MH |
3902 | |
3903 | /* Write the global refs size. */ | |
3904 | ||
3905 | bfd_putl32 (0, int_buf); | |
3906 | ||
226f9f4f | 3907 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) |
5967ca92 MH |
3908 | return false; |
3909 | ||
3910 | return true; | |
3911 | } | |
3912 | ||
3913 | /* Create the module info substream within the DBI. */ | |
3914 | static bool | |
3915 | create_module_info_substream (bfd *abfd, bfd *pdb, void **data, | |
803561cb | 3916 | uint32_t *size, struct string_table *strings, |
d5b4c0dd | 3917 | struct source_files_info *source, |
81814b6f | 3918 | struct types *types, struct types *ids, |
8d25f5ef MH |
3919 | bfd *sym_rec_stream, struct globals *glob, |
3920 | const char *pdb_name) | |
5967ca92 MH |
3921 | { |
3922 | uint8_t *ptr; | |
803561cb | 3923 | unsigned int mod_num; |
5967ca92 MH |
3924 | |
3925 | static const char linker_fn[] = "* Linker *"; | |
3926 | ||
3927 | *size = 0; | |
3928 | ||
3929 | for (bfd *in = coff_data (abfd)->link_info->input_bfds; in; | |
3930 | in = in->link.next) | |
3931 | { | |
3932 | size_t len = sizeof (struct module_info); | |
3933 | ||
3934 | if (!strcmp (bfd_get_filename (in), "dll stuff")) | |
3935 | { | |
3936 | len += sizeof (linker_fn); /* Object name. */ | |
3937 | len++; /* Empty module name. */ | |
3938 | } | |
3939 | else if (in->my_archive) | |
3940 | { | |
3941 | char *name = lrealpath (bfd_get_filename (in)); | |
3942 | ||
3943 | len += strlen (name) + 1; /* Object name. */ | |
3944 | ||
3945 | free (name); | |
3946 | ||
3947 | name = lrealpath (bfd_get_filename (in->my_archive)); | |
3948 | ||
3949 | len += strlen (name) + 1; /* Archive name. */ | |
3950 | ||
3951 | free (name); | |
3952 | } | |
3953 | else | |
3954 | { | |
3955 | char *name = lrealpath (bfd_get_filename (in)); | |
3956 | size_t name_len = strlen (name) + 1; | |
3957 | ||
3958 | len += name_len; /* Object name. */ | |
3959 | len += name_len; /* And again as the archive name. */ | |
3960 | ||
3961 | free (name); | |
3962 | } | |
3963 | ||
3964 | if (len % 4) | |
3965 | len += 4 - (len % 4); | |
3966 | ||
3967 | *size += len; | |
803561cb MH |
3968 | |
3969 | source->mod_count++; | |
5967ca92 MH |
3970 | } |
3971 | ||
3972 | *data = xmalloc (*size); | |
3973 | ||
3974 | ptr = *data; | |
3975 | ||
803561cb MH |
3976 | source->mods = xmalloc (source->mod_count |
3977 | * sizeof (struct mod_source_files)); | |
3978 | memset (source->mods, 0, | |
3979 | source->mod_count * sizeof (struct mod_source_files)); | |
3980 | ||
3981 | mod_num = 0; | |
3982 | ||
5967ca92 MH |
3983 | for (bfd *in = coff_data (abfd)->link_info->input_bfds; in; |
3984 | in = in->link.next) | |
3985 | { | |
3986 | struct module_info *mod = (struct module_info *) ptr; | |
3987 | uint16_t stream_num; | |
3988 | bfd *stream; | |
803561cb | 3989 | uint32_t sym_byte_size, c13_info_size; |
5967ca92 MH |
3990 | uint8_t *start = ptr; |
3991 | ||
3992 | stream = add_stream (pdb, NULL, &stream_num); | |
3993 | ||
3994 | if (!stream) | |
3995 | { | |
803561cb MH |
3996 | for (unsigned int i = 0; i < source->mod_count; i++) |
3997 | { | |
3998 | free (source->mods[i].files); | |
3999 | } | |
4000 | ||
4001 | free (source->mods); | |
5967ca92 MH |
4002 | free (*data); |
4003 | return false; | |
4004 | } | |
4005 | ||
f559276d | 4006 | if (!populate_module_stream (stream, in, &sym_byte_size, |
803561cb | 4007 | strings, &c13_info_size, |
d5b4c0dd | 4008 | &source->mods[mod_num], abfd, |
81814b6f | 4009 | types, ids, mod_num, |
8d25f5ef | 4010 | sym_rec_stream, glob, pdb_name)) |
5967ca92 | 4011 | { |
803561cb MH |
4012 | for (unsigned int i = 0; i < source->mod_count; i++) |
4013 | { | |
4014 | free (source->mods[i].files); | |
4015 | } | |
4016 | ||
4017 | free (source->mods); | |
5967ca92 MH |
4018 | free (*data); |
4019 | return false; | |
4020 | } | |
4021 | ||
4022 | bfd_putl32 (0, &mod->unused1); | |
4023 | ||
4024 | /* These are dummy values - MSVC copies the first section contribution | |
4025 | entry here, but doesn't seem to use it for anything. */ | |
4026 | bfd_putl16 (0xffff, &mod->sc.section); | |
4027 | bfd_putl16 (0, &mod->sc.padding1); | |
4028 | bfd_putl32 (0, &mod->sc.offset); | |
4029 | bfd_putl32 (0xffffffff, &mod->sc.size); | |
4030 | bfd_putl32 (0, &mod->sc.characteristics); | |
4031 | bfd_putl16 (0xffff, &mod->sc.module_index); | |
4032 | bfd_putl16 (0, &mod->sc.padding2); | |
4033 | bfd_putl32 (0, &mod->sc.data_crc); | |
4034 | bfd_putl32 (0, &mod->sc.reloc_crc); | |
4035 | ||
4036 | bfd_putl16 (0, &mod->flags); | |
4037 | bfd_putl16 (stream_num, &mod->module_sym_stream); | |
81814b6f | 4038 | bfd_putl32 (sizeof (uint32_t) + sym_byte_size, &mod->sym_byte_size); |
5967ca92 | 4039 | bfd_putl32 (0, &mod->c11_byte_size); |
803561cb | 4040 | bfd_putl32 (c13_info_size, &mod->c13_byte_size); |
5967ca92 MH |
4041 | bfd_putl16 (0, &mod->source_file_count); |
4042 | bfd_putl16 (0, &mod->padding); | |
4043 | bfd_putl32 (0, &mod->unused2); | |
4044 | bfd_putl32 (0, &mod->source_file_name_index); | |
4045 | bfd_putl32 (0, &mod->pdb_file_path_name_index); | |
4046 | ||
4047 | ptr += sizeof (struct module_info); | |
4048 | ||
4049 | if (!strcmp (bfd_get_filename (in), "dll stuff")) | |
4050 | { | |
4051 | /* Object name. */ | |
4052 | memcpy (ptr, linker_fn, sizeof (linker_fn)); | |
4053 | ptr += sizeof (linker_fn); | |
4054 | ||
4055 | /* Empty module name. */ | |
4056 | *ptr = 0; | |
4057 | ptr++; | |
4058 | } | |
4059 | else if (in->my_archive) | |
4060 | { | |
4061 | char *name = lrealpath (bfd_get_filename (in)); | |
4062 | size_t name_len = strlen (name) + 1; | |
4063 | ||
4064 | /* Object name. */ | |
4065 | memcpy (ptr, name, name_len); | |
4066 | ptr += name_len; | |
4067 | ||
4068 | free (name); | |
4069 | ||
4070 | name = lrealpath (bfd_get_filename (in->my_archive)); | |
4071 | name_len = strlen (name) + 1; | |
4072 | ||
4073 | /* Archive name. */ | |
4074 | memcpy (ptr, name, name_len); | |
4075 | ptr += name_len; | |
4076 | ||
4077 | free (name); | |
4078 | } | |
4079 | else | |
4080 | { | |
4081 | char *name = lrealpath (bfd_get_filename (in)); | |
4082 | size_t name_len = strlen (name) + 1; | |
4083 | ||
4084 | /* Object name. */ | |
4085 | memcpy (ptr, name, name_len); | |
4086 | ptr += name_len; | |
4087 | ||
4088 | /* Object name again as archive name. */ | |
4089 | memcpy (ptr, name, name_len); | |
4090 | ptr += name_len; | |
4091 | ||
4092 | free (name); | |
4093 | } | |
4094 | ||
4095 | /* Pad to next four-byte boundary. */ | |
4096 | ||
4097 | if ((ptr - start) % 4) | |
4098 | { | |
4099 | memset (ptr, 0, 4 - ((ptr - start) % 4)); | |
4100 | ptr += 4 - ((ptr - start) % 4); | |
4101 | } | |
803561cb MH |
4102 | |
4103 | mod_num++; | |
5967ca92 MH |
4104 | } |
4105 | ||
4106 | return true; | |
4107 | } | |
4108 | ||
08827105 MH |
4109 | /* Return the index of a given output section. */ |
4110 | static uint16_t | |
4111 | find_section_number (bfd *abfd, asection *sect) | |
4112 | { | |
4113 | uint16_t i = 1; | |
4114 | ||
4115 | for (asection *s = abfd->sections; s; s = s->next) | |
4116 | { | |
4117 | if (s == sect) | |
4118 | return i; | |
4119 | ||
4120 | /* Empty sections aren't output. */ | |
4121 | if (s->size != 0) | |
4122 | i++; | |
4123 | } | |
4124 | ||
4125 | return 0; | |
4126 | } | |
4127 | ||
38395c77 MH |
4128 | /* Used as parameter to qsort, to sort section contributions by section and |
4129 | offset. */ | |
4130 | static int | |
4131 | section_contribs_compare (const void *p1, const void *p2) | |
4132 | { | |
4133 | const struct in_sc *sc1 = p1; | |
4134 | const struct in_sc *sc2 = p2; | |
4135 | ||
4136 | if (sc1->sect_num < sc2->sect_num) | |
4137 | return -1; | |
4138 | if (sc1->sect_num > sc2->sect_num) | |
4139 | return 1; | |
4140 | ||
4141 | if (sc1->s->output_offset < sc2->s->output_offset) | |
4142 | return -1; | |
4143 | if (sc1->s->output_offset > sc2->s->output_offset) | |
4144 | return 1; | |
4145 | ||
4146 | return 0; | |
4147 | } | |
4148 | ||
e2a1b0a0 MH |
4149 | /* Create the substream which maps addresses in the image file to locations |
4150 | in the original object files. */ | |
4151 | static bool | |
4152 | create_section_contrib_substream (bfd *abfd, void **data, uint32_t *size) | |
4153 | { | |
4154 | unsigned int num_sc = 0; | |
4155 | struct section_contribution *sc; | |
4156 | uint16_t mod_index; | |
4157 | char *sect_flags; | |
4158 | file_ptr offset; | |
38395c77 MH |
4159 | struct in_sc *sc_in, *sc2; |
4160 | uint32_t *ptr; | |
e2a1b0a0 MH |
4161 | |
4162 | for (bfd *in = coff_data (abfd)->link_info->input_bfds; in; | |
4163 | in = in->link.next) | |
4164 | { | |
4165 | for (asection *s = in->sections; s; s = s->next) | |
4166 | { | |
4167 | if (s->size == 0 || discarded_section (s)) | |
4168 | continue; | |
4169 | ||
4170 | num_sc++; | |
4171 | } | |
4172 | } | |
4173 | ||
4174 | *size = sizeof (uint32_t) + (num_sc * sizeof (struct section_contribution)); | |
4175 | *data = xmalloc (*size); | |
4176 | ||
4177 | bfd_putl32 (SECTION_CONTRIB_VERSION_60, *data); | |
4178 | ||
4179 | /* Read characteristics of outputted sections. */ | |
4180 | ||
4181 | sect_flags = xmalloc (sizeof (uint32_t) * abfd->section_count); | |
4182 | ||
4183 | offset = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); | |
4184 | offset += offsetof (struct external_scnhdr, s_flags); | |
4185 | ||
4186 | for (unsigned int i = 0; i < abfd->section_count; i++) | |
4187 | { | |
e416bd75 AM |
4188 | if (bfd_seek (abfd, offset, SEEK_SET) != 0 |
4189 | || bfd_read (sect_flags + (i * sizeof (uint32_t)), sizeof (uint32_t), | |
4190 | abfd) != sizeof (uint32_t)) | |
e2a1b0a0 MH |
4191 | { |
4192 | free (*data); | |
4193 | free (sect_flags); | |
4194 | return false; | |
4195 | } | |
4196 | ||
4197 | offset += sizeof (struct external_scnhdr); | |
4198 | } | |
4199 | ||
38395c77 MH |
4200 | /* Microsoft's DIA expects section contributions to be sorted by section |
4201 | number and offset, otherwise it will be unable to resolve line numbers. */ | |
4202 | ||
4203 | sc_in = xmalloc (num_sc * sizeof (* sc_in)); | |
4204 | sc2 = sc_in; | |
e2a1b0a0 MH |
4205 | |
4206 | mod_index = 0; | |
4207 | for (bfd *in = coff_data (abfd)->link_info->input_bfds; in; | |
4208 | in = in->link.next) | |
4209 | { | |
4210 | for (asection *s = in->sections; s; s = s->next) | |
4211 | { | |
e2a1b0a0 MH |
4212 | if (s->size == 0 || discarded_section (s)) |
4213 | continue; | |
4214 | ||
38395c77 MH |
4215 | sc2->s = s; |
4216 | sc2->sect_num = find_section_number (abfd, s->output_section); | |
4217 | sc2->mod_index = mod_index; | |
e2a1b0a0 | 4218 | |
38395c77 | 4219 | sc2++; |
e2a1b0a0 MH |
4220 | } |
4221 | ||
4222 | mod_index++; | |
4223 | } | |
4224 | ||
38395c77 MH |
4225 | qsort (sc_in, num_sc, sizeof (* sc_in), section_contribs_compare); |
4226 | ||
4227 | ptr = *data; | |
4228 | sc = (struct section_contribution *) (ptr + 1); /* Skip the version word. */ | |
4229 | ||
4230 | for (unsigned int i = 0; i < num_sc; i++) | |
4231 | { | |
4232 | memcpy (&sc->characteristics, | |
4233 | sect_flags + ((sc_in[i].sect_num - 1) * sizeof (uint32_t)), | |
4234 | sizeof (uint32_t)); | |
4235 | ||
4236 | bfd_putl16 (sc_in[i].sect_num, &sc->section); | |
4237 | bfd_putl16 (0, &sc->padding1); | |
4238 | bfd_putl32 (sc_in[i].s->output_offset, &sc->offset); | |
4239 | bfd_putl32 (sc_in[i].s->size, &sc->size); | |
4240 | bfd_putl16 (sc_in[i].mod_index, &sc->module_index); | |
4241 | bfd_putl16 (0, &sc->padding2); | |
4242 | bfd_putl32 (0, &sc->data_crc); | |
4243 | bfd_putl32 (0, &sc->reloc_crc); | |
4244 | ||
4245 | sc++; | |
4246 | } | |
4247 | ||
4248 | free (sc_in); | |
e2a1b0a0 MH |
4249 | free (sect_flags); |
4250 | ||
4251 | return true; | |
4252 | } | |
4253 | ||
803561cb MH |
4254 | /* The source info substream lives within the DBI stream, and lists the |
4255 | source files for each object file (i.e. it's derived from the | |
4256 | DEBUG_S_FILECHKSMS parts of the .debug$S sections). This is a bit | |
4257 | superfluous, as the filenames are also available in the C13 parts of | |
4258 | the module streams, but MSVC relies on it to work properly. */ | |
4259 | static void | |
4260 | create_source_info_substream (void **data, uint32_t *size, | |
4261 | struct source_files_info *source) | |
4262 | { | |
4263 | uint16_t dedupe_source_files_count = 0; | |
4264 | uint16_t source_files_count = 0; | |
4265 | uint32_t strings_len = 0; | |
4266 | uint8_t *ptr; | |
4267 | ||
4268 | /* Loop through the source files, marking unique filenames. The pointers | |
4269 | here are for entries in the main string table, and so have already | |
4270 | been deduplicated. */ | |
4271 | ||
4272 | for (uint16_t i = 0; i < source->mod_count; i++) | |
4273 | { | |
4274 | for (uint16_t j = 0; j < source->mods[i].files_count; j++) | |
4275 | { | |
4276 | if (source->mods[i].files[j]) | |
4277 | { | |
4278 | if (source->mods[i].files[j]->source_file_offset == 0xffffffff) | |
4279 | { | |
4280 | source->mods[i].files[j]->source_file_offset = strings_len; | |
4281 | strings_len += source->mods[i].files[j]->len + 1; | |
4282 | dedupe_source_files_count++; | |
4283 | } | |
4284 | ||
4285 | source_files_count++; | |
4286 | } | |
4287 | } | |
4288 | } | |
4289 | ||
4290 | *size = sizeof (uint16_t) + sizeof (uint16_t); | |
4291 | *size += (sizeof (uint16_t) + sizeof (uint16_t)) * source->mod_count; | |
4292 | *size += sizeof (uint32_t) * source_files_count; | |
4293 | *size += strings_len; | |
4294 | ||
4295 | *data = xmalloc (*size); | |
4296 | ||
4297 | ptr = (uint8_t *) *data; | |
4298 | ||
4299 | /* Write header (module count and source file count). */ | |
4300 | ||
4301 | bfd_putl16 (source->mod_count, ptr); | |
4302 | ptr += sizeof (uint16_t); | |
4303 | ||
4304 | bfd_putl16 (dedupe_source_files_count, ptr); | |
4305 | ptr += sizeof (uint16_t); | |
4306 | ||
4307 | /* Write "ModIndices". As the LLVM documentation puts it, "this array is | |
4308 | present, but does not appear to be useful". */ | |
4309 | ||
4310 | for (uint16_t i = 0; i < source->mod_count; i++) | |
4311 | { | |
4312 | bfd_putl16 (i, ptr); | |
4313 | ptr += sizeof (uint16_t); | |
4314 | } | |
4315 | ||
4316 | /* Write source file count for each module. */ | |
4317 | ||
4318 | for (uint16_t i = 0; i < source->mod_count; i++) | |
4319 | { | |
4320 | bfd_putl16 (source->mods[i].files_count, ptr); | |
4321 | ptr += sizeof (uint16_t); | |
4322 | } | |
4323 | ||
4324 | /* For each module, write the offsets within the string table | |
4325 | for each source file. */ | |
4326 | ||
4327 | for (uint16_t i = 0; i < source->mod_count; i++) | |
4328 | { | |
4329 | for (uint16_t j = 0; j < source->mods[i].files_count; j++) | |
4330 | { | |
4331 | if (source->mods[i].files[j]) | |
4332 | { | |
4333 | bfd_putl32 (source->mods[i].files[j]->source_file_offset, ptr); | |
4334 | ptr += sizeof (uint32_t); | |
4335 | } | |
4336 | } | |
4337 | } | |
4338 | ||
4339 | /* Write the string table. We set source_file_offset to a dummy value for | |
4340 | each entry we write, so we don't write duplicate filenames. */ | |
4341 | ||
4342 | for (uint16_t i = 0; i < source->mod_count; i++) | |
4343 | { | |
4344 | for (uint16_t j = 0; j < source->mods[i].files_count; j++) | |
4345 | { | |
4346 | if (source->mods[i].files[j] | |
4347 | && source->mods[i].files[j]->source_file_offset != 0xffffffff) | |
4348 | { | |
4349 | memcpy (ptr, source->mods[i].files[j]->s, | |
4350 | source->mods[i].files[j]->len); | |
4351 | ptr += source->mods[i].files[j]->len; | |
4352 | ||
4353 | *ptr = 0; | |
4354 | ptr++; | |
4355 | ||
4356 | source->mods[i].files[j]->source_file_offset = 0xffffffff; | |
4357 | } | |
4358 | } | |
4359 | } | |
4360 | } | |
4361 | ||
81814b6f MH |
4362 | /* Used as parameter to qsort, to sort globals by hash. */ |
4363 | static int | |
4364 | global_compare_hash (const void *s1, const void *s2) | |
4365 | { | |
4366 | const struct global *g1 = *(const struct global **) s1; | |
4367 | const struct global *g2 = *(const struct global **) s2; | |
4368 | ||
4369 | if (g1->hash < g2->hash) | |
4370 | return -1; | |
4371 | if (g1->hash > g2->hash) | |
4372 | return 1; | |
4373 | ||
4374 | return 0; | |
4375 | } | |
4376 | ||
4377 | /* Create the globals stream, which contains the unmangled symbol names. */ | |
4378 | static bool | |
4379 | create_globals_stream (bfd *pdb, struct globals *glob, uint16_t *stream_num) | |
4380 | { | |
4381 | bfd *stream; | |
4382 | struct globals_hash_header h; | |
4383 | uint32_t buckets_size, filled_buckets = 0; | |
4384 | struct global **sorted = NULL; | |
4385 | bool ret = false; | |
4386 | struct global *buckets[NUM_GLOBALS_HASH_BUCKETS]; | |
4387 | char int_buf[sizeof (uint32_t)]; | |
4388 | ||
4389 | stream = add_stream (pdb, NULL, stream_num); | |
4390 | if (!stream) | |
4391 | return false; | |
4392 | ||
4393 | memset (buckets, 0, sizeof (buckets)); | |
4394 | ||
4395 | if (glob->num_entries > 0) | |
4396 | { | |
4397 | struct global *g; | |
4398 | ||
4399 | /* Create an array of pointers, sorted by hash value. */ | |
4400 | ||
4401 | sorted = xmalloc (sizeof (struct global *) * glob->num_entries); | |
4402 | ||
4403 | g = glob->first; | |
4404 | for (unsigned int i = 0; i < glob->num_entries; i++) | |
4405 | { | |
4406 | sorted[i] = g; | |
4407 | g = g->next; | |
4408 | } | |
4409 | ||
4410 | qsort (sorted, glob->num_entries, sizeof (struct global *), | |
4411 | global_compare_hash); | |
4412 | ||
4413 | /* Populate the buckets. */ | |
4414 | ||
4415 | for (unsigned int i = 0; i < glob->num_entries; i++) | |
4416 | { | |
4417 | if (!buckets[sorted[i]->hash]) | |
4418 | { | |
4419 | buckets[sorted[i]->hash] = sorted[i]; | |
4420 | filled_buckets++; | |
4421 | } | |
4422 | ||
4423 | sorted[i]->index = i; | |
4424 | } | |
4425 | } | |
4426 | ||
4427 | buckets_size = NUM_GLOBALS_HASH_BUCKETS / 8; | |
4428 | buckets_size += sizeof (uint32_t); | |
4429 | buckets_size += filled_buckets * sizeof (uint32_t); | |
4430 | ||
4431 | bfd_putl32 (GLOBALS_HASH_SIGNATURE, &h.signature); | |
4432 | bfd_putl32 (GLOBALS_HASH_VERSION_70, &h.version); | |
4433 | bfd_putl32 (glob->num_entries * sizeof (struct hash_record), | |
4434 | &h.entries_size); | |
4435 | bfd_putl32 (buckets_size, &h.buckets_size); | |
4436 | ||
226f9f4f | 4437 | if (bfd_write (&h, sizeof (h), stream) != sizeof (h)) |
81814b6f MH |
4438 | return false; |
4439 | ||
4440 | /* Write hash entries, sorted by hash. */ | |
4441 | ||
4442 | for (unsigned int i = 0; i < glob->num_entries; i++) | |
4443 | { | |
4444 | struct hash_record hr; | |
4445 | ||
4446 | bfd_putl32 (sorted[i]->offset + 1, &hr.offset); | |
4447 | bfd_putl32 (sorted[i]->refcount, &hr.reference); | |
4448 | ||
226f9f4f | 4449 | if (bfd_write (&hr, sizeof (hr), stream) != sizeof (hr)) |
81814b6f MH |
4450 | goto end; |
4451 | } | |
4452 | ||
4453 | /* Write the bitmap for filled and unfilled buckets. */ | |
4454 | ||
4455 | for (unsigned int i = 0; i < NUM_GLOBALS_HASH_BUCKETS; i += 8) | |
4456 | { | |
4457 | uint8_t v = 0; | |
4458 | ||
4459 | for (unsigned int j = 0; j < 8; j++) | |
4460 | { | |
4461 | if (buckets[i + j]) | |
4462 | v |= 1 << j; | |
4463 | } | |
4464 | ||
226f9f4f | 4465 | if (bfd_write (&v, sizeof (v), stream) != sizeof (v)) |
81814b6f MH |
4466 | goto end; |
4467 | } | |
4468 | ||
4469 | /* Add a 4-byte gap. */ | |
4470 | ||
4471 | bfd_putl32 (0, int_buf); | |
4472 | ||
226f9f4f | 4473 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) |
81814b6f MH |
4474 | goto end; |
4475 | ||
4476 | /* Write the bucket offsets. */ | |
4477 | ||
4478 | for (unsigned int i = 0; i < NUM_GLOBALS_HASH_BUCKETS; i++) | |
4479 | { | |
4480 | if (buckets[i]) | |
4481 | { | |
4482 | /* 0xc is size of internal hash_record structure in | |
4483 | Microsoft's parser. */ | |
4484 | bfd_putl32 (buckets[i]->index * 0xc, int_buf); | |
4485 | ||
226f9f4f | 4486 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != |
81814b6f MH |
4487 | sizeof (uint32_t)) |
4488 | goto end; | |
4489 | } | |
4490 | } | |
4491 | ||
4492 | ret = true; | |
4493 | ||
4494 | end: | |
4495 | free (sorted); | |
4496 | ||
4497 | return ret; | |
4498 | } | |
4499 | ||
4500 | /* Hash an entry in the globals list. */ | |
4501 | static hashval_t | |
4502 | hash_global_entry (const void *p) | |
4503 | { | |
4504 | const struct global *g = (const struct global *) p; | |
4505 | uint16_t len = bfd_getl16 (g->data); | |
4506 | ||
4507 | return iterative_hash (g->data, len, 0); | |
4508 | } | |
4509 | ||
4510 | /* Compare an entry in the globals list with a symbol. */ | |
4511 | static int | |
4512 | eq_global_entry (const void *a, const void *b) | |
4513 | { | |
4514 | const struct global *g = (const struct global *) a; | |
4515 | uint16_t len1, len2; | |
4516 | ||
4517 | len1 = bfd_getl16 (g->data) + sizeof (uint16_t); | |
4518 | len2 = bfd_getl16 (b) + sizeof (uint16_t); | |
4519 | ||
4520 | if (len1 != len2) | |
4521 | return 0; | |
4522 | ||
4523 | return !memcmp (g->data, b, len1); | |
4524 | } | |
4525 | ||
b41a6533 MH |
4526 | /* Stream 4 is the debug information (DBI) stream. */ |
4527 | static bool | |
5967ca92 | 4528 | populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, |
08827105 MH |
4529 | uint16_t section_header_stream_num, |
4530 | uint16_t sym_rec_stream_num, | |
f559276d | 4531 | uint16_t publics_stream_num, |
d5b4c0dd | 4532 | struct string_table *strings, |
fca9096a | 4533 | struct types *types, |
81814b6f | 4534 | struct types *ids, |
8d25f5ef | 4535 | bfd *sym_rec_stream, const char *pdb_name) |
b41a6533 MH |
4536 | { |
4537 | struct pdb_dbi_stream_header h; | |
4538 | struct optional_dbg_header opt; | |
803561cb MH |
4539 | void *mod_info, *sc, *source_info; |
4540 | uint32_t mod_info_size, sc_size, source_info_size; | |
4541 | struct source_files_info source; | |
81814b6f MH |
4542 | struct globals glob; |
4543 | uint16_t globals_stream_num; | |
803561cb MH |
4544 | |
4545 | source.mod_count = 0; | |
4546 | source.mods = NULL; | |
5967ca92 | 4547 | |
81814b6f MH |
4548 | glob.num_entries = 0; |
4549 | glob.first = NULL; | |
4550 | glob.last = NULL; | |
4551 | ||
4552 | glob.hashmap = htab_create_alloc (0, hash_global_entry, | |
4553 | eq_global_entry, free, xcalloc, free); | |
4554 | ||
f559276d | 4555 | if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size, |
81814b6f | 4556 | strings, &source, types, ids, |
8d25f5ef | 4557 | sym_rec_stream, &glob, pdb_name)) |
81814b6f MH |
4558 | { |
4559 | htab_delete (glob.hashmap); | |
4560 | return false; | |
4561 | } | |
4562 | ||
4563 | if (!create_globals_stream (pdb, &glob, &globals_stream_num)) | |
4564 | { | |
4565 | htab_delete (glob.hashmap); | |
4566 | ||
4567 | for (unsigned int i = 0; i < source.mod_count; i++) | |
4568 | { | |
4569 | free (source.mods[i].files); | |
4570 | } | |
4571 | free (source.mods); | |
4572 | ||
4573 | free (mod_info); | |
4574 | return false; | |
4575 | } | |
4576 | ||
4577 | htab_delete (glob.hashmap); | |
b41a6533 | 4578 | |
e2a1b0a0 MH |
4579 | if (!create_section_contrib_substream (abfd, &sc, &sc_size)) |
4580 | { | |
803561cb MH |
4581 | for (unsigned int i = 0; i < source.mod_count; i++) |
4582 | { | |
4583 | free (source.mods[i].files); | |
4584 | } | |
4585 | free (source.mods); | |
4586 | ||
e2a1b0a0 MH |
4587 | free (mod_info); |
4588 | return false; | |
4589 | } | |
4590 | ||
803561cb MH |
4591 | create_source_info_substream (&source_info, &source_info_size, &source); |
4592 | ||
4593 | for (unsigned int i = 0; i < source.mod_count; i++) | |
4594 | { | |
4595 | free (source.mods[i].files); | |
4596 | } | |
4597 | free (source.mods); | |
4598 | ||
b41a6533 MH |
4599 | bfd_putl32 (0xffffffff, &h.version_signature); |
4600 | bfd_putl32 (DBI_STREAM_VERSION_70, &h.version_header); | |
4601 | bfd_putl32 (1, &h.age); | |
81814b6f | 4602 | bfd_putl16 (globals_stream_num, &h.global_stream_index); |
b41a6533 | 4603 | bfd_putl16 (0x8e1d, &h.build_number); // MSVC 14.29 |
08827105 | 4604 | bfd_putl16 (publics_stream_num, &h.public_stream_index); |
b41a6533 | 4605 | bfd_putl16 (0, &h.pdb_dll_version); |
08827105 | 4606 | bfd_putl16 (sym_rec_stream_num, &h.sym_record_stream); |
b41a6533 | 4607 | bfd_putl16 (0, &h.pdb_dll_rbld); |
5967ca92 | 4608 | bfd_putl32 (mod_info_size, &h.mod_info_size); |
e2a1b0a0 | 4609 | bfd_putl32 (sc_size, &h.section_contribution_size); |
b41a6533 | 4610 | bfd_putl32 (0, &h.section_map_size); |
803561cb | 4611 | bfd_putl32 (source_info_size, &h.source_info_size); |
b41a6533 MH |
4612 | bfd_putl32 (0, &h.type_server_map_size); |
4613 | bfd_putl32 (0, &h.mfc_type_server_index); | |
4614 | bfd_putl32 (sizeof (opt), &h.optional_dbg_header_size); | |
4615 | bfd_putl32 (0, &h.ec_substream_size); | |
4616 | bfd_putl16 (0, &h.flags); | |
4617 | bfd_putl16 (get_arch_number (abfd), &h.machine); | |
4618 | bfd_putl32 (0, &h.padding); | |
4619 | ||
226f9f4f | 4620 | if (bfd_write (&h, sizeof (h), stream) != sizeof (h)) |
5967ca92 | 4621 | { |
803561cb | 4622 | free (source_info); |
e2a1b0a0 | 4623 | free (sc); |
5967ca92 MH |
4624 | free (mod_info); |
4625 | return false; | |
4626 | } | |
4627 | ||
226f9f4f | 4628 | if (bfd_write (mod_info, mod_info_size, stream) != mod_info_size) |
5967ca92 | 4629 | { |
803561cb | 4630 | free (source_info); |
e2a1b0a0 | 4631 | free (sc); |
5967ca92 MH |
4632 | free (mod_info); |
4633 | return false; | |
4634 | } | |
4635 | ||
4636 | free (mod_info); | |
b41a6533 | 4637 | |
226f9f4f | 4638 | if (bfd_write (sc, sc_size, stream) != sc_size) |
e2a1b0a0 | 4639 | { |
803561cb | 4640 | free (source_info); |
e2a1b0a0 MH |
4641 | free (sc); |
4642 | return false; | |
4643 | } | |
4644 | ||
4645 | free (sc); | |
4646 | ||
226f9f4f | 4647 | if (bfd_write (source_info, source_info_size, stream) != source_info_size) |
803561cb MH |
4648 | { |
4649 | free (source_info); | |
4650 | return false; | |
4651 | } | |
4652 | ||
4653 | free (source_info); | |
4654 | ||
b41a6533 MH |
4655 | bfd_putl16 (0xffff, &opt.fpo_stream); |
4656 | bfd_putl16 (0xffff, &opt.exception_stream); | |
4657 | bfd_putl16 (0xffff, &opt.fixup_stream); | |
4658 | bfd_putl16 (0xffff, &opt.omap_to_src_stream); | |
4659 | bfd_putl16 (0xffff, &opt.omap_from_src_stream); | |
a7267222 | 4660 | bfd_putl16 (section_header_stream_num, &opt.section_header_stream); |
b41a6533 MH |
4661 | bfd_putl16 (0xffff, &opt.token_map_stream); |
4662 | bfd_putl16 (0xffff, &opt.xdata_stream); | |
4663 | bfd_putl16 (0xffff, &opt.pdata_stream); | |
4664 | bfd_putl16 (0xffff, &opt.new_fpo_stream); | |
4665 | bfd_putl16 (0xffff, &opt.orig_section_header_stream); | |
4666 | ||
226f9f4f | 4667 | if (bfd_write (&opt, sizeof (opt), stream) != sizeof (opt)) |
b41a6533 MH |
4668 | return false; |
4669 | ||
4670 | return true; | |
4671 | } | |
4672 | ||
08827105 MH |
4673 | /* Used as parameter to qsort, to sort publics by hash. */ |
4674 | static int | |
4675 | public_compare_hash (const void *s1, const void *s2) | |
4676 | { | |
4677 | const struct public *p1 = *(const struct public **) s1; | |
4678 | const struct public *p2 = *(const struct public **) s2; | |
4679 | ||
4680 | if (p1->hash < p2->hash) | |
4681 | return -1; | |
4682 | if (p1->hash > p2->hash) | |
4683 | return 1; | |
4684 | ||
4685 | return 0; | |
4686 | } | |
4687 | ||
4688 | /* Used as parameter to qsort, to sort publics by address. */ | |
4689 | static int | |
4690 | public_compare_addr (const void *s1, const void *s2) | |
4691 | { | |
4692 | const struct public *p1 = *(const struct public **) s1; | |
4693 | const struct public *p2 = *(const struct public **) s2; | |
4694 | ||
4695 | if (p1->section < p2->section) | |
4696 | return -1; | |
4697 | if (p1->section > p2->section) | |
4698 | return 1; | |
4699 | ||
4700 | if (p1->address < p2->address) | |
4701 | return -1; | |
4702 | if (p1->address > p2->address) | |
4703 | return 1; | |
4704 | ||
4705 | return 0; | |
4706 | } | |
4707 | ||
4708 | /* The publics stream is a hash map of S_PUB32 records, which are stored | |
4709 | in the symbol record stream. Each S_PUB32 entry represents a symbol | |
4710 | from the point of view of the linker: a section index, an offset within | |
4711 | the section, and a mangled name. Compare with S_GDATA32 and S_GPROC32, | |
4712 | which are the same thing but generated by the compiler. */ | |
4713 | static bool | |
4714 | populate_publics_stream (bfd *stream, bfd *abfd, bfd *sym_rec_stream) | |
4715 | { | |
4716 | struct publics_header header; | |
4717 | struct globals_hash_header hash_header; | |
4718 | const unsigned int num_buckets = 4096; | |
4719 | unsigned int num_entries = 0, filled_buckets = 0; | |
4720 | unsigned int buckets_size, sym_hash_size; | |
4721 | char int_buf[sizeof (uint32_t)]; | |
4722 | struct public *publics_head = NULL, *publics_tail = NULL; | |
4723 | struct public **buckets; | |
4724 | struct public **sorted = NULL; | |
4725 | bool ret = false; | |
4726 | ||
4727 | buckets = xmalloc (sizeof (struct public *) * num_buckets); | |
4728 | memset (buckets, 0, sizeof (struct public *) * num_buckets); | |
4729 | ||
4730 | /* Loop through the global symbols in our input files, and write S_PUB32 | |
4731 | records in the symbol record stream for those that make it into the | |
4732 | final image. */ | |
4733 | for (bfd *in = coff_data (abfd)->link_info->input_bfds; in; | |
4734 | in = in->link.next) | |
4735 | { | |
8b182dc3 MH |
4736 | if (!in->outsymbols) |
4737 | continue; | |
4738 | ||
08827105 MH |
4739 | for (unsigned int i = 0; i < in->symcount; i++) |
4740 | { | |
4741 | struct bfd_symbol *sym = in->outsymbols[i]; | |
4742 | ||
4743 | if (sym->flags & BSF_GLOBAL) | |
4744 | { | |
4745 | struct pubsym ps; | |
4746 | uint16_t record_length; | |
4747 | const char *name = sym->name; | |
4748 | size_t name_len = strlen (name); | |
4749 | struct public *p = xmalloc (sizeof (struct public)); | |
4750 | unsigned int padding = 0; | |
4751 | uint16_t section; | |
4752 | uint32_t flags = 0; | |
4753 | ||
4754 | section = | |
4755 | find_section_number (abfd, sym->section->output_section); | |
4756 | ||
4757 | if (section == 0) | |
4758 | continue; | |
4759 | ||
4760 | p->next = NULL; | |
4761 | p->offset = bfd_tell (sym_rec_stream); | |
4762 | p->hash = calc_hash (name, name_len) % num_buckets; | |
4763 | p->section = section; | |
4764 | p->address = sym->section->output_offset + sym->value; | |
4765 | ||
4766 | record_length = sizeof (struct pubsym) + name_len + 1; | |
4767 | ||
4768 | if (record_length % 4) | |
4769 | padding = 4 - (record_length % 4); | |
4770 | ||
4771 | /* Assume that all global symbols in executable sections | |
4772 | are functions. */ | |
4773 | if (sym->section->flags & SEC_CODE) | |
4774 | flags = PUBSYM_FUNCTION; | |
4775 | ||
4776 | bfd_putl16 (record_length + padding - sizeof (uint16_t), | |
4777 | &ps.record_length); | |
4778 | bfd_putl16 (S_PUB32, &ps.record_type); | |
4779 | bfd_putl32 (flags, &ps.flags); | |
4780 | bfd_putl32 (p->address, &ps.offset); | |
4781 | bfd_putl16 (p->section, &ps.section); | |
4782 | ||
226f9f4f | 4783 | if (bfd_write (&ps, sizeof (struct pubsym), sym_rec_stream) != |
08827105 MH |
4784 | sizeof (struct pubsym)) |
4785 | goto end; | |
4786 | ||
226f9f4f | 4787 | if (bfd_write (name, name_len + 1, sym_rec_stream) != |
08827105 MH |
4788 | name_len + 1) |
4789 | goto end; | |
4790 | ||
4791 | for (unsigned int j = 0; j < padding; j++) | |
4792 | { | |
4793 | uint8_t b = 0; | |
4794 | ||
226f9f4f | 4795 | if (bfd_write (&b, sizeof (uint8_t), sym_rec_stream) != |
08827105 MH |
4796 | sizeof (uint8_t)) |
4797 | goto end; | |
4798 | } | |
4799 | ||
4800 | if (!publics_head) | |
4801 | publics_head = p; | |
4802 | else | |
4803 | publics_tail->next = p; | |
4804 | ||
4805 | publics_tail = p; | |
4806 | num_entries++; | |
4807 | } | |
4808 | } | |
4809 | } | |
4810 | ||
4811 | ||
4812 | if (num_entries > 0) | |
4813 | { | |
4814 | /* Create an array of pointers, sorted by hash value. */ | |
4815 | ||
4816 | sorted = xmalloc (sizeof (struct public *) * num_entries); | |
4817 | ||
4818 | struct public *p = publics_head; | |
4819 | for (unsigned int i = 0; i < num_entries; i++) | |
4820 | { | |
4821 | sorted[i] = p; | |
4822 | p = p->next; | |
4823 | } | |
4824 | ||
4825 | qsort (sorted, num_entries, sizeof (struct public *), | |
4826 | public_compare_hash); | |
4827 | ||
4828 | /* Populate the buckets. */ | |
4829 | ||
4830 | for (unsigned int i = 0; i < num_entries; i++) | |
4831 | { | |
4832 | if (!buckets[sorted[i]->hash]) | |
4833 | { | |
4834 | buckets[sorted[i]->hash] = sorted[i]; | |
4835 | filled_buckets++; | |
4836 | } | |
4837 | ||
4838 | sorted[i]->index = i; | |
4839 | } | |
4840 | } | |
4841 | ||
4842 | buckets_size = num_buckets / 8; | |
4843 | buckets_size += sizeof (uint32_t); | |
4844 | buckets_size += filled_buckets * sizeof (uint32_t); | |
4845 | ||
4846 | sym_hash_size = sizeof (hash_header); | |
4847 | sym_hash_size += num_entries * sizeof (struct hash_record); | |
4848 | sym_hash_size += buckets_size; | |
4849 | ||
4850 | /* Output the publics header. */ | |
4851 | ||
4852 | bfd_putl32 (sym_hash_size, &header.sym_hash_size); | |
4853 | bfd_putl32 (num_entries * sizeof (uint32_t), &header.addr_map_size); | |
4854 | bfd_putl32 (0, &header.num_thunks); | |
4855 | bfd_putl32 (0, &header.thunks_size); | |
4856 | bfd_putl32 (0, &header.thunk_table); | |
4857 | bfd_putl32 (0, &header.thunk_table_offset); | |
4858 | bfd_putl32 (0, &header.num_sects); | |
4859 | ||
226f9f4f | 4860 | if (bfd_write (&header, sizeof (header), stream) != sizeof (header)) |
08827105 MH |
4861 | goto end; |
4862 | ||
4863 | /* Output the global hash header. */ | |
4864 | ||
4865 | bfd_putl32 (GLOBALS_HASH_SIGNATURE, &hash_header.signature); | |
4866 | bfd_putl32 (GLOBALS_HASH_VERSION_70, &hash_header.version); | |
4867 | bfd_putl32 (num_entries * sizeof (struct hash_record), | |
4868 | &hash_header.entries_size); | |
4869 | bfd_putl32 (buckets_size, &hash_header.buckets_size); | |
4870 | ||
226f9f4f | 4871 | if (bfd_write (&hash_header, sizeof (hash_header), stream) != |
08827105 MH |
4872 | sizeof (hash_header)) |
4873 | goto end; | |
4874 | ||
4875 | /* Write the entries in hash order. */ | |
4876 | ||
4877 | for (unsigned int i = 0; i < num_entries; i++) | |
4878 | { | |
4879 | struct hash_record hr; | |
4880 | ||
4881 | bfd_putl32 (sorted[i]->offset + 1, &hr.offset); | |
4882 | bfd_putl32 (1, &hr.reference); | |
4883 | ||
226f9f4f | 4884 | if (bfd_write (&hr, sizeof (hr), stream) != sizeof (hr)) |
08827105 MH |
4885 | goto end; |
4886 | } | |
4887 | ||
4888 | /* Write the bitmap for filled and unfilled buckets. */ | |
4889 | ||
4890 | for (unsigned int i = 0; i < num_buckets; i += 8) | |
4891 | { | |
4892 | uint8_t v = 0; | |
4893 | ||
4894 | for (unsigned int j = 0; j < 8; j++) | |
4895 | { | |
4896 | if (buckets[i + j]) | |
4897 | v |= 1 << j; | |
4898 | } | |
4899 | ||
226f9f4f | 4900 | if (bfd_write (&v, sizeof (v), stream) != sizeof (v)) |
08827105 MH |
4901 | goto end; |
4902 | } | |
4903 | ||
4904 | /* Add a 4-byte gap. */ | |
4905 | ||
4906 | bfd_putl32 (0, int_buf); | |
4907 | ||
226f9f4f | 4908 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) |
08827105 MH |
4909 | goto end; |
4910 | ||
4911 | /* Write the bucket offsets. */ | |
4912 | ||
4913 | for (unsigned int i = 0; i < num_buckets; i++) | |
4914 | { | |
4915 | if (buckets[i]) | |
4916 | { | |
4917 | /* 0xc is size of internal hash_record structure in | |
4918 | Microsoft's parser. */ | |
4919 | bfd_putl32 (buckets[i]->index * 0xc, int_buf); | |
4920 | ||
226f9f4f | 4921 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != |
08827105 MH |
4922 | sizeof (uint32_t)) |
4923 | goto end; | |
4924 | } | |
4925 | } | |
4926 | ||
4927 | /* Write the address map: offsets into the symbol record stream of | |
4928 | S_PUB32 records, ordered by address. */ | |
4929 | ||
4930 | if (num_entries > 0) | |
4931 | { | |
4932 | qsort (sorted, num_entries, sizeof (struct public *), | |
4933 | public_compare_addr); | |
4934 | ||
4935 | for (unsigned int i = 0; i < num_entries; i++) | |
4936 | { | |
4937 | bfd_putl32 (sorted[i]->offset, int_buf); | |
4938 | ||
226f9f4f | 4939 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != |
08827105 MH |
4940 | sizeof (uint32_t)) |
4941 | goto end; | |
4942 | } | |
4943 | } | |
4944 | ||
4945 | ret = true; | |
4946 | ||
4947 | end: | |
4948 | free (buckets); | |
4949 | ||
4950 | while (publics_head) | |
4951 | { | |
4952 | struct public *p = publics_head->next; | |
4953 | ||
4954 | free (publics_head); | |
4955 | publics_head = p; | |
4956 | } | |
4957 | ||
4958 | free (sorted); | |
4959 | ||
4960 | return ret; | |
4961 | } | |
4962 | ||
a7267222 MH |
4963 | /* The section header stream contains a copy of the section headers |
4964 | from the PE file, in the same format. */ | |
4965 | static bool | |
4966 | create_section_header_stream (bfd *pdb, bfd *abfd, uint16_t *num) | |
4967 | { | |
4968 | bfd *stream; | |
4969 | unsigned int section_count; | |
4970 | file_ptr scn_base; | |
4971 | size_t len; | |
4972 | char *buf; | |
4973 | ||
4974 | stream = add_stream (pdb, NULL, num); | |
4975 | if (!stream) | |
4976 | return false; | |
4977 | ||
4978 | section_count = abfd->section_count; | |
4979 | ||
4980 | /* Empty sections aren't output. */ | |
4981 | for (asection *sect = abfd->sections; sect; sect = sect->next) | |
4982 | { | |
4983 | if (sect->size == 0) | |
4984 | section_count--; | |
4985 | } | |
4986 | ||
4987 | if (section_count == 0) | |
4988 | return true; | |
4989 | ||
4990 | /* Copy section table from output - it's already been written at this | |
4991 | point. */ | |
4992 | ||
4993 | scn_base = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); | |
4994 | ||
e416bd75 AM |
4995 | if (bfd_seek (abfd, scn_base, SEEK_SET) != 0) |
4996 | return false; | |
a7267222 MH |
4997 | |
4998 | len = section_count * sizeof (struct external_scnhdr); | |
4999 | buf = xmalloc (len); | |
5000 | ||
226f9f4f | 5001 | if (bfd_read (buf, len, abfd) != len) |
a7267222 MH |
5002 | { |
5003 | free (buf); | |
5004 | return false; | |
5005 | } | |
5006 | ||
226f9f4f | 5007 | if (bfd_write (buf, len, stream) != len) |
a7267222 MH |
5008 | { |
5009 | free (buf); | |
5010 | return false; | |
5011 | } | |
5012 | ||
5013 | free (buf); | |
5014 | ||
5015 | return true; | |
5016 | } | |
5017 | ||
f559276d MH |
5018 | /* Populate the "/names" named stream, which contains the string table. */ |
5019 | static bool | |
5020 | populate_names_stream (bfd *stream, struct string_table *strings) | |
5021 | { | |
5022 | char int_buf[sizeof (uint32_t)]; | |
5023 | struct string_table_header h; | |
5024 | uint32_t num_strings = 0, num_buckets; | |
5025 | struct string **buckets; | |
5026 | ||
5027 | bfd_putl32 (STRING_TABLE_SIGNATURE, &h.signature); | |
5028 | bfd_putl32 (STRING_TABLE_VERSION, &h.version); | |
5029 | ||
226f9f4f | 5030 | if (bfd_write (&h, sizeof (h), stream) != sizeof (h)) |
f559276d MH |
5031 | return false; |
5032 | ||
5033 | bfd_putl32 (strings->strings_len, int_buf); | |
5034 | ||
226f9f4f | 5035 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) |
f559276d MH |
5036 | return false; |
5037 | ||
5038 | int_buf[0] = 0; | |
5039 | ||
226f9f4f | 5040 | if (bfd_write (int_buf, 1, stream) != 1) |
f559276d MH |
5041 | return false; |
5042 | ||
5043 | for (struct string *s = strings->strings_head; s; s = s->next) | |
5044 | { | |
226f9f4f | 5045 | if (bfd_write (s->s, s->len, stream) != s->len) |
f559276d MH |
5046 | return false; |
5047 | ||
226f9f4f | 5048 | if (bfd_write (int_buf, 1, stream) != 1) |
f559276d MH |
5049 | return false; |
5050 | ||
5051 | num_strings++; | |
5052 | } | |
5053 | ||
5054 | num_buckets = num_strings * 2; | |
5055 | ||
5056 | buckets = xmalloc (sizeof (struct string *) * num_buckets); | |
5057 | memset (buckets, 0, sizeof (struct string *) * num_buckets); | |
5058 | ||
5059 | for (struct string *s = strings->strings_head; s; s = s->next) | |
5060 | { | |
5061 | uint32_t bucket_num = s->hash % num_buckets; | |
5062 | ||
5063 | while (buckets[bucket_num]) | |
5064 | { | |
5065 | bucket_num++; | |
5066 | ||
5067 | if (bucket_num == num_buckets) | |
5068 | bucket_num = 0; | |
5069 | } | |
5070 | ||
5071 | buckets[bucket_num] = s; | |
5072 | } | |
5073 | ||
5074 | bfd_putl32 (num_buckets, int_buf); | |
5075 | ||
226f9f4f | 5076 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) |
f559276d MH |
5077 | { |
5078 | free (buckets); | |
5079 | return false; | |
5080 | } | |
5081 | ||
5082 | for (unsigned int i = 0; i < num_buckets; i++) | |
5083 | { | |
5084 | if (buckets[i]) | |
5085 | bfd_putl32 (buckets[i]->offset, int_buf); | |
5086 | else | |
5087 | bfd_putl32 (0, int_buf); | |
5088 | ||
226f9f4f | 5089 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != |
f559276d MH |
5090 | sizeof (uint32_t)) |
5091 | { | |
5092 | free (buckets); | |
5093 | return false; | |
5094 | } | |
5095 | } | |
5096 | ||
5097 | free (buckets); | |
5098 | ||
5099 | bfd_putl32 (num_strings, int_buf); | |
5100 | ||
226f9f4f | 5101 | if (bfd_write (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) |
f559276d MH |
5102 | return false; |
5103 | ||
5104 | return true; | |
5105 | } | |
5106 | ||
d5b4c0dd MH |
5107 | /* Calculate the hash of a type_entry. */ |
5108 | static hashval_t | |
5109 | hash_type_entry (const void *p) | |
5110 | { | |
5111 | const struct type_entry *e = (const struct type_entry *) p; | |
5112 | uint16_t size = bfd_getl16 (e->data) + sizeof (uint16_t); | |
5113 | ||
5114 | return iterative_hash (e->data, size, 0); | |
5115 | } | |
5116 | ||
5117 | /* Compare a type_entry with a type. */ | |
5118 | static int | |
5119 | eq_type_entry (const void *a, const void *b) | |
5120 | { | |
5121 | const struct type_entry *e = (const struct type_entry *) a; | |
5122 | uint16_t size_a = bfd_getl16 (e->data); | |
5123 | uint16_t size_b = bfd_getl16 (b); | |
5124 | ||
5125 | if (size_a != size_b) | |
5126 | return 0; | |
5127 | ||
5128 | return memcmp (e->data + sizeof (uint16_t), | |
5129 | (const uint8_t *) b + sizeof (uint16_t), size_a) == 0; | |
5130 | } | |
5131 | ||
b41a6533 MH |
5132 | /* Create a PDB debugging file for the PE image file abfd with the build ID |
5133 | guid, stored at pdb_name. */ | |
5134 | bool | |
5135 | create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) | |
5136 | { | |
5137 | bfd *pdb; | |
5138 | bool ret = false; | |
08827105 | 5139 | bfd *info_stream, *dbi_stream, *names_stream, *sym_rec_stream, |
d5b4c0dd | 5140 | *publics_stream, *tpi_stream, *ipi_stream; |
08827105 | 5141 | uint16_t section_header_stream_num, sym_rec_stream_num, publics_stream_num; |
f559276d | 5142 | struct string_table strings; |
d5b4c0dd | 5143 | struct types types, ids; |
b41a6533 MH |
5144 | |
5145 | pdb = bfd_openw (pdb_name, "pdb"); | |
5146 | if (!pdb) | |
5147 | { | |
3c5e7c6d | 5148 | einfo (_("%P: warning: cannot create PDB file: %E\n")); |
b41a6533 MH |
5149 | return false; |
5150 | } | |
5151 | ||
f559276d MH |
5152 | strings.strings_head = NULL; |
5153 | strings.strings_tail = NULL; | |
5154 | strings.strings_len = 1; | |
5155 | strings.hashmap = htab_create_alloc (0, hash_string_table_entry, | |
5156 | eq_string_table_entry, free, | |
5157 | xcalloc, free); | |
5158 | ||
b41a6533 MH |
5159 | bfd_set_format (pdb, bfd_archive); |
5160 | ||
5161 | if (!create_old_directory_stream (pdb)) | |
5162 | { | |
5163 | einfo (_("%P: warning: cannot create old directory stream " | |
3c5e7c6d | 5164 | "in PDB file: %E\n")); |
b41a6533 MH |
5165 | goto end; |
5166 | } | |
5167 | ||
5168 | info_stream = add_stream (pdb, NULL, NULL); | |
5169 | ||
5170 | if (!info_stream) | |
5171 | { | |
5172 | einfo (_("%P: warning: cannot create info stream " | |
3c5e7c6d | 5173 | "in PDB file: %E\n")); |
b41a6533 MH |
5174 | goto end; |
5175 | } | |
5176 | ||
d5b4c0dd MH |
5177 | tpi_stream = add_stream (pdb, NULL, NULL); |
5178 | ||
5179 | if (!tpi_stream) | |
b41a6533 MH |
5180 | { |
5181 | einfo (_("%P: warning: cannot create TPI stream " | |
3c5e7c6d | 5182 | "in PDB file: %E\n")); |
b41a6533 MH |
5183 | goto end; |
5184 | } | |
5185 | ||
5186 | dbi_stream = add_stream (pdb, NULL, NULL); | |
5187 | ||
5188 | if (!dbi_stream) | |
5189 | { | |
5190 | einfo (_("%P: warning: cannot create DBI stream " | |
3c5e7c6d | 5191 | "in PDB file: %E\n")); |
b41a6533 MH |
5192 | goto end; |
5193 | } | |
5194 | ||
d5b4c0dd MH |
5195 | ipi_stream = add_stream (pdb, NULL, NULL); |
5196 | ||
5197 | if (!ipi_stream) | |
b41a6533 MH |
5198 | { |
5199 | einfo (_("%P: warning: cannot create IPI stream " | |
3c5e7c6d | 5200 | "in PDB file: %E\n")); |
b41a6533 MH |
5201 | goto end; |
5202 | } | |
5203 | ||
5204 | names_stream = add_stream (pdb, "/names", NULL); | |
5205 | ||
5206 | if (!names_stream) | |
5207 | { | |
5208 | einfo (_("%P: warning: cannot create /names stream " | |
3c5e7c6d | 5209 | "in PDB file: %E\n")); |
b41a6533 MH |
5210 | goto end; |
5211 | } | |
5212 | ||
08827105 MH |
5213 | sym_rec_stream = add_stream (pdb, NULL, &sym_rec_stream_num); |
5214 | ||
5215 | if (!sym_rec_stream) | |
5216 | { | |
5217 | einfo (_("%P: warning: cannot create symbol record stream " | |
5218 | "in PDB file: %E\n")); | |
5219 | goto end; | |
5220 | } | |
5221 | ||
5222 | publics_stream = add_stream (pdb, NULL, &publics_stream_num); | |
5223 | ||
5224 | if (!publics_stream) | |
5225 | { | |
5226 | einfo (_("%P: warning: cannot create publics stream " | |
5227 | "in PDB file: %E\n")); | |
5228 | goto end; | |
5229 | } | |
5230 | ||
a7267222 MH |
5231 | if (!create_section_header_stream (pdb, abfd, §ion_header_stream_num)) |
5232 | { | |
5233 | einfo (_("%P: warning: cannot create section header stream " | |
5234 | "in PDB file: %E\n")); | |
5235 | goto end; | |
5236 | } | |
5237 | ||
d5b4c0dd MH |
5238 | types.num_types = 0; |
5239 | types.hashmap = htab_create_alloc (0, hash_type_entry, eq_type_entry, | |
5240 | free, xcalloc, free); | |
5241 | types.first = types.last = NULL; | |
5242 | ||
5243 | ids.num_types = 0; | |
5244 | ids.hashmap = htab_create_alloc (0, hash_type_entry, eq_type_entry, | |
5245 | free, xcalloc, free); | |
5246 | ids.first = ids.last = NULL; | |
5247 | ||
5967ca92 | 5248 | if (!populate_dbi_stream (dbi_stream, abfd, pdb, section_header_stream_num, |
f559276d | 5249 | sym_rec_stream_num, publics_stream_num, |
8d25f5ef | 5250 | &strings, &types, &ids, sym_rec_stream, pdb_name)) |
b41a6533 MH |
5251 | { |
5252 | einfo (_("%P: warning: cannot populate DBI stream " | |
3c5e7c6d | 5253 | "in PDB file: %E\n")); |
d5b4c0dd MH |
5254 | htab_delete (types.hashmap); |
5255 | htab_delete (ids.hashmap); | |
5256 | goto end; | |
5257 | } | |
5258 | ||
5259 | if (!populate_type_stream (pdb, tpi_stream, &types)) | |
5260 | { | |
5261 | einfo (_("%P: warning: cannot populate TPI stream " | |
5262 | "in PDB file: %E\n")); | |
5263 | htab_delete (types.hashmap); | |
5264 | htab_delete (ids.hashmap); | |
b41a6533 MH |
5265 | goto end; |
5266 | } | |
5267 | ||
d5b4c0dd MH |
5268 | htab_delete (types.hashmap); |
5269 | ||
5270 | if (!populate_type_stream (pdb, ipi_stream, &ids)) | |
5271 | { | |
5272 | einfo (_("%P: warning: cannot populate IPI stream " | |
5273 | "in PDB file: %E\n")); | |
5274 | htab_delete (ids.hashmap); | |
5275 | goto end; | |
5276 | } | |
5277 | ||
5278 | htab_delete (ids.hashmap); | |
5279 | ||
f559276d MH |
5280 | add_string ("", 0, &strings); |
5281 | ||
5282 | if (!populate_names_stream (names_stream, &strings)) | |
5283 | { | |
5284 | einfo (_("%P: warning: cannot populate names stream " | |
5285 | "in PDB file: %E\n")); | |
5286 | goto end; | |
5287 | } | |
5288 | ||
08827105 MH |
5289 | if (!populate_publics_stream (publics_stream, abfd, sym_rec_stream)) |
5290 | { | |
5291 | einfo (_("%P: warning: cannot populate publics stream " | |
5292 | "in PDB file: %E\n")); | |
5293 | goto end; | |
5294 | } | |
5295 | ||
b41a6533 MH |
5296 | if (!populate_info_stream (pdb, info_stream, guid)) |
5297 | { | |
5298 | einfo (_("%P: warning: cannot populate info stream " | |
3c5e7c6d | 5299 | "in PDB file: %E\n")); |
b41a6533 MH |
5300 | goto end; |
5301 | } | |
5302 | ||
5303 | ret = true; | |
5304 | ||
5305 | end: | |
5306 | bfd_close (pdb); | |
5307 | ||
f559276d MH |
5308 | htab_delete (strings.hashmap); |
5309 | ||
b41a6533 MH |
5310 | return ret; |
5311 | } |