update copyright year range in GDB files
[external/binutils.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-2017 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 = (struct pe_sections_info *) 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 (minimal_symbol_reader &reader,
154                      const char *sym_name,
155                      unsigned long func_rva,
156                      int ordinal,
157                      const struct read_pe_section_data *section_data,
158                      const char *dll_name, struct objfile *objfile)
159 {
160   char *qualified_name, *bare_name;
161   /* Add the stored offset to get the loaded address of the symbol.  */
162   CORE_ADDR vma = func_rva + section_data->vma_offset;
163
164   /* Generate a (hopefully unique) qualified name using the first part
165      of the dll name, e.g. KERNEL32!AddAtomA.  This matches the style
166      used by windbg from the "Microsoft Debugging Tools for Windows".  */
167
168   if (sym_name == NULL || *sym_name == '\0')
169     bare_name = xstrprintf ("#%d", ordinal);
170   else
171     bare_name = xstrdup (sym_name);
172
173   qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);
174
175   if ((section_data->ms_type == mst_unknown) && debug_coff_pe_read)
176     fprintf_unfiltered (gdb_stdlog , _("Unknown section type for \"%s\""
177                         " for entry \"%s\" in dll \"%s\"\n"),
178                         section_data->section_name, sym_name, dll_name);
179
180   reader.record_with_info (qualified_name, vma, section_data->ms_type,
181                            section_data->index);
182
183   /* Enter the plain name as well, which might not be unique.  */
184   reader.record_with_info (bare_name, vma, section_data->ms_type,
185                            section_data->index);
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 (minimal_symbol_reader &reader,
204                       const char *sym_name, const char *forward_dll_name,
205                       const char *forward_func_name, int ordinal,
206                       const char *dll_name, struct objfile *objfile)
207 {
208   CORE_ADDR vma, baseaddr;
209   struct bound_minimal_symbol msymbol;
210   enum minimal_symbol_type msymtype;
211   char *qualified_name, *bare_name;
212   int forward_dll_name_len = strlen (forward_dll_name);
213   int forward_func_name_len = strlen (forward_func_name);
214   int forward_len = forward_dll_name_len + forward_func_name_len + 2;
215   char *forward_qualified_name = (char *) alloca (forward_len);
216   short section;
217
218   xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name,
219              forward_func_name);
220
221
222   msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name);
223
224   if (!msymbol.minsym)
225     {
226       int i;
227
228       for (i = 0; i < forward_dll_name_len; i++)
229         forward_qualified_name[i] = tolower (forward_qualified_name[i]);
230       msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name);
231     }
232
233   if (!msymbol.minsym)
234     {
235       if (debug_coff_pe_read)
236         fprintf_unfiltered (gdb_stdlog, _("Unable to find function \"%s\" in"
237                             " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"),
238                             forward_func_name, forward_dll_name, sym_name,
239                             dll_name);
240       return 0;
241     }
242
243   if (debug_coff_pe_read > 1)
244     fprintf_unfiltered (gdb_stdlog, _("Adding forwarded exported symbol"
245                         " \"%s\" in dll \"%s\", pointing to \"%s\"\n"),
246                         sym_name, dll_name, forward_qualified_name);
247
248   vma = BMSYMBOL_VALUE_ADDRESS (msymbol);
249   msymtype = MSYMBOL_TYPE (msymbol.minsym);
250   section = MSYMBOL_SECTION (msymbol.minsym);
251
252   /* Generate a (hopefully unique) qualified name using the first part
253      of the dll name, e.g. KERNEL32!AddAtomA.  This matches the style
254      used by windbg from the "Microsoft Debugging Tools for Windows".  */
255
256   if (sym_name == NULL || *sym_name == '\0')
257     bare_name = xstrprintf ("#%d", ordinal);
258   else
259     bare_name = xstrdup (sym_name);
260
261   qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);
262
263   /* Note that this code makes a minimal symbol whose value may point
264      outside of any section in this objfile.  These symbols can't
265      really be relocated properly, but nevertheless we make a stab at
266      it, choosing an approach consistent with the history of this
267      code.  */
268   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
269
270   reader.record_with_info (qualified_name, vma - baseaddr, msymtype, section);
271
272   /* Enter the plain name as well, which might not be unique.  */
273   reader.record_with_info (bare_name, vma - baseaddr, msymtype, section);
274   xfree (qualified_name);
275   xfree (bare_name);
276
277   return 1;
278 }
279
280 /* Truncate a dll_name at the last dot character.  */
281
282 static void
283 read_pe_truncate_name (char *dll_name)
284 {
285   char *last_point = strrchr (dll_name, '.');
286
287   if (last_point != NULL)
288     *last_point = '\0';
289 }
290 \f
291 /* Low-level support functions, direct from the ld module pe-dll.c.  */
292 static unsigned int
293 pe_get16 (bfd *abfd, int where)
294 {
295   unsigned char b[2];
296
297   bfd_seek (abfd, (file_ptr) where, SEEK_SET);
298   bfd_bread (b, (bfd_size_type) 2, abfd);
299   return b[0] + (b[1] << 8);
300 }
301
302 static unsigned int
303 pe_get32 (bfd *abfd, int where)
304 {
305   unsigned char b[4];
306
307   bfd_seek (abfd, (file_ptr) where, SEEK_SET);
308   bfd_bread (b, (bfd_size_type) 4, abfd);
309   return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
310 }
311
312 static unsigned int
313 pe_as16 (void *ptr)
314 {
315   unsigned char *b = (unsigned char *) ptr;
316
317   return b[0] + (b[1] << 8);
318 }
319
320 static unsigned int
321 pe_as32 (void *ptr)
322 {
323   unsigned char *b = (unsigned char *) ptr;
324
325   return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
326 }
327 \f
328 /* Read the (non-debug) export symbol table from a portable
329    executable.  Code originally lifted from the ld function
330    pe_implied_import_dll in pe-dll.c.  */
331
332 void
333 read_pe_exported_syms (minimal_symbol_reader &reader,
334                        struct objfile *objfile)
335 {
336   bfd *dll = objfile->obfd;
337   unsigned long nbnormal, nbforward;
338   unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
339   unsigned long export_opthdrrva, export_opthdrsize;
340   unsigned long export_rva, export_size, nsections, secptr, expptr;
341   unsigned long exp_funcbase;
342   unsigned char *expdata, *erva;
343   unsigned long name_rvas, ordinals, nexp, ordbase;
344   char *dll_name = (char *) dll->filename;
345   int otherix = PE_SECTION_TABLE_SIZE;
346   int is_pe64 = 0;
347   int is_pe32 = 0;
348
349   /* Array elements are for text, data and bss in that order
350      Initialization with RVA_START > RVA_END guarantees that
351      unused sections won't be matched.  */
352   struct read_pe_section_data *section_data;
353   struct pe_sections_info pe_sections_info;
354
355   struct cleanup *back_to = make_cleanup (null_cleanup, 0);
356
357   char const *target = bfd_get_target (objfile->obfd);
358
359   section_data = XCNEWVEC (struct read_pe_section_data, PE_SECTION_TABLE_SIZE);
360
361   make_cleanup (free_current_contents, &section_data);
362
363   for (i=0; i < PE_SECTION_TABLE_SIZE; i++)
364     {
365       section_data[i].vma_offset = 0;
366       section_data[i].rva_start = 1;
367       section_data[i].rva_end = 0;
368     };
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";
375
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)
383     {
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.  */
387       do_cleanups (back_to);
388       return;
389     }
390
391   /* Get pe_header, optional header and numbers of export entries.  */
392   pe_header_offset = pe_get32 (dll, 0x3c);
393   opthdr_ofs = pe_header_offset + 4 + 20;
394   if (is_pe64)
395     num_entries = pe_get32 (dll, opthdr_ofs + 108);
396   else
397     num_entries = pe_get32 (dll, opthdr_ofs + 92);
398
399   if (num_entries < 1)          /* No exports.  */
400     {
401       do_cleanups (back_to);
402       return;
403     }
404   if (is_pe64)
405     {
406       export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112);
407       export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116);
408     }
409   else
410     {
411       export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96);
412       export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100);
413     }
414   nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
415   secptr = (pe_header_offset + 4 + 20 +
416             pe_get16 (dll, pe_header_offset + 4 + 16));
417   expptr = 0;
418   export_size = 0;
419
420   /* Get the rva and size of the export section.  */
421   for (i = 0; i < nsections; i++)
422     {
423       char sname[8];
424       unsigned long secptr1 = secptr + 40 * i;
425       unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
426       unsigned long vsize = pe_get32 (dll, secptr1 + 16);
427       unsigned long fptr = pe_get32 (dll, secptr1 + 20);
428
429       bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
430       bfd_bread (sname, (bfd_size_type) sizeof (sname), dll);
431
432       if ((strcmp (sname, ".edata") == 0)
433           || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize))
434         {
435           if (strcmp (sname, ".edata") != 0)
436             {
437               if (debug_coff_pe_read)
438                 fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll "
439                                     "\"%s\" is in section \"%s\"\n"),
440                                     dll_name, sname);
441             }
442           else if (export_opthdrrva != vaddr && debug_coff_pe_read)
443             fprintf_unfiltered (gdb_stdlog, _("Wrong value of export RVA"
444                                 " for dll \"%s\": 0x%lx instead of 0x%lx\n"),
445                                 dll_name, export_opthdrrva, vaddr);
446           expptr = fptr + (export_opthdrrva - vaddr);
447           break;
448         }
449     }
450
451   export_rva = export_opthdrrva;
452   export_size = export_opthdrsize;
453
454   if (export_size == 0)
455     {
456       /* Empty export table.  */
457       do_cleanups (back_to);
458       return;
459     }
460
461   /* Scan sections and store the base and size of the relevant
462      sections.  */
463   for (i = 0; i < nsections; i++)
464     {
465       unsigned long secptr1 = secptr + 40 * i;
466       unsigned long vsize = pe_get32 (dll, secptr1 + 8);
467       unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
468       unsigned long characteristics = pe_get32 (dll, secptr1 + 36);
469       char sec_name[SCNNMLEN + 1];
470       int sectix;
471       unsigned int bfd_section_index;
472       asection *section;
473
474       bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
475       bfd_bread (sec_name, (bfd_size_type) SCNNMLEN, dll);
476       sec_name[SCNNMLEN] = '\0';
477
478       sectix = read_pe_section_index (sec_name);
479       section = bfd_get_section_by_name (dll, sec_name);
480       if (section)
481         bfd_section_index = section->index;
482       else
483         bfd_section_index = -1;
484
485       if (sectix != PE_SECTION_INDEX_INVALID)
486         {
487           section_data[sectix].rva_start = vaddr;
488           section_data[sectix].rva_end = vaddr + vsize;
489           section_data[sectix].index = bfd_section_index;
490         }
491       else
492         {
493           char *name;
494
495           section_data = XRESIZEVEC (struct read_pe_section_data, section_data,
496                                      otherix + 1);
497           name = xstrdup (sec_name);
498           section_data[otherix].section_name = name;
499           make_cleanup (xfree, name);
500           section_data[otherix].rva_start = vaddr;
501           section_data[otherix].rva_end = vaddr + vsize;
502           section_data[otherix].vma_offset = 0;
503           section_data[otherix].index = bfd_section_index;
504           if (characteristics & IMAGE_SCN_CNT_CODE)
505             section_data[otherix].ms_type = mst_text;
506           else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
507             section_data[otherix].ms_type = mst_data;
508           else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
509             section_data[otherix].ms_type = mst_bss;
510           else
511             section_data[otherix].ms_type = mst_unknown;
512           otherix++;
513         }
514     }
515
516   expdata = (unsigned char *) xmalloc (export_size);
517   make_cleanup (xfree, expdata);
518
519   bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
520   bfd_bread (expdata, (bfd_size_type) export_size, dll);
521   erva = expdata - export_rva;
522
523   nexp = pe_as32 (expdata + 24);
524   name_rvas = pe_as32 (expdata + 32);
525   ordinals = pe_as32 (expdata + 36);
526   ordbase = pe_as32 (expdata + 16);
527   exp_funcbase = pe_as32 (expdata + 28);
528
529   /* Use internal dll name instead of full pathname.  */
530   dll_name = (char *) (pe_as32 (expdata + 12) + erva);
531
532   pe_sections_info.nb_sections = otherix;
533   pe_sections_info.sections = section_data;
534
535   bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info);
536
537   /* Truncate name at first dot. Should maybe also convert to all
538      lower case for convenience on Windows.  */
539   read_pe_truncate_name (dll_name);
540
541   if (debug_coff_pe_read)
542     fprintf_unfiltered (gdb_stdlog, _("DLL \"%s\" has %ld export entries,"
543                         " base=%ld\n"), dll_name, nexp, ordbase);
544   nbforward = 0;
545   nbnormal = 0;
546   /* Iterate through the list of symbols.  */
547   for (i = 0; i < nexp; i++)
548     {
549       /* Pointer to the names vector.  */
550       unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
551       /* Retrieve ordinal value.  */
552
553       unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);
554
555
556       /* Pointer to the function address vector.  */
557       /* This is relatived to ordinal value. */
558       unsigned long func_rva = pe_as32 (erva + exp_funcbase +
559                                         ordinal * 4);
560
561       /* Find this symbol's section in our own array.  */
562       int sectix = 0;
563       int section_found = 0;
564
565       /* First handle forward cases.  */
566       if (func_rva >= export_rva && func_rva < export_rva + export_size)
567         {
568           char *forward_name = (char *) (erva + func_rva);
569           char *funcname = (char *) (erva + name_rva);
570           char *forward_dll_name = forward_name;
571           char *forward_func_name = forward_name;
572           char *sep = strrchr (forward_name, '.');
573
574           if (sep)
575             {
576               int len = (int) (sep - forward_name);
577
578               forward_dll_name = (char *) alloca (len + 1);
579               strncpy (forward_dll_name, forward_name, len);
580               forward_dll_name[len] = '\0';
581               forward_func_name = ++sep;
582             }
583           if (add_pe_forwarded_sym (reader, funcname, forward_dll_name,
584                                     forward_func_name, ordinal,
585                                     dll_name, objfile) != 0)
586             ++nbforward;
587           continue;
588         }
589
590       for (sectix = 0; sectix < otherix; ++sectix)
591         {
592           if ((func_rva >= section_data[sectix].rva_start)
593               && (func_rva < section_data[sectix].rva_end))
594             {
595               char *sym_name = (char *) (erva + name_rva);
596
597               section_found = 1;
598               add_pe_exported_sym (reader, sym_name, func_rva, ordinal,
599                                    section_data + sectix, dll_name, objfile);
600               ++nbnormal;
601               break;
602             }
603         }
604       if (!section_found)
605         {
606           char *funcname = (char *) (erva + name_rva);
607
608           if (name_rva == 0)
609             {
610               add_pe_exported_sym (reader, NULL, func_rva, ordinal,
611                                    section_data, dll_name, objfile);
612               ++nbnormal;
613             }
614           else if (debug_coff_pe_read)
615             fprintf_unfiltered (gdb_stdlog, _("Export name \"%s\" ord. %lu,"
616                                 " RVA 0x%lx in dll \"%s\" not handled\n"),
617                                 funcname, ordinal, func_rva, dll_name);
618         }
619     }
620
621   if (debug_coff_pe_read)
622     fprintf_unfiltered (gdb_stdlog, _("Finished reading \"%s\", exports %ld,"
623                         " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal,
624                         nbforward, nbnormal + nbforward, nexp);
625   /* Discard expdata and section_data.  */
626   do_cleanups (back_to);
627 }
628
629 /* Extract from ABFD the offset of the .text section.
630    This offset is mainly related to the offset within the file.
631    The value was previously expected to be 0x1000 for all files,
632    but some Windows OS core DLLs seem to use 0x10000 section alignement
633    which modified the return value of that function.
634    Still return default 0x1000 value if ABFD is NULL or
635    if '.text' section is not found, but that should not happen...  */
636
637 #define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000
638
639 CORE_ADDR
640 pe_text_section_offset (struct bfd *abfd)
641
642 {
643   unsigned long pe_header_offset, i;
644   unsigned long nsections, secptr;
645   int is_pe64 = 0;
646   int is_pe32 = 0;
647   char const *target;
648
649   if (!abfd)
650     return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
651
652   target = bfd_get_target (abfd);
653
654   is_pe64 = (strcmp (target, "pe-x86-64") == 0
655              || strcmp (target, "pei-x86-64") == 0);
656   is_pe32 = (strcmp (target, "pe-i386") == 0
657              || strcmp (target, "pei-i386") == 0
658              || strcmp (target, "pe-arm-wince-little") == 0
659              || strcmp (target, "pei-arm-wince-little") == 0);
660
661   if (!is_pe32 && !is_pe64)
662     {
663       /* This is not a recognized PE format file.  Abort now, because
664          the code is untested on anything else.  *FIXME* test on
665          further architectures and loosen or remove this test.  */
666       return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
667     }
668
669   /* Get pe_header, optional header and numbers of sections.  */
670   pe_header_offset = pe_get32 (abfd, 0x3c);
671   nsections = pe_get16 (abfd, pe_header_offset + 4 + 2);
672   secptr = (pe_header_offset + 4 + 20 +
673             pe_get16 (abfd, pe_header_offset + 4 + 16));
674
675   /* Get the rva and size of the export section.  */
676   for (i = 0; i < nsections; i++)
677     {
678       char sname[SCNNMLEN + 1];
679       unsigned long secptr1 = secptr + 40 * i;
680       unsigned long vaddr = pe_get32 (abfd, secptr1 + 12);
681
682       bfd_seek (abfd, (file_ptr) secptr1, SEEK_SET);
683       bfd_bread (sname, (bfd_size_type) SCNNMLEN, abfd);
684       sname[SCNNMLEN] = '\0';
685       if (strcmp (sname, ".text") == 0)
686         return vaddr;
687     }
688
689   return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
690 }
691
692 /* Implements "show debug coff_pe_read" command.  */
693
694 static void
695 show_debug_coff_pe_read (struct ui_file *file, int from_tty,
696                          struct cmd_list_element *c, const char *value)
697 {
698   fprintf_filtered (file, _("Coff PE read debugging is %s.\n"), value);
699 }
700
701 /* Provide a prototype to silence -Wmissing-prototypes.  */
702
703 void _initialize_coff_pe_read (void);
704
705 /* Adds "Set/show debug coff_pe_read" commands.  */
706
707 void
708 _initialize_coff_pe_read (void)
709 {
710   add_setshow_zuinteger_cmd ("coff-pe-read", class_maintenance,
711                              &debug_coff_pe_read,
712                              _("Set coff PE read debugging."),
713                              _("Show coff PE read debugging."),
714                              _("When set, debugging messages for coff reading "
715                                "of exported symbols are displayed."),
716                              NULL, show_debug_coff_pe_read,
717                              &setdebuglist, &showdebuglist);
718 }