* coff-pe-read.h (pe_text_section_offset): Declare new function.
[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, 2007-2012 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
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   char *section_name;           /* Recorded section name.  */
56 };
57
58 #ifndef IMAGE_SCN_CNT_CODE
59 # define IMAGE_SCN_CNT_CODE 0x20
60 #endif
61 #ifndef IMAGE_SCN_CNT_INITIALIZED_DATA
62 # define IMAGE_SCN_CNT_INITIALIZED_DATA 0x40
63 #endif
64 #ifndef IMAGE_SCN_CNT_UNINITIALIZED_DATA
65 # define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x80
66 #endif
67 #define PE_SECTION_INDEX_TEXT     0
68 #define PE_SECTION_INDEX_DATA     1
69 #define PE_SECTION_INDEX_BSS      2
70 #define PE_SECTION_TABLE_SIZE     3
71 #define PE_SECTION_INDEX_INVALID -1
72 \f
73 /* Get the index of the named section in our own array, which contains
74    text, data and bss in that order.  Return PE_SECTION_INDEX_INVALID
75    if passed an unrecognised section name.  */
76
77 static int
78 read_pe_section_index (const char *section_name)
79 {
80   if (strcmp (section_name, ".text") == 0)
81     {
82       return PE_SECTION_INDEX_TEXT;
83     }
84
85   else if (strcmp (section_name, ".data") == 0)
86     {
87       return PE_SECTION_INDEX_DATA;
88     }
89
90   else if (strcmp (section_name, ".bss") == 0)
91     {
92       return PE_SECTION_INDEX_BSS;
93     }
94
95   else
96     {
97       return PE_SECTION_INDEX_INVALID;
98     }
99 }
100
101 /* Get the index of the named section in our own full arrayi.
102    text, data and bss in that order.  Return PE_SECTION_INDEX_INVALID
103    if passed an unrecognised section name.  */
104
105 static int
106 get_pe_section_index (const char *section_name,
107                       struct read_pe_section_data *sections,
108                       int nb_sections)
109 {
110   int i;
111
112   for (i = 0; i < nb_sections; i++)
113     if (strcmp (sections[i].section_name, section_name) == 0)
114       return i;
115   return PE_SECTION_INDEX_INVALID;
116 }
117
118 /* Structure used by get_section_vmas function below
119    to access section_data array and the size of the array
120    stored in nb_sections field.  */
121 struct pe_sections_info
122 {
123   int nb_sections;
124   struct read_pe_section_data *sections;
125 };
126
127 /* Record the virtual memory address of a section.  */
128
129 static void
130 get_section_vmas (bfd *abfd, asection *sectp, void *context)
131 {
132   struct pe_sections_info *data = context;
133   struct read_pe_section_data *sections = data->sections;
134   int sectix = get_pe_section_index (sectp->name, sections,
135                                      data->nb_sections);
136
137   if (sectix != PE_SECTION_INDEX_INVALID)
138     {
139       /* Data within the section start at rva_start in the pe and at
140          bfd_get_section_vma() within memory.  Store the offset.  */
141
142       sections[sectix].vma_offset
143         = bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start;
144     }
145 }
146 \f
147 /* Create a minimal symbol entry for an exported symbol.
148    SYM_NAME contains the exported name or NULL if exported by ordinal,
149    FUNC_RVA contains the Relative Virtual Address of the symbol,
150    ORDINAL is the ordinal index value of the symbol,
151    SECTION_DATA contains information about the section in which the
152    symbol is declared,
153    DLL_NAME is the internal name of the DLL file,
154    OBJFILE is the objfile struct of DLL_NAME.  */
155
156 static void
157 add_pe_exported_sym (const char *sym_name,
158                      unsigned long func_rva,
159                      int ordinal,
160                      const struct read_pe_section_data *section_data,
161                      const char *dll_name, struct objfile *objfile)
162 {
163   char *qualified_name, *bare_name;
164   /* Add the stored offset to get the loaded address of the symbol.  */
165   CORE_ADDR vma = func_rva + section_data->vma_offset;
166   int dll_name_len = strlen (dll_name);
167
168   /* Generate a (hopefully unique) qualified name using the first part
169      of the dll name, e.g. KERNEL32!AddAtomA.  This matches the style
170      used by windbg from the "Microsoft Debugging Tools for Windows".  */
171
172   if (sym_name == NULL || *sym_name == '\0')
173     bare_name = xstrprintf ("#%d", ordinal);
174   else
175     bare_name = xstrdup (sym_name);
176
177   qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);
178
179   if ((section_data->ms_type == mst_unknown) && debug_coff_pe_read)
180     fprintf_unfiltered (gdb_stdlog , _("Unknown section type for \"%s\""
181                         " for entry \"%s\" in dll \"%s\"\n"),
182                         section_data->section_name, sym_name, dll_name);
183
184   prim_record_minimal_symbol (qualified_name, vma,
185                               section_data->ms_type, objfile);
186
187   /* Enter the plain name as well, which might not be unique.  */
188   prim_record_minimal_symbol (bare_name, vma, section_data->ms_type, objfile);
189   if (debug_coff_pe_read > 1)
190     fprintf_unfiltered (gdb_stdlog, _("Adding exported symbol \"%s\""
191                         " in dll \"%s\"\n"), sym_name, dll_name);
192   xfree (qualified_name);
193   xfree (bare_name);
194 }
195
196 /* Create a minimal symbol entry for an exported forward symbol.
197    Return 1 if the forwarded function was found 0 otherwise.
198    SYM_NAME contains the exported name or NULL if exported by ordinal,
199    FORWARD_DLL_NAME is the name of the DLL in which the target symobl resides,
200    FORWARD_FUNC_NAME is the name of the target symbol in that DLL,
201    ORDINAL is the ordinal index value of the symbol,
202    DLL_NAME is the internal name of the DLL file,
203    OBJFILE is the objfile struct of DLL_NAME.  */
204
205 static int
206 add_pe_forwarded_sym (const char *sym_name, const char *forward_dll_name,
207                       const char *forward_func_name, int ordinal,
208                       const char *dll_name, struct objfile *objfile)
209 {
210   CORE_ADDR vma;
211   struct objfile *forward_objfile;
212   struct minimal_symbol *msymbol;
213   short section;
214   enum minimal_symbol_type msymtype;
215   int dll_name_len = strlen (dll_name);
216   char *qualified_name, *bare_name;
217   int forward_dll_name_len = strlen (forward_dll_name);
218   int forward_func_name_len = strlen (forward_func_name);
219   int forward_len = forward_dll_name_len + forward_func_name_len + 2;
220   char *forward_qualified_name = alloca (forward_len);
221
222   xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name,
223              forward_func_name);
224
225
226   msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name,
227                                                &forward_objfile);
228
229   if (!msymbol)
230     {
231       int i;
232
233       for (i = 0; i < forward_dll_name_len; i++)
234         forward_qualified_name[i] = tolower (forward_qualified_name[i]);
235       msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name,
236                                                    &forward_objfile);
237     }
238
239   if (!msymbol)
240     {
241       if (debug_coff_pe_read)
242         fprintf_unfiltered (gdb_stdlog, _("Unable to find function \"%s\" in"
243                             " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"),
244                             forward_func_name, forward_dll_name, sym_name,
245                             dll_name);
246       return 0;
247     }
248
249   if (debug_coff_pe_read > 1)
250     fprintf_unfiltered (gdb_stdlog, _("Adding forwarded exported symbol"
251                         " \"%s\" in dll \"%s\", pointing to \"%s\"\n"),
252                         sym_name, dll_name, forward_qualified_name);
253
254   vma = SYMBOL_VALUE_ADDRESS (msymbol);
255   section = SYMBOL_SECTION (msymbol);
256   msymtype = MSYMBOL_TYPE (msymbol);
257
258   /* Generate a (hopefully unique) qualified name using the first part
259      of the dll name, e.g. KERNEL32!AddAtomA.  This matches the style
260      used by windbg from the "Microsoft Debugging Tools for Windows".  */
261
262   if (sym_name == NULL || *sym_name == '\0')
263     bare_name = xstrprintf ("#%d", ordinal);
264   else
265     bare_name = xstrdup (sym_name);
266
267   qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);
268
269   prim_record_minimal_symbol (qualified_name, vma, msymtype, objfile);
270
271   /* Enter the plain name as well, which might not be unique.  */
272   prim_record_minimal_symbol (bare_name, vma, msymtype, objfile);
273   xfree (qualified_name);
274   xfree (bare_name);
275
276   return 1;
277 }
278
279 /* Truncate a dll_name at the last dot character.  */
280
281 static void
282 read_pe_truncate_name (char *dll_name)
283 {
284   char *last_point = strrchr (dll_name, '.');
285
286   if (last_point != NULL)
287     *last_point = '\0';
288 }
289 \f
290 /* Low-level support functions, direct from the ld module pe-dll.c.  */
291 static unsigned int
292 pe_get16 (bfd *abfd, int where)
293 {
294   unsigned char b[2];
295
296   bfd_seek (abfd, (file_ptr) where, SEEK_SET);
297   bfd_bread (b, (bfd_size_type) 2, abfd);
298   return b[0] + (b[1] << 8);
299 }
300
301 static unsigned int
302 pe_get32 (bfd *abfd, int where)
303 {
304   unsigned char b[4];
305
306   bfd_seek (abfd, (file_ptr) where, SEEK_SET);
307   bfd_bread (b, (bfd_size_type) 4, abfd);
308   return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
309 }
310
311 static unsigned int
312 pe_as16 (void *ptr)
313 {
314   unsigned char *b = ptr;
315
316   return b[0] + (b[1] << 8);
317 }
318
319 static unsigned int
320 pe_as32 (void *ptr)
321 {
322   unsigned char *b = ptr;
323
324   return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
325 }
326 \f
327 /* Read the (non-debug) export symbol table from a portable
328    executable.  Code originally lifted from the ld function
329    pe_implied_import_dll in pe-dll.c.  */
330
331 void
332 read_pe_exported_syms (struct objfile *objfile)
333 {
334   bfd *dll = objfile->obfd;
335   unsigned long nbnormal, nbforward;
336   unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
337   unsigned long export_opthdrrva, export_opthdrsize;
338   unsigned long export_rva, export_size, nsections, secptr, expptr;
339   unsigned long exp_funcbase;
340   unsigned char *expdata, *erva;
341   unsigned long name_rvas, ordinals, nexp, ordbase;
342   char *dll_name = (char *) dll->filename;
343   int otherix = PE_SECTION_TABLE_SIZE;
344   int exportix = -1;
345   int is_pe64 = 0;
346   int is_pe32 = 0;
347
348   /* Array elements are for text, data and bss in that order
349      Initialization with RVA_START > RVA_END guarantees that
350      unused sections won't be matched.  */
351   struct read_pe_section_data *section_data;
352   struct pe_sections_info pe_sections_info;
353
354   struct cleanup *back_to = make_cleanup (null_cleanup, 0);
355
356   char const *target = bfd_get_target (objfile->obfd);
357
358   section_data = xzalloc (PE_SECTION_TABLE_SIZE
359                          * sizeof (struct read_pe_section_data));
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       return;
388     }
389
390   /* Get pe_header, optional header and numbers of export entries.  */
391   pe_header_offset = pe_get32 (dll, 0x3c);
392   opthdr_ofs = pe_header_offset + 4 + 20;
393   if (is_pe64)
394     num_entries = pe_get32 (dll, opthdr_ofs + 108);
395   else
396     num_entries = pe_get32 (dll, opthdr_ofs + 92);
397
398   if (num_entries < 1)          /* No exports.  */
399     {
400       return;
401     }
402   if (is_pe64)
403     {
404       export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112);
405       export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116);
406     }
407   else
408     {
409       export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96);
410       export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100);
411     }
412   nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
413   secptr = (pe_header_offset + 4 + 20 +
414             pe_get16 (dll, pe_header_offset + 4 + 16));
415   expptr = 0;
416   export_size = 0;
417
418   /* Get the rva and size of the export section.  */
419   for (i = 0; i < nsections; i++)
420     {
421       char sname[8];
422       unsigned long secptr1 = secptr + 40 * i;
423       unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
424       unsigned long vsize = pe_get32 (dll, secptr1 + 16);
425       unsigned long fptr = pe_get32 (dll, secptr1 + 20);
426
427       bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
428       bfd_bread (sname, (bfd_size_type) sizeof (sname), dll);
429
430       if ((strcmp (sname, ".edata") == 0)
431           || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize))
432         {
433           if (strcmp (sname, ".edata") != 0)
434             {
435               if (debug_coff_pe_read)
436                 fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll "
437                                     "\"%s\" is in section \"%s\"\n"),
438                                     dll_name, sname);
439             }
440           else if (export_opthdrrva != vaddr && debug_coff_pe_read)
441             fprintf_unfiltered (gdb_stdlog, _("Wrong value of export RVA"
442                                 " for dll \"%s\": 0x%lx instead of 0x%lx\n"),
443                                 dll_name, export_opthdrrva, vaddr);
444           expptr = fptr + (export_opthdrrva - vaddr);
445           exportix = i;
446           break;
447         }
448     }
449
450   export_rva = export_opthdrrva;
451   export_size = export_opthdrsize;
452
453   if (export_size == 0)
454     {
455       /* Empty export table.  */
456       return;
457     }
458
459   /* Scan sections and store the base and size of the relevant
460      sections.  */
461   for (i = 0; i < nsections; i++)
462     {
463       unsigned long secptr1 = secptr + 40 * i;
464       unsigned long vsize = pe_get32 (dll, secptr1 + 8);
465       unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
466       unsigned long characteristics = pe_get32 (dll, secptr1 + 36);
467       char sec_name[9];
468       int sectix;
469
470       memset (sec_name, 0, sizeof (sec_name));
471       bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
472       bfd_bread (sec_name, (bfd_size_type) 8, dll);
473
474       sectix = read_pe_section_index (sec_name);
475
476       if (sectix != PE_SECTION_INDEX_INVALID)
477         {
478           section_data[sectix].rva_start = vaddr;
479           section_data[sectix].rva_end = vaddr + vsize;
480         }
481       else
482         {
483           char *name;
484
485           section_data = xrealloc (section_data, (otherix + 1)
486                                    * sizeof (struct read_pe_section_data));
487           name = xstrdup (sec_name);
488           section_data[otherix].section_name = name;
489           make_cleanup (xfree, name);
490           section_data[otherix].rva_start = vaddr;
491           section_data[otherix].rva_end = vaddr + vsize;
492           section_data[otherix].vma_offset = 0;
493           if (characteristics & IMAGE_SCN_CNT_CODE)
494             section_data[otherix].ms_type = mst_text;
495           else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
496             section_data[otherix].ms_type = mst_data;
497           else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
498             section_data[otherix].ms_type = mst_bss;
499           else
500             section_data[otherix].ms_type = mst_unknown;
501           otherix++;
502         }
503     }
504
505   expdata = (unsigned char *) xmalloc (export_size);
506   make_cleanup (xfree, expdata);
507
508   bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
509   bfd_bread (expdata, (bfd_size_type) export_size, dll);
510   erva = expdata - export_rva;
511
512   nexp = pe_as32 (expdata + 24);
513   name_rvas = pe_as32 (expdata + 32);
514   ordinals = pe_as32 (expdata + 36);
515   ordbase = pe_as32 (expdata + 16);
516   exp_funcbase = pe_as32 (expdata + 28);
517
518   /* Use internal dll name instead of full pathname.  */
519   dll_name = pe_as32 (expdata + 12) + erva;
520
521   pe_sections_info.nb_sections = otherix;
522   pe_sections_info.sections = section_data;
523
524   bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info);
525
526   /* Adjust the vma_offsets in case this PE got relocated. This
527      assumes that *all* sections share the same relocation offset
528      as the text section.  */
529   for (i = 0; i < otherix; i++)
530     {
531       section_data[i].vma_offset
532         += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
533     }
534
535   /* Truncate name at first dot. Should maybe also convert to all
536      lower case for convenience on Windows.  */
537   read_pe_truncate_name (dll_name);
538
539   if (debug_coff_pe_read)
540     fprintf_unfiltered (gdb_stdlog, _("DLL \"%s\" has %ld export entries,"
541                         " base=%ld\n"), dll_name, nexp, ordbase);
542   nbforward = 0;
543   nbnormal = 0;
544   /* Iterate through the list of symbols.  */
545   for (i = 0; i < nexp; i++)
546     {
547       /* Pointer to the names vector.  */
548       unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
549       /* Retrieve ordinal value.  */
550
551       unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);
552
553
554       /* Pointer to the function address vector.  */
555       /* This is relatived to ordinal value. */
556       unsigned long func_rva = pe_as32 (erva + exp_funcbase +
557                                         ordinal * 4);
558
559       /* Find this symbol's section in our own array.  */
560       int sectix = 0;
561       int section_found = 0;
562
563       /* First handle forward cases.  */
564       if (func_rva >= export_rva && func_rva < export_rva + export_size)
565         {
566           char *forward_name = (char *) (erva + func_rva);
567           char *funcname = (char *) (erva + name_rva);
568           char *forward_dll_name = forward_name;
569           char *forward_func_name = forward_name;
570           char *sep = strrchr (forward_name, '.');
571
572           if (sep)
573             {
574               int len = (int) (sep - forward_name);
575
576               forward_dll_name = alloca (len + 1);
577               strncpy (forward_dll_name, forward_name, len);
578               forward_dll_name[len] = '\0';
579               forward_func_name = ++sep;
580             }
581           if (add_pe_forwarded_sym (funcname, forward_dll_name,
582                                     forward_func_name, ordinal,
583                                     dll_name, objfile) != 0)
584             ++nbforward;
585           continue;
586         }
587
588       for (sectix = 0; sectix < otherix; ++sectix)
589         {
590           if ((func_rva >= section_data[sectix].rva_start)
591               && (func_rva < section_data[sectix].rva_end))
592             {
593               section_found = 1;
594               add_pe_exported_sym (erva + name_rva,
595                                    func_rva, ordinal,
596                                    section_data + sectix, dll_name, objfile);
597               ++nbnormal;
598               break;
599             }
600         }
601       if (!section_found)
602         {
603           char *funcname = (char *) (erva + name_rva);
604
605           if (name_rva == 0)
606             {
607               add_pe_exported_sym (NULL, func_rva, ordinal,
608                                    section_data, dll_name, objfile);
609               ++nbnormal;
610             }
611           else if (debug_coff_pe_read)
612             fprintf_unfiltered (gdb_stdlog, _("Export name \"%s\" ord. %lu,"
613                                 " RVA 0x%lx in dll \"%s\" not handled\n"),
614                                 funcname, ordinal, func_rva, dll_name);
615         }
616     }
617
618   if (debug_coff_pe_read)
619     fprintf_unfiltered (gdb_stdlog, _("Finished reading \"%s\", exports %ld,"
620                         " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal,
621                         nbforward, nbnormal + nbforward, nexp);
622   /* Discard expdata and section_data.  */
623   do_cleanups (back_to);
624 }
625
626 /* Extract from ABFD the offset of the .text section.
627    This offset is mainly related to the offset within the file.
628    The value was previously expected to be 0x1000 for all files,
629    but some Windows OS core DLLs seem to use 0x10000 section alignement
630    which modified the return value of that function.
631    Still return default 0x1000 value if ABFD is NULL or
632    if '.text' section is not found, but that should not happen...  */
633
634 #define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000
635
636 CORE_ADDR
637 pe_text_section_offset (struct bfd *abfd)
638
639 {
640   unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
641   unsigned long export_rva, export_size, nsections, secptr, expptr;
642   unsigned long exp_funcbase;
643   unsigned char *expdata, *erva;
644   unsigned long name_rvas, ordinals, nexp, ordbase;
645   char *dll_name;
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   opthdr_ofs = pe_header_offset + 4 + 20;
673   nsections = pe_get16 (abfd, pe_header_offset + 4 + 2);
674   secptr = (pe_header_offset + 4 + 20 +
675             pe_get16 (abfd, pe_header_offset + 4 + 16));
676
677   /* Get the rva and size of the export section.  */
678   for (i = 0; i < nsections; i++)
679     {
680       char sname[8];
681       unsigned long secptr1 = secptr + 40 * i;
682       unsigned long vaddr = pe_get32 (abfd, secptr1 + 12);
683
684       bfd_seek (abfd, (file_ptr) secptr1, SEEK_SET);
685       bfd_bread (sname, (bfd_size_type) 8, abfd);
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_uinteger_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 }