xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/coff-pe-read.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
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-2023 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 "gdbsupport/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   std::string 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 
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 		      const std::vector<read_pe_section_data> &sections)
104 {
105   for (int i = 0; i < sections.size (); i++)
106     if (sections[i].section_name == section_name)
107       return i;
108   return PE_SECTION_INDEX_INVALID;
109 }
110 
111 
112 /* Create a minimal symbol entry for an exported symbol.
113    SYM_NAME contains the exported name or NULL if exported by ordinal,
114    FUNC_RVA contains the Relative Virtual Address of the symbol,
115    ORDINAL is the ordinal index value of the symbol,
116    SECTION_DATA contains information about the section in which the
117    symbol is declared,
118    DLL_NAME is the internal name of the DLL file,
119    OBJFILE is the objfile struct of DLL_NAME.  */
120 
121 static void
122 add_pe_exported_sym (minimal_symbol_reader &reader,
123 		     const char *sym_name,
124 		     unsigned long func_rva,
125 		     int ordinal,
126 		     const struct read_pe_section_data *section_data,
127 		     const char *dll_name, struct objfile *objfile)
128 {
129   /* Add the stored offset to get the loaded address of the symbol.  */
130   CORE_ADDR vma = func_rva + 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 symobl 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
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   CORE_ADDR vma, baseaddr;
178   struct bound_minimal_symbol msymbol;
179   enum minimal_symbol_type msymtype;
180   int forward_dll_name_len = strlen (forward_dll_name);
181   short section;
182 
183   std::string forward_qualified_name = string_printf ("%s!%s",
184 						      forward_dll_name,
185 						      forward_func_name);
186 
187   msymbol = lookup_bound_minimal_symbol (forward_qualified_name.c_str ());
188 
189   if (!msymbol.minsym)
190     {
191       int i;
192 
193       for (i = 0; i < forward_dll_name_len; i++)
194 	forward_qualified_name[i] = tolower (forward_qualified_name[i]);
195       msymbol = lookup_bound_minimal_symbol (forward_qualified_name.c_str ());
196     }
197 
198   if (!msymbol.minsym)
199     {
200       if (debug_coff_pe_read)
201 	gdb_printf (gdb_stdlog, _("Unable to find function \"%s\" in"
202 				  " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"),
203 		    forward_func_name, forward_dll_name, sym_name,
204 		    dll_name);
205       return 0;
206     }
207 
208   if (debug_coff_pe_read > 1)
209     gdb_printf (gdb_stdlog, _("Adding forwarded exported symbol"
210 			      " \"%s\" in dll \"%s\", pointing to \"%s\"\n"),
211 		sym_name, dll_name, forward_qualified_name.c_str ());
212 
213   vma = msymbol.value_address ();
214   msymtype = msymbol.minsym->type ();
215   section = msymbol.minsym->section_index ();
216 
217   /* Generate a (hopefully unique) qualified name using the first part
218      of the dll name, e.g. KERNEL32!AddAtomA.  This matches the style
219      used by windbg from the "Microsoft Debugging Tools for Windows".  */
220 
221   std::string bare_name;
222   if (sym_name == NULL || *sym_name == '\0')
223     bare_name = string_printf ("#%d", ordinal);
224   else
225     bare_name = sym_name;
226 
227   std::string qualified_name
228     = string_printf ("%s!%s", dll_name, bare_name.c_str ());
229 
230   /* Note that this code makes a minimal symbol whose value may point
231      outside of any section in this objfile.  These symbols can't
232      really be relocated properly, but nevertheless we make a stab at
233      it, choosing an approach consistent with the history of this
234      code.  */
235   baseaddr = objfile->text_section_offset ();
236 
237   reader.record_with_info (qualified_name.c_str (), vma - baseaddr, msymtype,
238 			   section);
239 
240   /* Enter the plain name as well, which might not be unique.  */
241   reader.record_with_info (bare_name.c_str(), vma - baseaddr, msymtype,
242 			   section);
243 
244   return 1;
245 }
246 
247 /* Truncate a dll_name at the last dot character.  */
248 
249 static void
250 read_pe_truncate_name (char *dll_name)
251 {
252   char *last_point = strrchr (dll_name, '.');
253 
254   if (last_point != NULL)
255     *last_point = '\0';
256 }
257 
258 /* Low-level support functions, direct from the ld module pe-dll.c.  */
259 static unsigned int
260 pe_get16 (bfd *abfd, int where)
261 {
262   unsigned char b[2];
263 
264   bfd_seek (abfd, (file_ptr) where, SEEK_SET);
265   bfd_bread (b, (bfd_size_type) 2, abfd);
266   return b[0] + (b[1] << 8);
267 }
268 
269 static unsigned int
270 pe_get32 (bfd *abfd, int where)
271 {
272   unsigned char b[4];
273 
274   bfd_seek (abfd, (file_ptr) where, SEEK_SET);
275   bfd_bread (b, (bfd_size_type) 4, abfd);
276   return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
277 }
278 
279 static unsigned int
280 pe_as16 (void *ptr)
281 {
282   unsigned char *b = (unsigned char *) ptr;
283 
284   return b[0] + (b[1] << 8);
285 }
286 
287 static unsigned int
288 pe_as32 (void *ptr)
289 {
290   unsigned char *b = (unsigned char *) ptr;
291 
292   return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
293 }
294 
295 /* Read the (non-debug) export symbol table from a portable
296    executable.  Code originally lifted from the ld function
297    pe_implied_import_dll in pe-dll.c.  */
298 
299 void
300 read_pe_exported_syms (minimal_symbol_reader &reader,
301 		       struct objfile *objfile)
302 {
303   bfd *dll = objfile->obfd.get ();
304   unsigned long nbnormal, nbforward;
305   unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
306   unsigned long export_opthdrrva, export_opthdrsize;
307   unsigned long export_rva, export_size, nsections, secptr, expptr;
308   unsigned long exp_funcbase;
309   unsigned char *expdata, *erva;
310   unsigned long name_rvas, ordinals, nexp, ordbase;
311   int otherix = PE_SECTION_TABLE_SIZE;
312   int is_pe64 = 0;
313   int is_pe32 = 0;
314 
315   char const *target = bfd_get_target (objfile->obfd.get ());
316 
317   std::vector<struct read_pe_section_data> section_data
318     (PE_SECTION_TABLE_SIZE);
319 
320   for (i=0; i < PE_SECTION_TABLE_SIZE; i++)
321     {
322       section_data[i].vma_offset = 0;
323       section_data[i].rva_start = 1;
324       section_data[i].rva_end = 0;
325     };
326   section_data[PE_SECTION_INDEX_TEXT].ms_type = mst_text;
327   section_data[PE_SECTION_INDEX_TEXT].section_name = ".text";
328   section_data[PE_SECTION_INDEX_DATA].ms_type = mst_data;
329   section_data[PE_SECTION_INDEX_DATA].section_name = ".data";
330   section_data[PE_SECTION_INDEX_BSS].ms_type = mst_bss;
331   section_data[PE_SECTION_INDEX_BSS].section_name = ".bss";
332 
333   is_pe64 = (strcmp (target, "pe-x86-64") == 0
334 	     || strcmp (target, "pei-x86-64") == 0
335 	     || strcmp (target, "pe-aarch64") == 0
336 	     || strcmp (target, "pei-aarch64") == 0);
337   is_pe32 = (strcmp (target, "pe-i386") == 0
338 	     || strcmp (target, "pei-i386") == 0
339 	     || strcmp (target, "pe-arm-wince-little") == 0
340 	     || strcmp (target, "pei-arm-wince-little") == 0);
341   if (!is_pe32 && !is_pe64)
342     {
343       /* This is not a recognized PE format file.  Abort now, because
344 	 the code is untested on anything else.  *FIXME* test on
345 	 further architectures and loosen or remove this test.  */
346       return;
347     }
348 
349   /* Get pe_header, optional header and numbers of export entries.  */
350   pe_header_offset = pe_get32 (dll, 0x3c);
351   opthdr_ofs = pe_header_offset + 4 + 20;
352   if (is_pe64)
353     num_entries = pe_get32 (dll, opthdr_ofs + 108);
354   else
355     num_entries = pe_get32 (dll, opthdr_ofs + 92);
356 
357   if (num_entries < 1)		/* No exports.  */
358     return;
359   if (is_pe64)
360     {
361       export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112);
362       export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116);
363     }
364   else
365     {
366       export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96);
367       export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100);
368     }
369   nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
370   secptr = (pe_header_offset + 4 + 20 +
371 	    pe_get16 (dll, pe_header_offset + 4 + 16));
372   expptr = 0;
373   export_size = 0;
374 
375   /* Get the rva and size of the export section.  */
376   for (i = 0; i < nsections; i++)
377     {
378       char sname[8];
379       unsigned long secptr1 = secptr + 40 * i;
380       unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
381       unsigned long vsize = pe_get32 (dll, secptr1 + 16);
382       unsigned long fptr = pe_get32 (dll, secptr1 + 20);
383 
384       bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
385       bfd_bread (sname, (bfd_size_type) sizeof (sname), dll);
386 
387       if ((strcmp (sname, ".edata") == 0)
388 	  || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize))
389 	{
390 	  if (strcmp (sname, ".edata") != 0)
391 	    {
392 	      if (debug_coff_pe_read)
393 		gdb_printf (gdb_stdlog, _("Export RVA for dll "
394 					  "\"%s\" is in section \"%s\"\n"),
395 			    bfd_get_filename (dll), sname);
396 	    }
397 	  else if (export_opthdrrva != vaddr && debug_coff_pe_read)
398 	    gdb_printf (gdb_stdlog, _("Wrong value of export RVA"
399 				      " for dll \"%s\": 0x%lx instead of 0x%lx\n"),
400 			bfd_get_filename (dll), export_opthdrrva, vaddr);
401 	  expptr = fptr + (export_opthdrrva - vaddr);
402 	  break;
403 	}
404     }
405 
406   if (expptr == 0)
407     {
408       /* no section contains export table rva */
409       return;
410     }
411 
412   export_rva = export_opthdrrva;
413   export_size = export_opthdrsize;
414 
415   if (export_size == 0)
416     {
417       /* Empty export table.  */
418       return;
419     }
420 
421   /* Scan sections and store the base and size of the relevant
422      sections.  */
423   for (i = 0; i < nsections; i++)
424     {
425       unsigned long secptr1 = secptr + 40 * i;
426       unsigned long vsize = pe_get32 (dll, secptr1 + 8);
427       unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
428       unsigned long characteristics = pe_get32 (dll, secptr1 + 36);
429       char sec_name[SCNNMLEN + 1];
430       int sectix;
431       unsigned int bfd_section_index;
432       asection *section;
433 
434       bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
435       bfd_bread (sec_name, (bfd_size_type) SCNNMLEN, dll);
436       sec_name[SCNNMLEN] = '\0';
437 
438       sectix = read_pe_section_index (sec_name);
439       section = bfd_get_section_by_name (dll, sec_name);
440       if (section)
441 	bfd_section_index = section->index;
442       else
443 	bfd_section_index = -1;
444 
445       if (sectix != PE_SECTION_INDEX_INVALID)
446 	{
447 	  section_data[sectix].rva_start = vaddr;
448 	  section_data[sectix].rva_end = vaddr + vsize;
449 	  section_data[sectix].index = bfd_section_index;
450 	}
451       else
452 	{
453 	  section_data.resize (otherix + 1);
454 	  section_data[otherix].section_name = sec_name;
455 	  section_data[otherix].rva_start = vaddr;
456 	  section_data[otherix].rva_end = vaddr + vsize;
457 	  section_data[otherix].vma_offset = 0;
458 	  section_data[otherix].index = bfd_section_index;
459 	  if (characteristics & IMAGE_SCN_CNT_CODE)
460 	    section_data[otherix].ms_type = mst_text;
461 	  else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
462 	    section_data[otherix].ms_type = mst_data;
463 	  else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
464 	    section_data[otherix].ms_type = mst_bss;
465 	  else
466 	    section_data[otherix].ms_type = mst_unknown;
467 	  otherix++;
468 	}
469     }
470 
471   gdb::def_vector<unsigned char> expdata_storage (export_size);
472   expdata = expdata_storage.data ();
473 
474   bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
475   bfd_bread (expdata, (bfd_size_type) export_size, dll);
476   erva = expdata - export_rva;
477 
478   nexp = pe_as32 (expdata + 24);
479   name_rvas = pe_as32 (expdata + 32);
480   ordinals = pe_as32 (expdata + 36);
481   ordbase = pe_as32 (expdata + 16);
482   exp_funcbase = pe_as32 (expdata + 28);
483 
484   /* Use internal dll name instead of full pathname.  */
485   char *dll_name = (char *) (pe_as32 (expdata + 12) + erva);
486 
487   for (asection *sectp : gdb_bfd_sections (dll))
488     {
489       int sectix = get_pe_section_index (sectp->name, section_data);
490       if (sectix != PE_SECTION_INDEX_INVALID)
491 	{
492 	  /* Data within the section start at rva_start in the pe and at
493 	     bfd_get_section_vma() within memory.  Store the offset.  */
494 	  section_data[sectix].vma_offset
495 	    = bfd_section_vma (sectp) - section_data[sectix].rva_start;
496 	}
497     }
498 
499   /* Truncate name at first dot. Should maybe also convert to all
500      lower case for convenience on Windows.  */
501   read_pe_truncate_name (dll_name);
502 
503   if (debug_coff_pe_read)
504     gdb_printf (gdb_stdlog, _("DLL \"%s\" has %ld export entries,"
505 			      " base=%ld\n"), dll_name, nexp, ordbase);
506   nbforward = 0;
507   nbnormal = 0;
508   /* Iterate through the list of symbols.  */
509   for (i = 0; i < nexp; i++)
510     {
511       /* Pointer to the names vector.  */
512       unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
513       /* Retrieve ordinal value.  */
514 
515       unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);
516 
517 
518       /* Pointer to the function address vector.  */
519       /* This is relative to ordinal value. */
520       unsigned long func_rva = pe_as32 (erva + exp_funcbase +
521 					ordinal * 4);
522 
523       /* Find this symbol's section in our own array.  */
524       int sectix = 0;
525       int section_found = 0;
526 
527       /* First handle forward cases.  */
528       if (func_rva >= export_rva && func_rva < export_rva + export_size)
529 	{
530 	  const char *forward_name = (const char *) (erva + func_rva);
531 	  const char *funcname = (const char *) (erva + name_rva);
532 	  const char *forward_dll_name = forward_name;
533 	  const char *forward_func_name = forward_name;
534 	  const char *sep = strrchr (forward_name, '.');
535 
536 	  std::string name_storage;
537 	  if (sep != nullptr)
538 	    {
539 	      int len = (int) (sep - forward_name);
540 
541 	      name_storage = std::string (forward_name, len);
542 	      forward_dll_name = name_storage.c_str ();
543 	      forward_func_name = sep + 1;
544 	    }
545 	  if (add_pe_forwarded_sym (reader, funcname, forward_dll_name,
546 				    forward_func_name, ordinal,
547 				    dll_name, objfile) != 0)
548 	    ++nbforward;
549 	  continue;
550 	}
551 
552       for (sectix = 0; sectix < otherix; ++sectix)
553 	{
554 	  if ((func_rva >= section_data[sectix].rva_start)
555 	      && (func_rva < section_data[sectix].rva_end))
556 	    {
557 	      const char *sym_name = (const char *) (erva + name_rva);
558 
559 	      section_found = 1;
560 	      add_pe_exported_sym (reader, sym_name, func_rva, ordinal,
561 				   &section_data[sectix], dll_name, objfile);
562 	      ++nbnormal;
563 	      break;
564 	    }
565 	}
566       if (!section_found)
567 	{
568 	  const char *funcname = (const char *) (erva + name_rva);
569 
570 	  if (name_rva == 0)
571 	    {
572 	      add_pe_exported_sym (reader, NULL, func_rva, ordinal,
573 				   &section_data[0], dll_name, objfile);
574 	      ++nbnormal;
575 	    }
576 	  else if (debug_coff_pe_read)
577 	    gdb_printf (gdb_stdlog, _("Export name \"%s\" ord. %lu,"
578 				      " RVA 0x%lx in dll \"%s\" not handled\n"),
579 			funcname, ordinal, func_rva, dll_name);
580 	}
581     }
582 
583   if (debug_coff_pe_read)
584     gdb_printf (gdb_stdlog, _("Finished reading \"%s\", exports %ld,"
585 			      " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal,
586 		nbforward, nbnormal + nbforward, nexp);
587 }
588 
589 /* Extract from ABFD the offset of the .text section.
590    This offset is mainly related to the offset within the file.
591    The value was previously expected to be 0x1000 for all files,
592    but some Windows OS core DLLs seem to use 0x10000 section alignment
593    which modified the return value of that function.
594    Still return default 0x1000 value if ABFD is NULL or
595    if '.text' section is not found, but that should not happen...  */
596 
597 #define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000
598 
599 CORE_ADDR
600 pe_text_section_offset (struct bfd *abfd)
601 
602 {
603   unsigned long pe_header_offset, i;
604   unsigned long nsections, secptr;
605   int is_pe64 = 0;
606   int is_pe32 = 0;
607   char const *target;
608 
609   if (!abfd)
610     return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
611 
612   target = bfd_get_target (abfd);
613 
614   is_pe64 = (strcmp (target, "pe-x86-64") == 0
615 	     || strcmp (target, "pei-x86-64") == 0
616 	     || strcmp (target, "pe-aarch64") == 0
617 	     || strcmp (target, "pei-aarch64") == 0);
618   is_pe32 = (strcmp (target, "pe-i386") == 0
619 	     || strcmp (target, "pei-i386") == 0
620 	     || strcmp (target, "pe-arm-wince-little") == 0
621 	     || strcmp (target, "pei-arm-wince-little") == 0);
622 
623   if (!is_pe32 && !is_pe64)
624     {
625       /* This is not a recognized PE format file.  Abort now, because
626 	 the code is untested on anything else.  *FIXME* test on
627 	 further architectures and loosen or remove this test.  */
628       return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
629     }
630 
631   /* Get pe_header, optional header and numbers of sections.  */
632   pe_header_offset = pe_get32 (abfd, 0x3c);
633   nsections = pe_get16 (abfd, pe_header_offset + 4 + 2);
634   secptr = (pe_header_offset + 4 + 20 +
635 	    pe_get16 (abfd, pe_header_offset + 4 + 16));
636 
637   /* Get the rva and size of the export section.  */
638   for (i = 0; i < nsections; i++)
639     {
640       char sname[SCNNMLEN + 1];
641       unsigned long secptr1 = secptr + 40 * i;
642       unsigned long vaddr = pe_get32 (abfd, secptr1 + 12);
643 
644       bfd_seek (abfd, (file_ptr) secptr1, SEEK_SET);
645       bfd_bread (sname, (bfd_size_type) SCNNMLEN, abfd);
646       sname[SCNNMLEN] = '\0';
647       if (strcmp (sname, ".text") == 0)
648 	return vaddr;
649     }
650 
651   return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
652 }
653 
654 /* Implements "show debug coff_pe_read" command.  */
655 
656 static void
657 show_debug_coff_pe_read (struct ui_file *file, int from_tty,
658 			 struct cmd_list_element *c, const char *value)
659 {
660   gdb_printf (file, _("Coff PE read debugging is %s.\n"), value);
661 }
662 
663 /* Adds "Set/show debug coff_pe_read" commands.  */
664 
665 void _initialize_coff_pe_read ();
666 void
667 _initialize_coff_pe_read ()
668 {
669   add_setshow_zuinteger_cmd ("coff-pe-read", class_maintenance,
670 			     &debug_coff_pe_read,
671 			     _("Set coff PE read debugging."),
672 			     _("Show coff PE read debugging."),
673 			     _("When set, debugging messages for coff reading "
674 			       "of exported symbols are displayed."),
675 			     NULL, show_debug_coff_pe_read,
676 			     &setdebuglist, &showdebuglist);
677 }
678