1 /* Read the export table symbols from a portable executable and
2 convert to internal format, for GDB. Used as a last resort if no
3 debugging symbols recognized.
4
5 Copyright (C) 2003-2024 Free Software Foundation, Inc.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */
23
24
25 #include "coff-pe-read.h"
26
27 #include "bfd.h"
28 #include "gdbtypes.h"
29
30 #include "command.h"
31 #include "cli/cli-cmds.h"
32 #include "symtab.h"
33 #include "symfile.h"
34 #include "objfiles.h"
35 #include "gdbsupport/common-utils.h"
36 #include "coff/internal.h"
37
38 #include <ctype.h>
39
40 /* Internal section information */
41
42 /* Coff PE read debugging flag:
43 default value is 0,
44 value 1 outputs problems encountered while parsing PE file,
45 value above 1 also lists all generated minimal symbols. */
46 static unsigned int debug_coff_pe_read;
47
48 struct read_pe_section_data
49 {
50 CORE_ADDR vma_offset; /* Offset to loaded address of section. */
51 unsigned long rva_start; /* Start offset within the pe. */
52 unsigned long rva_end; /* End offset within the pe. */
53 enum minimal_symbol_type ms_type; /* Type to assign symbols in
54 section. */
55 unsigned int index; /* BFD section number. */
56 std::string section_name; /* Recorded section name. */
57 };
58
59 #define IMAGE_SCN_CNT_CODE 0x20
60 #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x40
61 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x80
62 #define PE_SECTION_INDEX_TEXT 0
63 #define PE_SECTION_INDEX_DATA 1
64 #define PE_SECTION_INDEX_BSS 2
65 #define PE_SECTION_TABLE_SIZE 3
66 #define PE_SECTION_INDEX_INVALID -1
67
68 /* Get the index of the named section in our own array, which contains
69 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
70 if passed an unrecognised section name. */
71
72 static int
read_pe_section_index(const char * section_name)73 read_pe_section_index (const char *section_name)
74 {
75 if (strcmp (section_name, ".text") == 0)
76 {
77 return PE_SECTION_INDEX_TEXT;
78 }
79
80 else if (strcmp (section_name, ".data") == 0)
81 {
82 return PE_SECTION_INDEX_DATA;
83 }
84
85 else if (strcmp (section_name, ".bss") == 0)
86 {
87 return PE_SECTION_INDEX_BSS;
88 }
89
90 else
91 {
92 return PE_SECTION_INDEX_INVALID;
93 }
94 }
95
96 /* Get the index of the named section in our own full array.
97 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
98 if passed an unrecognised section name. */
99
100 static int
get_pe_section_index(const char * section_name,const std::vector<read_pe_section_data> & sections)101 get_pe_section_index (const char *section_name,
102 const std::vector<read_pe_section_data> §ions)
103 {
104 for (int i = 0; i < sections.size (); i++)
105 if (sections[i].section_name == section_name)
106 return i;
107 return PE_SECTION_INDEX_INVALID;
108 }
109
110
111 /* Create a minimal symbol entry for an exported symbol.
112 SYM_NAME contains the exported name or NULL if exported by ordinal,
113 FUNC_RVA contains the Relative Virtual Address of the symbol,
114 ORDINAL is the ordinal index value of the symbol,
115 SECTION_DATA contains information about the section in which the
116 symbol is declared,
117 DLL_NAME is the internal name of the DLL file,
118 OBJFILE is the objfile struct of DLL_NAME. */
119
120 static void
add_pe_exported_sym(minimal_symbol_reader & reader,const char * sym_name,unsigned long func_rva,int ordinal,const struct read_pe_section_data * section_data,const char * dll_name,struct objfile * objfile)121 add_pe_exported_sym (minimal_symbol_reader &reader,
122 const char *sym_name,
123 unsigned long func_rva,
124 int ordinal,
125 const struct read_pe_section_data *section_data,
126 const char *dll_name, struct objfile *objfile)
127 {
128 /* Add the stored offset to get the loaded address of the symbol. */
129 unrelocated_addr vma = unrelocated_addr (func_rva
130 + section_data->vma_offset);
131
132 /* Generate a (hopefully unique) qualified name using the first part
133 of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
134 used by windbg from the "Microsoft Debugging Tools for Windows". */
135
136 std::string bare_name;
137 if (sym_name == NULL || *sym_name == '\0')
138 bare_name = string_printf ("#%d", ordinal);
139 else
140 bare_name = sym_name;
141
142 std::string qualified_name
143 = string_printf ("%s!%s", dll_name, bare_name.c_str ());
144
145 if ((section_data->ms_type == mst_unknown) && debug_coff_pe_read)
146 gdb_printf (gdb_stdlog , _("Unknown section type for \"%s\""
147 " for entry \"%s\" in dll \"%s\"\n"),
148 section_data->section_name.c_str (), sym_name,
149 dll_name);
150
151 reader.record_with_info (qualified_name.c_str (), vma, section_data->ms_type,
152 section_data->index);
153
154 /* Enter the plain name as well, which might not be unique. */
155 reader.record_with_info (bare_name.c_str (), vma, section_data->ms_type,
156 section_data->index);
157 if (debug_coff_pe_read > 1)
158 gdb_printf (gdb_stdlog, _("Adding exported symbol \"%s\""
159 " in dll \"%s\"\n"), sym_name, dll_name);
160 }
161
162 /* Create a minimal symbol entry for an exported forward symbol.
163 Return 1 if the forwarded function was found 0 otherwise.
164 SYM_NAME contains the exported name or NULL if exported by ordinal,
165 FORWARD_DLL_NAME is the name of the DLL in which the target symbol resides,
166 FORWARD_FUNC_NAME is the name of the target symbol in that DLL,
167 ORDINAL is the ordinal index value of the symbol,
168 DLL_NAME is the internal name of the DLL file,
169 OBJFILE is the objfile struct of DLL_NAME. */
170
171 static int
add_pe_forwarded_sym(minimal_symbol_reader & reader,const char * sym_name,const char * forward_dll_name,const char * forward_func_name,int ordinal,const char * dll_name,struct objfile * objfile)172 add_pe_forwarded_sym (minimal_symbol_reader &reader,
173 const char *sym_name, const char *forward_dll_name,
174 const char *forward_func_name, int ordinal,
175 const char *dll_name, struct objfile *objfile)
176 {
177 struct bound_minimal_symbol msymbol;
178 enum minimal_symbol_type msymtype;
179 int forward_dll_name_len = strlen (forward_dll_name);
180 short section;
181
182 std::string forward_qualified_name = string_printf ("%s!%s",
183 forward_dll_name,
184 forward_func_name);
185
186 msymbol = lookup_bound_minimal_symbol (forward_qualified_name.c_str ());
187
188 if (!msymbol.minsym)
189 {
190 int i;
191
192 for (i = 0; i < forward_dll_name_len; i++)
193 forward_qualified_name[i] = tolower (forward_qualified_name[i]);
194 msymbol = lookup_bound_minimal_symbol (forward_qualified_name.c_str ());
195 }
196
197 if (!msymbol.minsym)
198 {
199 if (debug_coff_pe_read)
200 gdb_printf (gdb_stdlog, _("Unable to find function \"%s\" in"
201 " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"),
202 forward_func_name, forward_dll_name, sym_name,
203 dll_name);
204 return 0;
205 }
206
207 if (debug_coff_pe_read > 1)
208 gdb_printf (gdb_stdlog, _("Adding forwarded exported symbol"
209 " \"%s\" in dll \"%s\", pointing to \"%s\"\n"),
210 sym_name, dll_name, forward_qualified_name.c_str ());
211
212 /* Calculate VMA as if it were relative to DLL_NAME/OBJFILE, even though
213 it actually points inside another dll (FORWARD_DLL_NAME). */
214 unrelocated_addr vma = unrelocated_addr (msymbol.value_address ()
215 - objfile->text_section_offset ());
216 msymtype = msymbol.minsym->type ();
217 section = msymbol.minsym->section_index ();
218
219 /* Generate a (hopefully unique) qualified name using the first part
220 of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
221 used by windbg from the "Microsoft Debugging Tools for Windows". */
222
223 std::string bare_name;
224 if (sym_name == NULL || *sym_name == '\0')
225 bare_name = string_printf ("#%d", ordinal);
226 else
227 bare_name = sym_name;
228
229 std::string qualified_name
230 = string_printf ("%s!%s", dll_name, bare_name.c_str ());
231
232 /* Note that this code makes a minimal symbol whose value may point
233 outside of any section in this objfile. These symbols can't
234 really be relocated properly, but nevertheless we make a stab at
235 it, choosing an approach consistent with the history of this
236 code. */
237
238 reader.record_with_info (qualified_name.c_str (), vma, msymtype, section);
239
240 /* Enter the plain name as well, which might not be unique. */
241 reader.record_with_info (bare_name.c_str(), vma, msymtype, section);
242
243 return 1;
244 }
245
246 /* Truncate a dll_name at the last dot character. */
247
248 static void
read_pe_truncate_name(char * dll_name)249 read_pe_truncate_name (char *dll_name)
250 {
251 char *last_point = strrchr (dll_name, '.');
252
253 if (last_point != NULL)
254 *last_point = '\0';
255 }
256
257 /* Low-level support functions, direct from the ld module pe-dll.c. */
258 static unsigned int
pe_get16(bfd * abfd,int where,bool * fail)259 pe_get16 (bfd *abfd, int where, bool *fail)
260 {
261 unsigned char b[2];
262
263 if (bfd_seek (abfd, where, SEEK_SET) != 0
264 || bfd_read (b, 2, abfd) != 2)
265 {
266 *fail = true;
267 return 0;
268 }
269 return b[0] + (b[1] << 8);
270 }
271
272 static unsigned int
pe_get32(bfd * abfd,int where,bool * fail)273 pe_get32 (bfd *abfd, int where, bool *fail)
274 {
275 unsigned char b[4];
276
277 if (bfd_seek (abfd, where, SEEK_SET) != 0
278 || bfd_read (b, 4, abfd) != 4)
279 {
280 *fail = true;
281 return 0;
282 }
283 return b[0] + (b[1] << 8) + (b[2] << 16) + ((unsigned) b[3] << 24);
284 }
285
286 static unsigned int
pe_as16(void * ptr)287 pe_as16 (void *ptr)
288 {
289 unsigned char *b = (unsigned char *) ptr;
290
291 return b[0] + (b[1] << 8);
292 }
293
294 static unsigned int
pe_as32(void * ptr)295 pe_as32 (void *ptr)
296 {
297 unsigned char *b = (unsigned char *) ptr;
298
299 return b[0] + (b[1] << 8) + (b[2] << 16) + ((unsigned) b[3] << 24);
300 }
301
302 /* Read the (non-debug) export symbol table from a portable
303 executable. Code originally lifted from the ld function
304 pe_implied_import_dll in pe-dll.c. */
305
306 void
read_pe_exported_syms(minimal_symbol_reader & reader,struct objfile * objfile)307 read_pe_exported_syms (minimal_symbol_reader &reader,
308 struct objfile *objfile)
309 {
310 bfd *dll = objfile->obfd.get ();
311 unsigned long nbnormal, nbforward;
312 unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
313 unsigned long export_opthdrrva, export_opthdrsize;
314 unsigned long export_rva, export_size, nsections, secptr, expptr;
315 unsigned long exp_funcbase;
316 unsigned char *expdata, *erva;
317 unsigned long name_rvas, ordinals, nexp, ordbase;
318 int otherix = PE_SECTION_TABLE_SIZE;
319 int is_pe64 = 0;
320 int is_pe32 = 0;
321
322 char const *target = bfd_get_target (objfile->obfd.get ());
323
324 std::vector<struct read_pe_section_data> section_data
325 (PE_SECTION_TABLE_SIZE);
326
327 for (i=0; i < PE_SECTION_TABLE_SIZE; i++)
328 {
329 section_data[i].vma_offset = 0;
330 section_data[i].rva_start = 1;
331 section_data[i].rva_end = 0;
332 };
333 section_data[PE_SECTION_INDEX_TEXT].ms_type = mst_text;
334 section_data[PE_SECTION_INDEX_TEXT].section_name = ".text";
335 section_data[PE_SECTION_INDEX_DATA].ms_type = mst_data;
336 section_data[PE_SECTION_INDEX_DATA].section_name = ".data";
337 section_data[PE_SECTION_INDEX_BSS].ms_type = mst_bss;
338 section_data[PE_SECTION_INDEX_BSS].section_name = ".bss";
339
340 is_pe64 = (strcmp (target, "pe-x86-64") == 0
341 || strcmp (target, "pei-x86-64") == 0
342 || strcmp (target, "pe-aarch64") == 0
343 || strcmp (target, "pei-aarch64") == 0);
344 is_pe32 = (strcmp (target, "pe-i386") == 0
345 || strcmp (target, "pei-i386") == 0
346 || strcmp (target, "pe-arm-wince-little") == 0
347 || strcmp (target, "pei-arm-wince-little") == 0);
348
349 /* Possibly print a debug message about DLL not having a valid format. */
350 auto maybe_print_debug_msg = [&] () -> void {
351 if (debug_coff_pe_read)
352 gdb_printf (gdb_stdlog, _("%s doesn't appear to be a DLL\n"),
353 bfd_get_filename (dll));
354 };
355
356 if (!is_pe32 && !is_pe64)
357 return maybe_print_debug_msg ();
358
359 /* Get pe_header, optional header and numbers of export entries. */
360 bool fail = false;
361 pe_header_offset = pe_get32 (dll, 0x3c, &fail);
362 if (fail)
363 return maybe_print_debug_msg ();
364 opthdr_ofs = pe_header_offset + 4 + 20;
365 if (is_pe64)
366 num_entries = pe_get32 (dll, opthdr_ofs + 108, &fail);
367 else
368 num_entries = pe_get32 (dll, opthdr_ofs + 92, &fail);
369 if (fail)
370 return maybe_print_debug_msg ();
371
372 if (num_entries < 1) /* No exports. */
373 return;
374 if (is_pe64)
375 {
376 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112, &fail);
377 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116, &fail);
378 }
379 else
380 {
381 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96, &fail);
382 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100, &fail);
383 }
384 if (fail)
385 return maybe_print_debug_msg ();
386
387 nsections = pe_get16 (dll, pe_header_offset + 4 + 2, &fail);
388 secptr = (pe_header_offset + 4 + 20 +
389 pe_get16 (dll, pe_header_offset + 4 + 16, &fail));
390 if (fail)
391 return maybe_print_debug_msg ();
392 expptr = 0;
393 export_size = 0;
394
395 /* Get the rva and size of the export section. */
396 for (i = 0; i < nsections; i++)
397 {
398 char sname[8];
399 unsigned long secptr1 = secptr + 40 * i;
400 unsigned long vaddr = pe_get32 (dll, secptr1 + 12, &fail);
401 unsigned long vsize = pe_get32 (dll, secptr1 + 16, &fail);
402 unsigned long fptr = pe_get32 (dll, secptr1 + 20, &fail);
403
404 if (fail
405 || bfd_seek (dll, secptr1, SEEK_SET) != 0
406 || bfd_read (sname, sizeof (sname), dll) != sizeof (sname))
407 return maybe_print_debug_msg ();
408
409 if ((strcmp (sname, ".edata") == 0)
410 || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize))
411 {
412 if (strcmp (sname, ".edata") != 0)
413 {
414 if (debug_coff_pe_read)
415 gdb_printf (gdb_stdlog, _("Export RVA for dll "
416 "\"%s\" is in section \"%s\"\n"),
417 bfd_get_filename (dll), sname);
418 }
419 else if (export_opthdrrva != vaddr && debug_coff_pe_read)
420 gdb_printf (gdb_stdlog, _("Wrong value of export RVA"
421 " for dll \"%s\": 0x%lx instead of 0x%lx\n"),
422 bfd_get_filename (dll), export_opthdrrva, vaddr);
423 expptr = fptr + (export_opthdrrva - vaddr);
424 break;
425 }
426 }
427
428 if (expptr == 0)
429 {
430 /* no section contains export table rva */
431 return;
432 }
433
434 export_rva = export_opthdrrva;
435 export_size = export_opthdrsize;
436
437 if (export_size == 0)
438 {
439 /* Empty export table. */
440 return;
441 }
442
443 /* Scan sections and store the base and size of the relevant
444 sections. */
445 for (i = 0; i < nsections; i++)
446 {
447 unsigned long secptr1 = secptr + 40 * i;
448 unsigned long vsize = pe_get32 (dll, secptr1 + 8, &fail);
449 unsigned long vaddr = pe_get32 (dll, secptr1 + 12, &fail);
450 unsigned long characteristics = pe_get32 (dll, secptr1 + 36, &fail);
451 char sec_name[SCNNMLEN + 1];
452 int sectix;
453 unsigned int bfd_section_index;
454 asection *section;
455
456 if (fail
457 || bfd_seek (dll, secptr1 + 0, SEEK_SET) != 0
458 || bfd_read (sec_name, SCNNMLEN, dll) != SCNNMLEN)
459 return maybe_print_debug_msg ();
460 sec_name[SCNNMLEN] = '\0';
461
462 sectix = read_pe_section_index (sec_name);
463 section = bfd_get_section_by_name (dll, sec_name);
464 if (section)
465 bfd_section_index = section->index;
466 else
467 bfd_section_index = -1;
468
469 if (sectix != PE_SECTION_INDEX_INVALID)
470 {
471 section_data[sectix].rva_start = vaddr;
472 section_data[sectix].rva_end = vaddr + vsize;
473 section_data[sectix].index = bfd_section_index;
474 }
475 else
476 {
477 section_data.resize (otherix + 1);
478 section_data[otherix].section_name = sec_name;
479 section_data[otherix].rva_start = vaddr;
480 section_data[otherix].rva_end = vaddr + vsize;
481 section_data[otherix].vma_offset = 0;
482 section_data[otherix].index = bfd_section_index;
483 if (characteristics & IMAGE_SCN_CNT_CODE)
484 section_data[otherix].ms_type = mst_text;
485 else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
486 section_data[otherix].ms_type = mst_data;
487 else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
488 section_data[otherix].ms_type = mst_bss;
489 else
490 section_data[otherix].ms_type = mst_unknown;
491 otherix++;
492 }
493 }
494
495 gdb::def_vector<unsigned char> expdata_storage (export_size);
496 expdata = expdata_storage.data ();
497
498 if (bfd_seek (dll, expptr, SEEK_SET) != 0
499 || bfd_read (expdata, export_size, dll) != export_size)
500 return maybe_print_debug_msg ();
501 erva = expdata - export_rva;
502
503 nexp = pe_as32 (expdata + 24);
504 name_rvas = pe_as32 (expdata + 32);
505 ordinals = pe_as32 (expdata + 36);
506 ordbase = pe_as32 (expdata + 16);
507 exp_funcbase = pe_as32 (expdata + 28);
508
509 /* Use internal dll name instead of full pathname. */
510 char *dll_name = (char *) (pe_as32 (expdata + 12) + erva);
511
512 for (asection *sectp : gdb_bfd_sections (dll))
513 {
514 int sectix = get_pe_section_index (sectp->name, section_data);
515 if (sectix != PE_SECTION_INDEX_INVALID)
516 {
517 /* Data within the section start at rva_start in the pe and at
518 bfd_get_section_vma() within memory. Store the offset. */
519 section_data[sectix].vma_offset
520 = bfd_section_vma (sectp) - section_data[sectix].rva_start;
521 }
522 }
523
524 /* Truncate name at first dot. Should maybe also convert to all
525 lower case for convenience on Windows. */
526 read_pe_truncate_name (dll_name);
527
528 if (debug_coff_pe_read)
529 gdb_printf (gdb_stdlog, _("DLL \"%s\" has %ld export entries,"
530 " base=%ld\n"), dll_name, nexp, ordbase);
531 nbforward = 0;
532 nbnormal = 0;
533 /* Iterate through the list of symbols. */
534 for (i = 0; i < nexp; i++)
535 {
536 /* Pointer to the names vector. */
537 unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
538 /* Retrieve ordinal value. */
539
540 unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);
541
542
543 /* Pointer to the function address vector. */
544 /* This is relative to ordinal value. */
545 unsigned long func_rva = pe_as32 (erva + exp_funcbase +
546 ordinal * 4);
547
548 /* Find this symbol's section in our own array. */
549 int sectix = 0;
550 int section_found = 0;
551
552 /* First handle forward cases. */
553 if (func_rva >= export_rva && func_rva < export_rva + export_size)
554 {
555 const char *forward_name = (const char *) (erva + func_rva);
556 const char *funcname = (const char *) (erva + name_rva);
557 const char *forward_dll_name = forward_name;
558 const char *forward_func_name = forward_name;
559 const char *sep = strrchr (forward_name, '.');
560
561 std::string name_storage;
562 if (sep != nullptr)
563 {
564 int len = (int) (sep - forward_name);
565
566 name_storage = std::string (forward_name, len);
567 forward_dll_name = name_storage.c_str ();
568 forward_func_name = sep + 1;
569 }
570 if (add_pe_forwarded_sym (reader, funcname, forward_dll_name,
571 forward_func_name, ordinal,
572 dll_name, objfile) != 0)
573 ++nbforward;
574 continue;
575 }
576
577 for (sectix = 0; sectix < otherix; ++sectix)
578 {
579 if ((func_rva >= section_data[sectix].rva_start)
580 && (func_rva < section_data[sectix].rva_end))
581 {
582 const char *sym_name = (const char *) (erva + name_rva);
583
584 section_found = 1;
585 add_pe_exported_sym (reader, sym_name, func_rva, ordinal,
586 §ion_data[sectix], dll_name, objfile);
587 ++nbnormal;
588 break;
589 }
590 }
591 if (!section_found)
592 {
593 const char *funcname = (const char *) (erva + name_rva);
594
595 if (name_rva == 0)
596 {
597 add_pe_exported_sym (reader, NULL, func_rva, ordinal,
598 §ion_data[0], dll_name, objfile);
599 ++nbnormal;
600 }
601 else if (debug_coff_pe_read)
602 gdb_printf (gdb_stdlog, _("Export name \"%s\" ord. %lu,"
603 " RVA 0x%lx in dll \"%s\" not handled\n"),
604 funcname, ordinal, func_rva, dll_name);
605 }
606 }
607
608 if (debug_coff_pe_read)
609 gdb_printf (gdb_stdlog, _("Finished reading \"%s\", exports %ld,"
610 " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal,
611 nbforward, nbnormal + nbforward, nexp);
612 }
613
614 /* Extract from ABFD the offset of the .text section.
615 This offset is mainly related to the offset within the file.
616 The value was previously expected to be 0x1000 for all files,
617 but some Windows OS core DLLs seem to use 0x10000 section alignment
618 which modified the return value of that function.
619 Still return default 0x1000 value if ABFD is NULL or
620 if '.text' section is not found, but that should not happen... */
621
622 #define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000
623
624 CORE_ADDR
pe_text_section_offset(struct bfd * abfd)625 pe_text_section_offset (struct bfd *abfd)
626
627 {
628 unsigned long pe_header_offset, i;
629 unsigned long nsections, secptr;
630 int is_pe64 = 0;
631 int is_pe32 = 0;
632 char const *target;
633
634 if (!abfd)
635 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
636
637 target = bfd_get_target (abfd);
638
639 is_pe64 = (strcmp (target, "pe-x86-64") == 0
640 || strcmp (target, "pei-x86-64") == 0
641 || strcmp (target, "pe-aarch64") == 0
642 || strcmp (target, "pei-aarch64") == 0);
643 is_pe32 = (strcmp (target, "pe-i386") == 0
644 || strcmp (target, "pei-i386") == 0
645 || strcmp (target, "pe-arm-wince-little") == 0
646 || strcmp (target, "pei-arm-wince-little") == 0);
647
648 if (!is_pe32 && !is_pe64)
649 {
650 /* This is not a recognized PE format file. Abort now, because
651 the code is untested on anything else. *FIXME* test on
652 further architectures and loosen or remove this test. */
653 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
654 }
655
656 /* Get pe_header, optional header and numbers of sections. */
657 bool fail = false;
658 pe_header_offset = pe_get32 (abfd, 0x3c, &fail);
659 if (fail)
660 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
661 nsections = pe_get16 (abfd, pe_header_offset + 4 + 2, &fail);
662 secptr = (pe_header_offset + 4 + 20 +
663 pe_get16 (abfd, pe_header_offset + 4 + 16, &fail));
664 if (fail)
665 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
666
667 /* Get the rva and size of the export section. */
668 for (i = 0; i < nsections; i++)
669 {
670 char sname[SCNNMLEN + 1];
671 unsigned long secptr1 = secptr + 40 * i;
672 unsigned long vaddr = pe_get32 (abfd, secptr1 + 12, &fail);
673
674 if (fail
675 || bfd_seek (abfd, secptr1, SEEK_SET) != 0
676 || bfd_read (sname, SCNNMLEN, abfd) != SCNNMLEN)
677 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
678 sname[SCNNMLEN] = '\0';
679 if (strcmp (sname, ".text") == 0)
680 return vaddr;
681 }
682
683 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
684 }
685
686 /* Implements "show debug coff_pe_read" command. */
687
688 static void
show_debug_coff_pe_read(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)689 show_debug_coff_pe_read (struct ui_file *file, int from_tty,
690 struct cmd_list_element *c, const char *value)
691 {
692 gdb_printf (file, _("Coff PE read debugging is %s.\n"), value);
693 }
694
695 /* Adds "Set/show debug coff_pe_read" commands. */
696
697 void _initialize_coff_pe_read ();
698 void
_initialize_coff_pe_read()699 _initialize_coff_pe_read ()
700 {
701 add_setshow_zuinteger_cmd ("coff-pe-read", class_maintenance,
702 &debug_coff_pe_read,
703 _("Set coff PE read debugging."),
704 _("Show coff PE read debugging."),
705 _("When set, debugging messages for coff reading "
706 "of exported symbols are displayed."),
707 NULL, show_debug_coff_pe_read,
708 &setdebuglist, &showdebuglist);
709 }
710