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> &sections)
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                                            &section_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                                            &section_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