]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/coff-pe-read.c
change minsym representation
[thirdparty/binutils-gdb.git] / gdb / coff-pe-read.c
CommitLineData
1b6bc7e0
CF
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
ecd75fc8 5 Copyright (C) 2003-2014 Free Software Foundation, Inc.
1b6bc7e0
CF
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
a9762ec7 11 the Free Software Foundation; either version 3 of the License, or
1b6bc7e0
CF
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
a9762ec7 20 along with this program. If not, see <http://www.gnu.org/licenses/>.
1b6bc7e0 21
aff410f1 22 Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */
1b6bc7e0 23
0baeab03
PA
24#include "defs.h"
25
1b6bc7e0
CF
26#include "coff-pe-read.h"
27
81de56be 28#include "bfd.h"
1b6bc7e0
CF
29#include "gdbtypes.h"
30
3999122f
PM
31#include "command.h"
32#include "gdbcmd.h"
1b6bc7e0
CF
33#include "symtab.h"
34#include "symfile.h"
35#include "objfiles.h"
3999122f 36#include "common/common-utils.h"
aab2f004 37#include "coff/internal.h"
3999122f
PM
38
39#include <ctype.h>
1b6bc7e0
CF
40
41/* Internal section information */
42
3999122f
PM
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. */
47static unsigned int debug_coff_pe_read;
48
1b6bc7e0
CF
49struct read_pe_section_data
50{
aff410f1
MS
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. */
f93ba80c 56 unsigned int index; /* BFD section number. */
3999122f 57 char *section_name; /* Recorded section name. */
1b6bc7e0
CF
58};
59
78ea0eca
PM
60#define IMAGE_SCN_CNT_CODE 0x20
61#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x40
62#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x80
1b6bc7e0
CF
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
aff410f1
MS
70 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
71 if passed an unrecognised section name. */
1b6bc7e0
CF
72
73static int
74read_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
f93ba80c 97/* Get the index of the named section in our own full array.
3999122f
PM
98 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
99 if passed an unrecognised section name. */
100
101static int
102get_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. */
117struct pe_sections_info
118{
119 int nb_sections;
120 struct read_pe_section_data *sections;
121};
122
aff410f1 123/* Record the virtual memory address of a section. */
1b6bc7e0
CF
124
125static void
126get_section_vmas (bfd *abfd, asection *sectp, void *context)
127{
3999122f
PM
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);
1b6bc7e0
CF
132
133 if (sectix != PE_SECTION_INDEX_INVALID)
134 {
135 /* Data within the section start at rva_start in the pe and at
aff410f1 136 bfd_get_section_vma() within memory. Store the offset. */
1b6bc7e0
CF
137
138 sections[sectix].vma_offset
139 = bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start;
140 }
141}
142\f
3999122f
PM
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. */
1b6bc7e0
CF
151
152static void
3999122f 153add_pe_exported_sym (const char *sym_name,
1b6bc7e0 154 unsigned long func_rva,
3999122f 155 int ordinal,
1b6bc7e0
CF
156 const struct read_pe_section_data *section_data,
157 const char *dll_name, struct objfile *objfile)
158{
3999122f 159 char *qualified_name, *bare_name;
aff410f1 160 /* Add the stored offset to get the loaded address of the symbol. */
1b6bc7e0 161 CORE_ADDR vma = func_rva + section_data->vma_offset;
1b6bc7e0
CF
162
163 /* Generate a (hopefully unique) qualified name using the first part
aff410f1
MS
164 of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
165 used by windbg from the "Microsoft Debugging Tools for Windows". */
1b6bc7e0 166
3999122f
PM
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);
1b6bc7e0 173
3999122f
PM
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);
1b6bc7e0 178
f93ba80c
PM
179 prim_record_minimal_symbol_and_info (qualified_name, vma,
180 section_data->ms_type,
181 section_data->index, objfile);
1b6bc7e0 182
3999122f 183 /* Enter the plain name as well, which might not be unique. */
f93ba80c
PM
184 prim_record_minimal_symbol_and_info (bare_name, vma, section_data->ms_type,
185 section_data->index, objfile);
3999122f
PM
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);
1b6bc7e0 189 xfree (qualified_name);
3999122f
PM
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
202static int
203add_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;
7cbd4a93 208 struct bound_minimal_symbol msymbol;
3999122f 209 enum minimal_symbol_type msymtype;
3999122f
PM
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);
f93ba80c 215 short section;
3999122f
PM
216
217 xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name,
218 forward_func_name);
219
220
7cbd4a93 221 msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name);
3999122f 222
7cbd4a93 223 if (!msymbol.minsym)
3999122f
PM
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]);
7cbd4a93 229 msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name);
3999122f
PM
230 }
231
7cbd4a93 232 if (!msymbol.minsym)
3999122f
PM
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
efd66ac6 247 vma = MSYMBOL_VALUE_ADDRESS (msymbol.minsym);
7cbd4a93 248 msymtype = MSYMBOL_TYPE (msymbol.minsym);
efd66ac6 249 section = MSYMBOL_SECTION (msymbol.minsym);
3999122f
PM
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
f93ba80c
PM
262 prim_record_minimal_symbol_and_info (qualified_name, vma, msymtype,
263 section, objfile);
1b6bc7e0 264
aff410f1 265 /* Enter the plain name as well, which might not be unique. */
f93ba80c
PM
266 prim_record_minimal_symbol_and_info (bare_name, vma, msymtype,
267 section, objfile);
3999122f
PM
268 xfree (qualified_name);
269 xfree (bare_name);
270
271 return 1;
1b6bc7e0
CF
272}
273
3999122f 274/* Truncate a dll_name at the last dot character. */
1b6bc7e0
CF
275
276static void
277read_pe_truncate_name (char *dll_name)
278{
3999122f 279 char *last_point = strrchr (dll_name, '.');
1b6bc7e0 280
3999122f
PM
281 if (last_point != NULL)
282 *last_point = '\0';
1b6bc7e0
CF
283}
284\f
aff410f1 285/* Low-level support functions, direct from the ld module pe-dll.c. */
1b6bc7e0
CF
286static unsigned int
287pe_get16 (bfd *abfd, int where)
288{
289 unsigned char b[2];
290
291 bfd_seek (abfd, (file_ptr) where, SEEK_SET);
292 bfd_bread (b, (bfd_size_type) 2, abfd);
293 return b[0] + (b[1] << 8);
294}
295
296static unsigned int
297pe_get32 (bfd *abfd, int where)
298{
299 unsigned char b[4];
300
301 bfd_seek (abfd, (file_ptr) where, SEEK_SET);
302 bfd_bread (b, (bfd_size_type) 4, abfd);
303 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
304}
305
3999122f
PM
306static unsigned int
307pe_as16 (void *ptr)
308{
309 unsigned char *b = ptr;
310
311 return b[0] + (b[1] << 8);
312}
313
1b6bc7e0
CF
314static unsigned int
315pe_as32 (void *ptr)
316{
317 unsigned char *b = ptr;
318
319 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
320}
321\f
322/* Read the (non-debug) export symbol table from a portable
aff410f1
MS
323 executable. Code originally lifted from the ld function
324 pe_implied_import_dll in pe-dll.c. */
1b6bc7e0
CF
325
326void
327read_pe_exported_syms (struct objfile *objfile)
328{
329 bfd *dll = objfile->obfd;
3999122f 330 unsigned long nbnormal, nbforward;
1b6bc7e0 331 unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
3999122f 332 unsigned long export_opthdrrva, export_opthdrsize;
1b6bc7e0
CF
333 unsigned long export_rva, export_size, nsections, secptr, expptr;
334 unsigned long exp_funcbase;
335 unsigned char *expdata, *erva;
336 unsigned long name_rvas, ordinals, nexp, ordbase;
3999122f
PM
337 char *dll_name = (char *) dll->filename;
338 int otherix = PE_SECTION_TABLE_SIZE;
a68ddad5
KT
339 int is_pe64 = 0;
340 int is_pe32 = 0;
1b6bc7e0
CF
341
342 /* Array elements are for text, data and bss in that order
3999122f 343 Initialization with RVA_START > RVA_END guarantees that
aff410f1 344 unused sections won't be matched. */
3999122f
PM
345 struct read_pe_section_data *section_data;
346 struct pe_sections_info pe_sections_info;
1b6bc7e0 347
3999122f 348 struct cleanup *back_to = make_cleanup (null_cleanup, 0);
1b6bc7e0
CF
349
350 char const *target = bfd_get_target (objfile->obfd);
351
3999122f
PM
352 section_data = xzalloc (PE_SECTION_TABLE_SIZE
353 * sizeof (struct read_pe_section_data));
354
355 make_cleanup (free_current_contents, &section_data);
356
357 for (i=0; i < PE_SECTION_TABLE_SIZE; i++)
358 {
359 section_data[i].vma_offset = 0;
360 section_data[i].rva_start = 1;
361 section_data[i].rva_end = 0;
362 };
363 section_data[PE_SECTION_INDEX_TEXT].ms_type = mst_text;
364 section_data[PE_SECTION_INDEX_TEXT].section_name = ".text";
365 section_data[PE_SECTION_INDEX_DATA].ms_type = mst_data;
366 section_data[PE_SECTION_INDEX_DATA].section_name = ".data";
367 section_data[PE_SECTION_INDEX_BSS].ms_type = mst_bss;
368 section_data[PE_SECTION_INDEX_BSS].section_name = ".bss";
369
5e13bd89
PA
370 is_pe64 = (strcmp (target, "pe-x86-64") == 0
371 || strcmp (target, "pei-x86-64") == 0);
372 is_pe32 = (strcmp (target, "pe-i386") == 0
373 || strcmp (target, "pei-i386") == 0
374 || strcmp (target, "pe-arm-wince-little") == 0
375 || strcmp (target, "pei-arm-wince-little") == 0);
a68ddad5 376 if (!is_pe32 && !is_pe64)
1b6bc7e0 377 {
5e13bd89
PA
378 /* This is not a recognized PE format file. Abort now, because
379 the code is untested on anything else. *FIXME* test on
aff410f1 380 further architectures and loosen or remove this test. */
feb14725 381 do_cleanups (back_to);
1b6bc7e0
CF
382 return;
383 }
384
385 /* Get pe_header, optional header and numbers of export entries. */
386 pe_header_offset = pe_get32 (dll, 0x3c);
387 opthdr_ofs = pe_header_offset + 4 + 20;
a68ddad5 388 if (is_pe64)
1dac1b47 389 num_entries = pe_get32 (dll, opthdr_ofs + 108);
a68ddad5
KT
390 else
391 num_entries = pe_get32 (dll, opthdr_ofs + 92);
1b6bc7e0
CF
392
393 if (num_entries < 1) /* No exports. */
394 {
feb14725 395 do_cleanups (back_to);
1b6bc7e0
CF
396 return;
397 }
a68ddad5
KT
398 if (is_pe64)
399 {
3999122f
PM
400 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112);
401 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116);
a68ddad5
KT
402 }
403 else
404 {
3999122f
PM
405 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96);
406 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100);
a68ddad5 407 }
1b6bc7e0
CF
408 nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
409 secptr = (pe_header_offset + 4 + 20 +
410 pe_get16 (dll, pe_header_offset + 4 + 16));
411 expptr = 0;
3999122f 412 export_size = 0;
1b6bc7e0
CF
413
414 /* Get the rva and size of the export section. */
415 for (i = 0; i < nsections; i++)
416 {
417 char sname[8];
418 unsigned long secptr1 = secptr + 40 * i;
419 unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
420 unsigned long vsize = pe_get32 (dll, secptr1 + 16);
421 unsigned long fptr = pe_get32 (dll, secptr1 + 20);
422
423 bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
3999122f 424 bfd_bread (sname, (bfd_size_type) sizeof (sname), dll);
1b6bc7e0 425
3999122f
PM
426 if ((strcmp (sname, ".edata") == 0)
427 || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize))
1b6bc7e0 428 {
3999122f
PM
429 if (strcmp (sname, ".edata") != 0)
430 {
431 if (debug_coff_pe_read)
432 fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll "
433 "\"%s\" is in section \"%s\"\n"),
434 dll_name, sname);
435 }
436 else if (export_opthdrrva != vaddr && debug_coff_pe_read)
437 fprintf_unfiltered (gdb_stdlog, _("Wrong value of export RVA"
438 " for dll \"%s\": 0x%lx instead of 0x%lx\n"),
439 dll_name, export_opthdrrva, vaddr);
440 expptr = fptr + (export_opthdrrva - vaddr);
1b6bc7e0
CF
441 break;
442 }
443 }
444
3999122f
PM
445 export_rva = export_opthdrrva;
446 export_size = export_opthdrsize;
447
1b6bc7e0
CF
448 if (export_size == 0)
449 {
aff410f1 450 /* Empty export table. */
feb14725 451 do_cleanups (back_to);
1b6bc7e0
CF
452 return;
453 }
454
aff410f1
MS
455 /* Scan sections and store the base and size of the relevant
456 sections. */
1b6bc7e0
CF
457 for (i = 0; i < nsections; i++)
458 {
459 unsigned long secptr1 = secptr + 40 * i;
460 unsigned long vsize = pe_get32 (dll, secptr1 + 8);
461 unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
3999122f 462 unsigned long characteristics = pe_get32 (dll, secptr1 + 36);
aab2f004 463 char sec_name[SCNNMLEN + 1];
1b6bc7e0 464 int sectix;
f93ba80c
PM
465 unsigned int bfd_section_index;
466 asection *section;
1b6bc7e0 467
1b6bc7e0 468 bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
aab2f004
PA
469 bfd_bread (sec_name, (bfd_size_type) SCNNMLEN, dll);
470 sec_name[SCNNMLEN] = '\0';
1b6bc7e0
CF
471
472 sectix = read_pe_section_index (sec_name);
f93ba80c
PM
473 section = bfd_get_section_by_name (dll, sec_name);
474 if (section)
475 bfd_section_index = section->index;
476 else
477 bfd_section_index = -1;
1b6bc7e0
CF
478
479 if (sectix != PE_SECTION_INDEX_INVALID)
480 {
481 section_data[sectix].rva_start = vaddr;
482 section_data[sectix].rva_end = vaddr + vsize;
f93ba80c 483 section_data[sectix].index = bfd_section_index;
1b6bc7e0 484 }
3999122f
PM
485 else
486 {
487 char *name;
488
489 section_data = xrealloc (section_data, (otherix + 1)
490 * sizeof (struct read_pe_section_data));
491 name = xstrdup (sec_name);
492 section_data[otherix].section_name = name;
493 make_cleanup (xfree, name);
494 section_data[otherix].rva_start = vaddr;
495 section_data[otherix].rva_end = vaddr + vsize;
496 section_data[otherix].vma_offset = 0;
f93ba80c 497 section_data[otherix].index = bfd_section_index;
3999122f
PM
498 if (characteristics & IMAGE_SCN_CNT_CODE)
499 section_data[otherix].ms_type = mst_text;
500 else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
501 section_data[otherix].ms_type = mst_data;
502 else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
503 section_data[otherix].ms_type = mst_bss;
504 else
505 section_data[otherix].ms_type = mst_unknown;
506 otherix++;
507 }
1b6bc7e0
CF
508 }
509
510 expdata = (unsigned char *) xmalloc (export_size);
3999122f 511 make_cleanup (xfree, expdata);
1b6bc7e0
CF
512
513 bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
514 bfd_bread (expdata, (bfd_size_type) export_size, dll);
515 erva = expdata - export_rva;
516
517 nexp = pe_as32 (expdata + 24);
518 name_rvas = pe_as32 (expdata + 32);
519 ordinals = pe_as32 (expdata + 36);
520 ordbase = pe_as32 (expdata + 16);
521 exp_funcbase = pe_as32 (expdata + 28);
522
aff410f1 523 /* Use internal dll name instead of full pathname. */
db5be46f 524 dll_name = (char *) (pe_as32 (expdata + 12) + erva);
1b6bc7e0 525
3999122f
PM
526 pe_sections_info.nb_sections = otherix;
527 pe_sections_info.sections = section_data;
528
529 bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info);
1b6bc7e0
CF
530
531 /* Adjust the vma_offsets in case this PE got relocated. This
532 assumes that *all* sections share the same relocation offset
aff410f1 533 as the text section. */
3999122f 534 for (i = 0; i < otherix; i++)
1b6bc7e0
CF
535 {
536 section_data[i].vma_offset
537 += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
538 }
539
1b6bc7e0 540 /* Truncate name at first dot. Should maybe also convert to all
aff410f1 541 lower case for convenience on Windows. */
1b6bc7e0
CF
542 read_pe_truncate_name (dll_name);
543
3999122f
PM
544 if (debug_coff_pe_read)
545 fprintf_unfiltered (gdb_stdlog, _("DLL \"%s\" has %ld export entries,"
546 " base=%ld\n"), dll_name, nexp, ordbase);
547 nbforward = 0;
548 nbnormal = 0;
1b6bc7e0
CF
549 /* Iterate through the list of symbols. */
550 for (i = 0; i < nexp; i++)
551 {
552 /* Pointer to the names vector. */
553 unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
3999122f
PM
554 /* Retrieve ordinal value. */
555
556 unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);
557
1b6bc7e0
CF
558
559 /* Pointer to the function address vector. */
3999122f
PM
560 /* This is relatived to ordinal value. */
561 unsigned long func_rva = pe_as32 (erva + exp_funcbase +
562 ordinal * 4);
1b6bc7e0 563
aff410f1 564 /* Find this symbol's section in our own array. */
1b6bc7e0 565 int sectix = 0;
3999122f
PM
566 int section_found = 0;
567
568 /* First handle forward cases. */
569 if (func_rva >= export_rva && func_rva < export_rva + export_size)
570 {
571 char *forward_name = (char *) (erva + func_rva);
572 char *funcname = (char *) (erva + name_rva);
573 char *forward_dll_name = forward_name;
574 char *forward_func_name = forward_name;
575 char *sep = strrchr (forward_name, '.');
576
577 if (sep)
578 {
579 int len = (int) (sep - forward_name);
1b6bc7e0 580
3999122f
PM
581 forward_dll_name = alloca (len + 1);
582 strncpy (forward_dll_name, forward_name, len);
583 forward_dll_name[len] = '\0';
584 forward_func_name = ++sep;
585 }
586 if (add_pe_forwarded_sym (funcname, forward_dll_name,
587 forward_func_name, ordinal,
588 dll_name, objfile) != 0)
589 ++nbforward;
590 continue;
591 }
592
593 for (sectix = 0; sectix < otherix; ++sectix)
1b6bc7e0
CF
594 {
595 if ((func_rva >= section_data[sectix].rva_start)
596 && (func_rva < section_data[sectix].rva_end))
597 {
db5be46f
PA
598 char *sym_name = (char *) (erva + name_rva);
599
3999122f 600 section_found = 1;
db5be46f 601 add_pe_exported_sym (sym_name, func_rva, ordinal,
1b6bc7e0 602 section_data + sectix, dll_name, objfile);
3999122f 603 ++nbnormal;
1b6bc7e0
CF
604 break;
605 }
606 }
3999122f
PM
607 if (!section_found)
608 {
609 char *funcname = (char *) (erva + name_rva);
610
611 if (name_rva == 0)
612 {
613 add_pe_exported_sym (NULL, func_rva, ordinal,
614 section_data, dll_name, objfile);
615 ++nbnormal;
616 }
617 else if (debug_coff_pe_read)
618 fprintf_unfiltered (gdb_stdlog, _("Export name \"%s\" ord. %lu,"
619 " RVA 0x%lx in dll \"%s\" not handled\n"),
620 funcname, ordinal, func_rva, dll_name);
621 }
1b6bc7e0
CF
622 }
623
3999122f
PM
624 if (debug_coff_pe_read)
625 fprintf_unfiltered (gdb_stdlog, _("Finished reading \"%s\", exports %ld,"
626 " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal,
627 nbforward, nbnormal + nbforward, nexp);
628 /* Discard expdata and section_data. */
1b6bc7e0
CF
629 do_cleanups (back_to);
630}
3999122f
PM
631
632/* Extract from ABFD the offset of the .text section.
633 This offset is mainly related to the offset within the file.
634 The value was previously expected to be 0x1000 for all files,
635 but some Windows OS core DLLs seem to use 0x10000 section alignement
636 which modified the return value of that function.
637 Still return default 0x1000 value if ABFD is NULL or
638 if '.text' section is not found, but that should not happen... */
639
640#define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000
641
642CORE_ADDR
643pe_text_section_offset (struct bfd *abfd)
644
645{
cebca8c1
AR
646 unsigned long pe_header_offset, i;
647 unsigned long nsections, secptr;
3999122f
PM
648 int is_pe64 = 0;
649 int is_pe32 = 0;
650 char const *target;
651
652 if (!abfd)
653 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
654
655 target = bfd_get_target (abfd);
656
657 is_pe64 = (strcmp (target, "pe-x86-64") == 0
658 || strcmp (target, "pei-x86-64") == 0);
659 is_pe32 = (strcmp (target, "pe-i386") == 0
660 || strcmp (target, "pei-i386") == 0
661 || strcmp (target, "pe-arm-wince-little") == 0
662 || strcmp (target, "pei-arm-wince-little") == 0);
663
664 if (!is_pe32 && !is_pe64)
665 {
666 /* This is not a recognized PE format file. Abort now, because
667 the code is untested on anything else. *FIXME* test on
668 further architectures and loosen or remove this test. */
669 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
670 }
671
672 /* Get pe_header, optional header and numbers of sections. */
673 pe_header_offset = pe_get32 (abfd, 0x3c);
3999122f
PM
674 nsections = pe_get16 (abfd, pe_header_offset + 4 + 2);
675 secptr = (pe_header_offset + 4 + 20 +
676 pe_get16 (abfd, pe_header_offset + 4 + 16));
677
678 /* Get the rva and size of the export section. */
679 for (i = 0; i < nsections; i++)
680 {
d8f4a83e 681 char sname[SCNNMLEN + 1];
3999122f
PM
682 unsigned long secptr1 = secptr + 40 * i;
683 unsigned long vaddr = pe_get32 (abfd, secptr1 + 12);
684
685 bfd_seek (abfd, (file_ptr) secptr1, SEEK_SET);
d8f4a83e
PM
686 bfd_bread (sname, (bfd_size_type) SCNNMLEN, abfd);
687 sname[SCNNMLEN] = '\0';
3999122f
PM
688 if (strcmp (sname, ".text") == 0)
689 return vaddr;
690 }
691
692 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET;
693}
694
695/* Implements "show debug coff_pe_read" command. */
696
697static void
698show_debug_coff_pe_read (struct ui_file *file, int from_tty,
699 struct cmd_list_element *c, const char *value)
700{
701 fprintf_filtered (file, _("Coff PE read debugging is %s.\n"), value);
702}
703
704/* Provide a prototype to silence -Wmissing-prototypes. */
705
706void _initialize_coff_pe_read (void);
707
708/* Adds "Set/show debug coff_pe_read" commands. */
709
710void
711_initialize_coff_pe_read (void)
712{
826ecc4d 713 add_setshow_zuinteger_cmd ("coff-pe-read", class_maintenance,
b75bf488
PA
714 &debug_coff_pe_read,
715 _("Set coff PE read debugging."),
716 _("Show coff PE read debugging."),
717 _("When set, debugging messages for coff reading "
718 "of exported symbols are displayed."),
719 NULL, show_debug_coff_pe_read,
720 &setdebuglist, &showdebuglist);
3999122f 721}