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