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