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-2014 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"
37 #include "coff/internal.h"
41 /* Internal section information */
43 /* Coff PE read debugging flag:
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;
49 struct read_pe_section_data
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
56 unsigned int index; /* BFD section number. */
57 char *section_name; /* Recorded section name. */
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
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. */
74 read_pe_section_index (const char *section_name)
76 if (strcmp (section_name, ".text") == 0)
78 return PE_SECTION_INDEX_TEXT;
81 else if (strcmp (section_name, ".data") == 0)
83 return PE_SECTION_INDEX_DATA;
86 else if (strcmp (section_name, ".bss") == 0)
88 return PE_SECTION_INDEX_BSS;
93 return PE_SECTION_INDEX_INVALID;
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. */
102 get_pe_section_index (const char *section_name,
103 struct read_pe_section_data *sections,
108 for (i = 0; i < nb_sections; i++)
109 if (strcmp (sections[i].section_name, section_name) == 0)
111 return PE_SECTION_INDEX_INVALID;
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
120 struct read_pe_section_data *sections;
123 /* Record the virtual memory address of a section. */
126 get_section_vmas (bfd *abfd, asection *sectp, void *context)
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,
133 if (sectix != PE_SECTION_INDEX_INVALID)
135 /* Data within the section start at rva_start in the pe and at
136 bfd_get_section_vma() within memory. Store the offset. */
138 sections[sectix].vma_offset
139 = bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start;
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
149 DLL_NAME is the internal name of the DLL file,
150 OBJFILE is the objfile struct of DLL_NAME. */
153 add_pe_exported_sym (const char *sym_name,
154 unsigned long func_rva,
156 const struct read_pe_section_data *section_data,
157 const char *dll_name, struct objfile *objfile)
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;
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". */
167 if (sym_name == NULL || *sym_name == '\0')
168 bare_name = xstrprintf ("#%d", ordinal);
170 bare_name = xstrdup (sym_name);
172 qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);
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);
179 prim_record_minimal_symbol_and_info (qualified_name, vma,
180 section_data->ms_type,
181 section_data->index, objfile);
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);
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. */
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)
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);
217 xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name,
221 msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name);
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);
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,
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);
247 vma = BMSYMBOL_VALUE_ADDRESS (msymbol);
248 msymtype = MSYMBOL_TYPE (msymbol.minsym);
249 section = MSYMBOL_SECTION (msymbol.minsym);
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". */
255 if (sym_name == NULL || *sym_name == '\0')
256 bare_name = xstrprintf ("#%d", ordinal);
258 bare_name = xstrdup (sym_name);
260 qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);
262 prim_record_minimal_symbol_and_info (qualified_name, vma, msymtype,
265 /* Enter the plain name as well, which might not be unique. */
266 prim_record_minimal_symbol_and_info (bare_name, vma, msymtype,
268 xfree (qualified_name);
274 /* Truncate a dll_name at the last dot character. */
277 read_pe_truncate_name (char *dll_name)
279 char *last_point = strrchr (dll_name, '.');
281 if (last_point != NULL)
285 /* Low-level support functions, direct from the ld module pe-dll.c. */
287 pe_get16 (bfd *abfd, int where)
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);
297 pe_get32 (bfd *abfd, int where)
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);
309 unsigned char *b = ptr;
311 return b[0] + (b[1] << 8);
317 unsigned char *b = ptr;
319 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
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. */
327 read_pe_exported_syms (struct objfile *objfile)
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;
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;
348 struct cleanup *back_to = make_cleanup (null_cleanup, 0);
350 char const *target = bfd_get_target (objfile->obfd);
352 section_data = xzalloc (PE_SECTION_TABLE_SIZE
353 * sizeof (struct read_pe_section_data));
355 make_cleanup (free_current_contents, §ion_data);
357 for (i=0; i < PE_SECTION_TABLE_SIZE; i++)
359 section_data[i].vma_offset = 0;
360 section_data[i].rva_start = 1;
361 section_data[i].rva_end = 0;
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";
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)
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);
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;
389 num_entries = pe_get32 (dll, opthdr_ofs + 108);
391 num_entries = pe_get32 (dll, opthdr_ofs + 92);
393 if (num_entries < 1) /* No exports. */
395 do_cleanups (back_to);
400 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112);
401 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116);
405 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96);
406 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100);
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));
414 /* Get the rva and size of the export section. */
415 for (i = 0; i < nsections; i++)
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);
423 bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
424 bfd_bread (sname, (bfd_size_type) sizeof (sname), dll);
426 if ((strcmp (sname, ".edata") == 0)
427 || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize))
429 if (strcmp (sname, ".edata") != 0)
431 if (debug_coff_pe_read)
432 fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll "
433 "\"%s\" is in section \"%s\"\n"),
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);
445 export_rva = export_opthdrrva;
446 export_size = export_opthdrsize;
448 if (export_size == 0)
450 /* Empty export table. */
451 do_cleanups (back_to);
455 /* Scan sections and store the base and size of the relevant
457 for (i = 0; i < nsections; i++)
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];
465 unsigned int bfd_section_index;
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';
472 sectix = read_pe_section_index (sec_name);
473 section = bfd_get_section_by_name (dll, sec_name);
475 bfd_section_index = section->index;
477 bfd_section_index = -1;
479 if (sectix != PE_SECTION_INDEX_INVALID)
481 section_data[sectix].rva_start = vaddr;
482 section_data[sectix].rva_end = vaddr + vsize;
483 section_data[sectix].index = bfd_section_index;
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;
505 section_data[otherix].ms_type = mst_unknown;
510 expdata = (unsigned char *) xmalloc (export_size);
511 make_cleanup (xfree, expdata);
513 bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
514 bfd_bread (expdata, (bfd_size_type) export_size, dll);
515 erva = expdata - export_rva;
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);
523 /* Use internal dll name instead of full pathname. */
524 dll_name = (char *) (pe_as32 (expdata + 12) + erva);
526 pe_sections_info.nb_sections = otherix;
527 pe_sections_info.sections = section_data;
529 bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info);
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++)
536 section_data[i].vma_offset
537 += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
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);
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);
549 /* Iterate through the list of symbols. */
550 for (i = 0; i < nexp; i++)
552 /* Pointer to the names vector. */
553 unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
554 /* Retrieve ordinal value. */
556 unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);
559 /* Pointer to the function address vector. */
560 /* This is relatived to ordinal value. */
561 unsigned long func_rva = pe_as32 (erva + exp_funcbase +
564 /* Find this symbol's section in our own array. */
566 int section_found = 0;
568 /* First handle forward cases. */
569 if (func_rva >= export_rva && func_rva < export_rva + export_size)
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, '.');
579 int len = (int) (sep - forward_name);
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;
586 if (add_pe_forwarded_sym (funcname, forward_dll_name,
587 forward_func_name, ordinal,
588 dll_name, objfile) != 0)
593 for (sectix = 0; sectix < otherix; ++sectix)
595 if ((func_rva >= section_data[sectix].rva_start)
596 && (func_rva < section_data[sectix].rva_end))
598 char *sym_name = (char *) (erva + name_rva);
601 add_pe_exported_sym (sym_name, func_rva, ordinal,
602 section_data + sectix, dll_name, objfile);
609 char *funcname = (char *) (erva + name_rva);
613 add_pe_exported_sym (NULL, func_rva, ordinal,
614 section_data, dll_name, objfile);
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);
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);
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... */
640 #define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000
643 pe_text_section_offset (struct bfd *abfd)
646 unsigned long pe_header_offset, i;
647 unsigned long nsections, secptr;
653 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
655 target = bfd_get_target (abfd);
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);
664 if (!is_pe32 && !is_pe64)
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;
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));
678 /* Get the rva and size of the export section. */
679 for (i = 0; i < nsections; i++)
681 char sname[SCNNMLEN + 1];
682 unsigned long secptr1 = secptr + 40 * i;
683 unsigned long vaddr = pe_get32 (abfd, secptr1 + 12);
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)
692 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
695 /* Implements "show debug coff_pe_read" command. */
698 show_debug_coff_pe_read (struct ui_file *file, int from_tty,
699 struct cmd_list_element *c, const char *value)
701 fprintf_filtered (file, _("Coff PE read debugging is %s.\n"), value);
704 /* Provide a prototype to silence -Wmissing-prototypes. */
706 void _initialize_coff_pe_read (void);
708 /* Adds "Set/show debug coff_pe_read" commands. */
711 _initialize_coff_pe_read (void)
713 add_setshow_zuinteger_cmd ("coff-pe-read", class_maintenance,
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);