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.
5 Copyright (C) 2003, 2007-2012 Free Software Foundation, Inc.
7 This file is part of GDB.
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.
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.
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/>.
22 Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */
26 #include "coff-pe-read.h"
36 #include "common/common-utils.h"
40 /* Internal section information */
42 /* Coff PE read debugging flag:
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;
48 struct read_pe_section_data
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
55 char *section_name; /* Recorded section name. */
58 #ifndef IMAGE_SCN_CNT_CODE
59 # define IMAGE_SCN_CNT_CODE 0x20
61 #ifndef IMAGE_SCN_CNT_INITIALIZED_DATA
62 # define IMAGE_SCN_CNT_INITIALIZED_DATA 0x40
64 #ifndef IMAGE_SCN_CNT_UNINITIALIZED_DATA
65 # define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x80
67 #define PE_SECTION_INDEX_TEXT 0
68 #define PE_SECTION_INDEX_DATA 1
69 #define PE_SECTION_INDEX_BSS 2
70 #define PE_SECTION_TABLE_SIZE 3
71 #define PE_SECTION_INDEX_INVALID -1
73 /* Get the index of the named section in our own array, which contains
74 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
75 if passed an unrecognised section name. */
78 read_pe_section_index (const char *section_name)
80 if (strcmp (section_name, ".text") == 0)
82 return PE_SECTION_INDEX_TEXT;
85 else if (strcmp (section_name, ".data") == 0)
87 return PE_SECTION_INDEX_DATA;
90 else if (strcmp (section_name, ".bss") == 0)
92 return PE_SECTION_INDEX_BSS;
97 return PE_SECTION_INDEX_INVALID;
101 /* Get the index of the named section in our own full arrayi.
102 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
103 if passed an unrecognised section name. */
106 get_pe_section_index (const char *section_name,
107 struct read_pe_section_data *sections,
112 for (i = 0; i < nb_sections; i++)
113 if (strcmp (sections[i].section_name, section_name) == 0)
115 return PE_SECTION_INDEX_INVALID;
118 /* Structure used by get_section_vmas function below
119 to access section_data array and the size of the array
120 stored in nb_sections field. */
121 struct pe_sections_info
124 struct read_pe_section_data *sections;
127 /* Record the virtual memory address of a section. */
130 get_section_vmas (bfd *abfd, asection *sectp, void *context)
132 struct pe_sections_info *data = context;
133 struct read_pe_section_data *sections = data->sections;
134 int sectix = get_pe_section_index (sectp->name, sections,
137 if (sectix != PE_SECTION_INDEX_INVALID)
139 /* Data within the section start at rva_start in the pe and at
140 bfd_get_section_vma() within memory. Store the offset. */
142 sections[sectix].vma_offset
143 = bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start;
147 /* Create a minimal symbol entry for an exported symbol.
148 SYM_NAME contains the exported name or NULL if exported by ordinal,
149 FUNC_RVA contains the Relative Virtual Address of the symbol,
150 ORDINAL is the ordinal index value of the symbol,
151 SECTION_DATA contains information about the section in which the
153 DLL_NAME is the internal name of the DLL file,
154 OBJFILE is the objfile struct of DLL_NAME. */
157 add_pe_exported_sym (const char *sym_name,
158 unsigned long func_rva,
160 const struct read_pe_section_data *section_data,
161 const char *dll_name, struct objfile *objfile)
163 char *qualified_name, *bare_name;
164 /* Add the stored offset to get the loaded address of the symbol. */
165 CORE_ADDR vma = func_rva + section_data->vma_offset;
166 int dll_name_len = strlen (dll_name);
168 /* Generate a (hopefully unique) qualified name using the first part
169 of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
170 used by windbg from the "Microsoft Debugging Tools for Windows". */
172 if (sym_name == NULL || *sym_name == '\0')
173 bare_name = xstrprintf ("#%d", ordinal);
175 bare_name = xstrdup (sym_name);
177 qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);
179 if ((section_data->ms_type == mst_unknown) && debug_coff_pe_read)
180 fprintf_unfiltered (gdb_stdlog , _("Unknown section type for \"%s\""
181 " for entry \"%s\" in dll \"%s\"\n"),
182 section_data->section_name, sym_name, dll_name);
184 prim_record_minimal_symbol (qualified_name, vma,
185 section_data->ms_type, objfile);
187 /* Enter the plain name as well, which might not be unique. */
188 prim_record_minimal_symbol (bare_name, vma, section_data->ms_type, objfile);
189 if (debug_coff_pe_read > 1)
190 fprintf_unfiltered (gdb_stdlog, _("Adding exported symbol \"%s\""
191 " in dll \"%s\"\n"), sym_name, dll_name);
192 xfree (qualified_name);
196 /* Create a minimal symbol entry for an exported forward symbol.
197 Return 1 if the forwarded function was found 0 otherwise.
198 SYM_NAME contains the exported name or NULL if exported by ordinal,
199 FORWARD_DLL_NAME is the name of the DLL in which the target symobl resides,
200 FORWARD_FUNC_NAME is the name of the target symbol in that DLL,
201 ORDINAL is the ordinal index value of the symbol,
202 DLL_NAME is the internal name of the DLL file,
203 OBJFILE is the objfile struct of DLL_NAME. */
206 add_pe_forwarded_sym (const char *sym_name, const char *forward_dll_name,
207 const char *forward_func_name, int ordinal,
208 const char *dll_name, struct objfile *objfile)
211 struct objfile *forward_objfile;
212 struct minimal_symbol *msymbol;
214 enum minimal_symbol_type msymtype;
215 int dll_name_len = strlen (dll_name);
216 char *qualified_name, *bare_name;
217 int forward_dll_name_len = strlen (forward_dll_name);
218 int forward_func_name_len = strlen (forward_func_name);
219 int forward_len = forward_dll_name_len + forward_func_name_len + 2;
220 char *forward_qualified_name = alloca (forward_len);
222 xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name,
226 msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name,
233 for (i = 0; i < forward_dll_name_len; i++)
234 forward_qualified_name[i] = tolower (forward_qualified_name[i]);
235 msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name,
241 if (debug_coff_pe_read)
242 fprintf_unfiltered (gdb_stdlog, _("Unable to find function \"%s\" in"
243 " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"),
244 forward_func_name, forward_dll_name, sym_name,
249 if (debug_coff_pe_read > 1)
250 fprintf_unfiltered (gdb_stdlog, _("Adding forwarded exported symbol"
251 " \"%s\" in dll \"%s\", pointing to \"%s\"\n"),
252 sym_name, dll_name, forward_qualified_name);
254 vma = SYMBOL_VALUE_ADDRESS (msymbol);
255 section = SYMBOL_SECTION (msymbol);
256 msymtype = MSYMBOL_TYPE (msymbol);
258 /* Generate a (hopefully unique) qualified name using the first part
259 of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
260 used by windbg from the "Microsoft Debugging Tools for Windows". */
262 if (sym_name == NULL || *sym_name == '\0')
263 bare_name = xstrprintf ("#%d", ordinal);
265 bare_name = xstrdup (sym_name);
267 qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);
269 prim_record_minimal_symbol (qualified_name, vma, msymtype, objfile);
271 /* Enter the plain name as well, which might not be unique. */
272 prim_record_minimal_symbol (bare_name, vma, msymtype, objfile);
273 xfree (qualified_name);
279 /* Truncate a dll_name at the last dot character. */
282 read_pe_truncate_name (char *dll_name)
284 char *last_point = strrchr (dll_name, '.');
286 if (last_point != NULL)
290 /* Low-level support functions, direct from the ld module pe-dll.c. */
292 pe_get16 (bfd *abfd, int where)
296 bfd_seek (abfd, (file_ptr) where, SEEK_SET);
297 bfd_bread (b, (bfd_size_type) 2, abfd);
298 return b[0] + (b[1] << 8);
302 pe_get32 (bfd *abfd, int where)
306 bfd_seek (abfd, (file_ptr) where, SEEK_SET);
307 bfd_bread (b, (bfd_size_type) 4, abfd);
308 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
314 unsigned char *b = ptr;
316 return b[0] + (b[1] << 8);
322 unsigned char *b = ptr;
324 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
327 /* Read the (non-debug) export symbol table from a portable
328 executable. Code originally lifted from the ld function
329 pe_implied_import_dll in pe-dll.c. */
332 read_pe_exported_syms (struct objfile *objfile)
334 bfd *dll = objfile->obfd;
335 unsigned long nbnormal, nbforward;
336 unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
337 unsigned long export_opthdrrva, export_opthdrsize;
338 unsigned long export_rva, export_size, nsections, secptr, expptr;
339 unsigned long exp_funcbase;
340 unsigned char *expdata, *erva;
341 unsigned long name_rvas, ordinals, nexp, ordbase;
342 char *dll_name = (char *) dll->filename;
343 int otherix = PE_SECTION_TABLE_SIZE;
348 /* Array elements are for text, data and bss in that order
349 Initialization with RVA_START > RVA_END guarantees that
350 unused sections won't be matched. */
351 struct read_pe_section_data *section_data;
352 struct pe_sections_info pe_sections_info;
354 struct cleanup *back_to = make_cleanup (null_cleanup, 0);
356 char const *target = bfd_get_target (objfile->obfd);
358 section_data = xzalloc (PE_SECTION_TABLE_SIZE
359 * sizeof (struct read_pe_section_data));
361 make_cleanup (free_current_contents, §ion_data);
363 for (i=0; i < PE_SECTION_TABLE_SIZE; i++)
365 section_data[i].vma_offset = 0;
366 section_data[i].rva_start = 1;
367 section_data[i].rva_end = 0;
369 section_data[PE_SECTION_INDEX_TEXT].ms_type = mst_text;
370 section_data[PE_SECTION_INDEX_TEXT].section_name = ".text";
371 section_data[PE_SECTION_INDEX_DATA].ms_type = mst_data;
372 section_data[PE_SECTION_INDEX_DATA].section_name = ".data";
373 section_data[PE_SECTION_INDEX_BSS].ms_type = mst_bss;
374 section_data[PE_SECTION_INDEX_BSS].section_name = ".bss";
376 is_pe64 = (strcmp (target, "pe-x86-64") == 0
377 || strcmp (target, "pei-x86-64") == 0);
378 is_pe32 = (strcmp (target, "pe-i386") == 0
379 || strcmp (target, "pei-i386") == 0
380 || strcmp (target, "pe-arm-wince-little") == 0
381 || strcmp (target, "pei-arm-wince-little") == 0);
382 if (!is_pe32 && !is_pe64)
384 /* This is not a recognized PE format file. Abort now, because
385 the code is untested on anything else. *FIXME* test on
386 further architectures and loosen or remove this test. */
390 /* Get pe_header, optional header and numbers of export entries. */
391 pe_header_offset = pe_get32 (dll, 0x3c);
392 opthdr_ofs = pe_header_offset + 4 + 20;
394 num_entries = pe_get32 (dll, opthdr_ofs + 108);
396 num_entries = pe_get32 (dll, opthdr_ofs + 92);
398 if (num_entries < 1) /* No exports. */
404 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112);
405 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116);
409 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96);
410 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100);
412 nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
413 secptr = (pe_header_offset + 4 + 20 +
414 pe_get16 (dll, pe_header_offset + 4 + 16));
418 /* Get the rva and size of the export section. */
419 for (i = 0; i < nsections; i++)
422 unsigned long secptr1 = secptr + 40 * i;
423 unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
424 unsigned long vsize = pe_get32 (dll, secptr1 + 16);
425 unsigned long fptr = pe_get32 (dll, secptr1 + 20);
427 bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
428 bfd_bread (sname, (bfd_size_type) sizeof (sname), dll);
430 if ((strcmp (sname, ".edata") == 0)
431 || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize))
433 if (strcmp (sname, ".edata") != 0)
435 if (debug_coff_pe_read)
436 fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll "
437 "\"%s\" is in section \"%s\"\n"),
440 else if (export_opthdrrva != vaddr && debug_coff_pe_read)
441 fprintf_unfiltered (gdb_stdlog, _("Wrong value of export RVA"
442 " for dll \"%s\": 0x%lx instead of 0x%lx\n"),
443 dll_name, export_opthdrrva, vaddr);
444 expptr = fptr + (export_opthdrrva - vaddr);
450 export_rva = export_opthdrrva;
451 export_size = export_opthdrsize;
453 if (export_size == 0)
455 /* Empty export table. */
459 /* Scan sections and store the base and size of the relevant
461 for (i = 0; i < nsections; i++)
463 unsigned long secptr1 = secptr + 40 * i;
464 unsigned long vsize = pe_get32 (dll, secptr1 + 8);
465 unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
466 unsigned long characteristics = pe_get32 (dll, secptr1 + 36);
470 memset (sec_name, 0, sizeof (sec_name));
471 bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
472 bfd_bread (sec_name, (bfd_size_type) 8, dll);
474 sectix = read_pe_section_index (sec_name);
476 if (sectix != PE_SECTION_INDEX_INVALID)
478 section_data[sectix].rva_start = vaddr;
479 section_data[sectix].rva_end = vaddr + vsize;
485 section_data = xrealloc (section_data, (otherix + 1)
486 * sizeof (struct read_pe_section_data));
487 name = xstrdup (sec_name);
488 section_data[otherix].section_name = name;
489 make_cleanup (xfree, name);
490 section_data[otherix].rva_start = vaddr;
491 section_data[otherix].rva_end = vaddr + vsize;
492 section_data[otherix].vma_offset = 0;
493 if (characteristics & IMAGE_SCN_CNT_CODE)
494 section_data[otherix].ms_type = mst_text;
495 else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
496 section_data[otherix].ms_type = mst_data;
497 else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
498 section_data[otherix].ms_type = mst_bss;
500 section_data[otherix].ms_type = mst_unknown;
505 expdata = (unsigned char *) xmalloc (export_size);
506 make_cleanup (xfree, expdata);
508 bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
509 bfd_bread (expdata, (bfd_size_type) export_size, dll);
510 erva = expdata - export_rva;
512 nexp = pe_as32 (expdata + 24);
513 name_rvas = pe_as32 (expdata + 32);
514 ordinals = pe_as32 (expdata + 36);
515 ordbase = pe_as32 (expdata + 16);
516 exp_funcbase = pe_as32 (expdata + 28);
518 /* Use internal dll name instead of full pathname. */
519 dll_name = pe_as32 (expdata + 12) + erva;
521 pe_sections_info.nb_sections = otherix;
522 pe_sections_info.sections = section_data;
524 bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info);
526 /* Adjust the vma_offsets in case this PE got relocated. This
527 assumes that *all* sections share the same relocation offset
528 as the text section. */
529 for (i = 0; i < otherix; i++)
531 section_data[i].vma_offset
532 += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
535 /* Truncate name at first dot. Should maybe also convert to all
536 lower case for convenience on Windows. */
537 read_pe_truncate_name (dll_name);
539 if (debug_coff_pe_read)
540 fprintf_unfiltered (gdb_stdlog, _("DLL \"%s\" has %ld export entries,"
541 " base=%ld\n"), dll_name, nexp, ordbase);
544 /* Iterate through the list of symbols. */
545 for (i = 0; i < nexp; i++)
547 /* Pointer to the names vector. */
548 unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
549 /* Retrieve ordinal value. */
551 unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);
554 /* Pointer to the function address vector. */
555 /* This is relatived to ordinal value. */
556 unsigned long func_rva = pe_as32 (erva + exp_funcbase +
559 /* Find this symbol's section in our own array. */
561 int section_found = 0;
563 /* First handle forward cases. */
564 if (func_rva >= export_rva && func_rva < export_rva + export_size)
566 char *forward_name = (char *) (erva + func_rva);
567 char *funcname = (char *) (erva + name_rva);
568 char *forward_dll_name = forward_name;
569 char *forward_func_name = forward_name;
570 char *sep = strrchr (forward_name, '.');
574 int len = (int) (sep - forward_name);
576 forward_dll_name = alloca (len + 1);
577 strncpy (forward_dll_name, forward_name, len);
578 forward_dll_name[len] = '\0';
579 forward_func_name = ++sep;
581 if (add_pe_forwarded_sym (funcname, forward_dll_name,
582 forward_func_name, ordinal,
583 dll_name, objfile) != 0)
588 for (sectix = 0; sectix < otherix; ++sectix)
590 if ((func_rva >= section_data[sectix].rva_start)
591 && (func_rva < section_data[sectix].rva_end))
594 add_pe_exported_sym (erva + name_rva,
596 section_data + sectix, dll_name, objfile);
603 char *funcname = (char *) (erva + name_rva);
607 add_pe_exported_sym (NULL, func_rva, ordinal,
608 section_data, dll_name, objfile);
611 else if (debug_coff_pe_read)
612 fprintf_unfiltered (gdb_stdlog, _("Export name \"%s\" ord. %lu,"
613 " RVA 0x%lx in dll \"%s\" not handled\n"),
614 funcname, ordinal, func_rva, dll_name);
618 if (debug_coff_pe_read)
619 fprintf_unfiltered (gdb_stdlog, _("Finished reading \"%s\", exports %ld,"
620 " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal,
621 nbforward, nbnormal + nbforward, nexp);
622 /* Discard expdata and section_data. */
623 do_cleanups (back_to);
626 /* Extract from ABFD the offset of the .text section.
627 This offset is mainly related to the offset within the file.
628 The value was previously expected to be 0x1000 for all files,
629 but some Windows OS core DLLs seem to use 0x10000 section alignement
630 which modified the return value of that function.
631 Still return default 0x1000 value if ABFD is NULL or
632 if '.text' section is not found, but that should not happen... */
634 #define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000
637 pe_text_section_offset (struct bfd *abfd)
640 unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
641 unsigned long export_rva, export_size, nsections, secptr, expptr;
642 unsigned long exp_funcbase;
643 unsigned char *expdata, *erva;
644 unsigned long name_rvas, ordinals, nexp, ordbase;
651 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
653 target = bfd_get_target (abfd);
655 is_pe64 = (strcmp (target, "pe-x86-64") == 0
656 || strcmp (target, "pei-x86-64") == 0);
657 is_pe32 = (strcmp (target, "pe-i386") == 0
658 || strcmp (target, "pei-i386") == 0
659 || strcmp (target, "pe-arm-wince-little") == 0
660 || strcmp (target, "pei-arm-wince-little") == 0);
662 if (!is_pe32 && !is_pe64)
664 /* This is not a recognized PE format file. Abort now, because
665 the code is untested on anything else. *FIXME* test on
666 further architectures and loosen or remove this test. */
667 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
670 /* Get pe_header, optional header and numbers of sections. */
671 pe_header_offset = pe_get32 (abfd, 0x3c);
672 opthdr_ofs = pe_header_offset + 4 + 20;
673 nsections = pe_get16 (abfd, pe_header_offset + 4 + 2);
674 secptr = (pe_header_offset + 4 + 20 +
675 pe_get16 (abfd, pe_header_offset + 4 + 16));
677 /* Get the rva and size of the export section. */
678 for (i = 0; i < nsections; i++)
681 unsigned long secptr1 = secptr + 40 * i;
682 unsigned long vaddr = pe_get32 (abfd, secptr1 + 12);
684 bfd_seek (abfd, (file_ptr) secptr1, SEEK_SET);
685 bfd_bread (sname, (bfd_size_type) 8, abfd);
686 if (strcmp (sname, ".text") == 0)
690 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
693 /* Implements "show debug coff_pe_read" command. */
696 show_debug_coff_pe_read (struct ui_file *file, int from_tty,
697 struct cmd_list_element *c, const char *value)
699 fprintf_filtered (file, _("Coff PE read debugging is %s.\n"), value);
702 /* Provide a prototype to silence -Wmissing-prototypes. */
704 void _initialize_coff_pe_read (void);
706 /* Adds "Set/show debug coff_pe_read" commands. */
709 _initialize_coff_pe_read (void)
711 add_setshow_uinteger_cmd ("coff_pe_read", class_maintenance,
713 _("Set coff PE read debugging."),
714 _("Show coff PE read debugging."),
715 _("When set, debugging messages for coff reading "
716 "of exported symbols are displayed."),
717 NULL, show_debug_coff_pe_read,
718 &setdebuglist, &showdebuglist);