* coff-pe-read.c: Include defs.h before bfd.h.
[deliverable/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
7b6bb8da
JB
5 Copyright (C) 2003, 2007, 2008, 2009, 2010, 2011
6 Free Software Foundation, Inc.
1b6bc7e0
CF
7
8 This file is part of GDB.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
a9762ec7 12 the Free Software Foundation; either version 3 of the License, or
1b6bc7e0
CF
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
a9762ec7 21 along with this program. If not, see <http://www.gnu.org/licenses/>.
1b6bc7e0 22
aff410f1 23 Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */
1b6bc7e0
CF
24
25#include "coff-pe-read.h"
26
1b6bc7e0 27#include "defs.h"
81de56be 28#include "bfd.h"
1b6bc7e0
CF
29#include "gdbtypes.h"
30
31#include "symtab.h"
32#include "symfile.h"
33#include "objfiles.h"
34
35/* Internal section information */
36
37struct read_pe_section_data
38{
aff410f1
MS
39 CORE_ADDR vma_offset; /* Offset to loaded address of section. */
40 unsigned long rva_start; /* Start offset within the pe. */
41 unsigned long rva_end; /* End offset within the pe. */
42 enum minimal_symbol_type ms_type; /* Type to assign symbols in
43 section. */
1b6bc7e0
CF
44};
45
46#define PE_SECTION_INDEX_TEXT 0
47#define PE_SECTION_INDEX_DATA 1
48#define PE_SECTION_INDEX_BSS 2
49#define PE_SECTION_TABLE_SIZE 3
50#define PE_SECTION_INDEX_INVALID -1
51\f
52/* Get the index of the named section in our own array, which contains
aff410f1
MS
53 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
54 if passed an unrecognised section name. */
1b6bc7e0
CF
55
56static int
57read_pe_section_index (const char *section_name)
58{
59 if (strcmp (section_name, ".text") == 0)
60 {
61 return PE_SECTION_INDEX_TEXT;
62 }
63
64 else if (strcmp (section_name, ".data") == 0)
65 {
66 return PE_SECTION_INDEX_DATA;
67 }
68
69 else if (strcmp (section_name, ".bss") == 0)
70 {
71 return PE_SECTION_INDEX_BSS;
72 }
73
74 else
75 {
76 return PE_SECTION_INDEX_INVALID;
77 }
78}
79
aff410f1 80/* Record the virtual memory address of a section. */
1b6bc7e0
CF
81
82static void
83get_section_vmas (bfd *abfd, asection *sectp, void *context)
84{
85 struct read_pe_section_data *sections = context;
86 int sectix = read_pe_section_index (sectp->name);
87
88 if (sectix != PE_SECTION_INDEX_INVALID)
89 {
90 /* Data within the section start at rva_start in the pe and at
aff410f1 91 bfd_get_section_vma() within memory. Store the offset. */
1b6bc7e0
CF
92
93 sections[sectix].vma_offset
94 = bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start;
95 }
96}
97\f
aff410f1 98/* Create a minimal symbol entry for an exported symbol. */
1b6bc7e0
CF
99
100static void
101add_pe_exported_sym (char *sym_name,
102 unsigned long func_rva,
103 const struct read_pe_section_data *section_data,
104 const char *dll_name, struct objfile *objfile)
105{
aff410f1 106 /* Add the stored offset to get the loaded address of the symbol. */
1b6bc7e0
CF
107
108 CORE_ADDR vma = func_rva + section_data->vma_offset;
109
110 char *qualified_name = 0;
111 int dll_name_len = strlen (dll_name);
1b6bc7e0
CF
112
113 /* Generate a (hopefully unique) qualified name using the first part
aff410f1
MS
114 of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
115 used by windbg from the "Microsoft Debugging Tools for Windows". */
1b6bc7e0
CF
116
117 qualified_name = xmalloc (dll_name_len + strlen (sym_name) + 2);
118
119 strncpy (qualified_name, dll_name, dll_name_len);
120 qualified_name[dll_name_len] = '!';
121 strcpy (qualified_name + dll_name_len + 1, sym_name);
122
123 prim_record_minimal_symbol (qualified_name,
124 vma, section_data->ms_type, objfile);
125
126 xfree (qualified_name);
127
aff410f1
MS
128 /* Enter the plain name as well, which might not be unique. */
129 prim_record_minimal_symbol (sym_name, vma,
130 section_data->ms_type, objfile);
1b6bc7e0
CF
131}
132
aff410f1 133/* Truncate a dll_name at the first dot character. */
1b6bc7e0
CF
134
135static void
136read_pe_truncate_name (char *dll_name)
137{
138 while (*dll_name)
139 {
140 if ((*dll_name) == '.')
141 {
aff410f1 142 *dll_name = '\0'; /* truncates and causes loop exit. */
1b6bc7e0
CF
143 }
144
145 else
146 {
147 ++dll_name;
148 }
149 }
150}
151\f
aff410f1 152/* Low-level support functions, direct from the ld module pe-dll.c. */
1b6bc7e0
CF
153static unsigned int
154pe_get16 (bfd *abfd, int where)
155{
156 unsigned char b[2];
157
158 bfd_seek (abfd, (file_ptr) where, SEEK_SET);
159 bfd_bread (b, (bfd_size_type) 2, abfd);
160 return b[0] + (b[1] << 8);
161}
162
163static unsigned int
164pe_get32 (bfd *abfd, int where)
165{
166 unsigned char b[4];
167
168 bfd_seek (abfd, (file_ptr) where, SEEK_SET);
169 bfd_bread (b, (bfd_size_type) 4, abfd);
170 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
171}
172
173static unsigned int
174pe_as32 (void *ptr)
175{
176 unsigned char *b = ptr;
177
178 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
179}
180\f
181/* Read the (non-debug) export symbol table from a portable
aff410f1
MS
182 executable. Code originally lifted from the ld function
183 pe_implied_import_dll in pe-dll.c. */
1b6bc7e0
CF
184
185void
186read_pe_exported_syms (struct objfile *objfile)
187{
188 bfd *dll = objfile->obfd;
189 unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
190 unsigned long export_rva, export_size, nsections, secptr, expptr;
191 unsigned long exp_funcbase;
192 unsigned char *expdata, *erva;
193 unsigned long name_rvas, ordinals, nexp, ordbase;
194 char *dll_name;
a68ddad5
KT
195 int is_pe64 = 0;
196 int is_pe32 = 0;
1b6bc7e0
CF
197
198 /* Array elements are for text, data and bss in that order
199 Initialization with start_rva > end_rva guarantees that
aff410f1 200 unused sections won't be matched. */
1b6bc7e0
CF
201 struct read_pe_section_data section_data[PE_SECTION_TABLE_SIZE]
202 = { {0, 1, 0, mst_text},
203 {0, 1, 0, mst_data},
204 {0, 1, 0, mst_bss}
205 };
206
207 struct cleanup *back_to = 0;
208
209 char const *target = bfd_get_target (objfile->obfd);
210
5e13bd89
PA
211 is_pe64 = (strcmp (target, "pe-x86-64") == 0
212 || strcmp (target, "pei-x86-64") == 0);
213 is_pe32 = (strcmp (target, "pe-i386") == 0
214 || strcmp (target, "pei-i386") == 0
215 || strcmp (target, "pe-arm-wince-little") == 0
216 || strcmp (target, "pei-arm-wince-little") == 0);
217
a68ddad5 218 if (!is_pe32 && !is_pe64)
1b6bc7e0 219 {
5e13bd89
PA
220 /* This is not a recognized PE format file. Abort now, because
221 the code is untested on anything else. *FIXME* test on
aff410f1 222 further architectures and loosen or remove this test. */
1b6bc7e0
CF
223 return;
224 }
225
226 /* Get pe_header, optional header and numbers of export entries. */
227 pe_header_offset = pe_get32 (dll, 0x3c);
228 opthdr_ofs = pe_header_offset + 4 + 20;
a68ddad5 229 if (is_pe64)
1dac1b47 230 num_entries = pe_get32 (dll, opthdr_ofs + 108);
a68ddad5
KT
231 else
232 num_entries = pe_get32 (dll, opthdr_ofs + 92);
1b6bc7e0
CF
233
234 if (num_entries < 1) /* No exports. */
235 {
236 return;
237 }
238
a68ddad5
KT
239 if (is_pe64)
240 {
241 export_rva = pe_get32 (dll, opthdr_ofs + 112);
242 export_size = pe_get32 (dll, opthdr_ofs + 116);
243 }
244 else
245 {
246 export_rva = pe_get32 (dll, opthdr_ofs + 96);
247 export_size = pe_get32 (dll, opthdr_ofs + 100);
248 }
1b6bc7e0
CF
249 nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
250 secptr = (pe_header_offset + 4 + 20 +
251 pe_get16 (dll, pe_header_offset + 4 + 16));
252 expptr = 0;
253
254 /* Get the rva and size of the export section. */
255 for (i = 0; i < nsections; i++)
256 {
257 char sname[8];
258 unsigned long secptr1 = secptr + 40 * i;
259 unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
260 unsigned long vsize = pe_get32 (dll, secptr1 + 16);
261 unsigned long fptr = pe_get32 (dll, secptr1 + 20);
262
263 bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
264 bfd_bread (sname, (bfd_size_type) 8, dll);
265
266 if (vaddr <= export_rva && vaddr + vsize > export_rva)
267 {
268 expptr = fptr + (export_rva - vaddr);
269 if (export_rva + export_size > vaddr + vsize)
270 export_size = vsize - (export_rva - vaddr);
271 break;
272 }
273 }
274
275 if (export_size == 0)
276 {
aff410f1 277 /* Empty export table. */
1b6bc7e0
CF
278 return;
279 }
280
aff410f1
MS
281 /* Scan sections and store the base and size of the relevant
282 sections. */
1b6bc7e0
CF
283 for (i = 0; i < nsections; i++)
284 {
285 unsigned long secptr1 = secptr + 40 * i;
286 unsigned long vsize = pe_get32 (dll, secptr1 + 8);
287 unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
1b6bc7e0
CF
288 char sec_name[9];
289 int sectix;
290
291 sec_name[8] = '\0';
292 bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
293 bfd_bread (sec_name, (bfd_size_type) 8, dll);
294
295 sectix = read_pe_section_index (sec_name);
296
297 if (sectix != PE_SECTION_INDEX_INVALID)
298 {
299 section_data[sectix].rva_start = vaddr;
300 section_data[sectix].rva_end = vaddr + vsize;
301 }
302 }
303
304 expdata = (unsigned char *) xmalloc (export_size);
305 back_to = make_cleanup (xfree, expdata);
306
307 bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
308 bfd_bread (expdata, (bfd_size_type) export_size, dll);
309 erva = expdata - export_rva;
310
311 nexp = pe_as32 (expdata + 24);
312 name_rvas = pe_as32 (expdata + 32);
313 ordinals = pe_as32 (expdata + 36);
314 ordbase = pe_as32 (expdata + 16);
315 exp_funcbase = pe_as32 (expdata + 28);
316
aff410f1 317 /* Use internal dll name instead of full pathname. */
1b6bc7e0
CF
318 dll_name = pe_as32 (expdata + 12) + erva;
319
320 bfd_map_over_sections (dll, get_section_vmas, section_data);
321
322 /* Adjust the vma_offsets in case this PE got relocated. This
323 assumes that *all* sections share the same relocation offset
aff410f1 324 as the text section. */
1b6bc7e0
CF
325 for (i = 0; i < PE_SECTION_TABLE_SIZE; i++)
326 {
327 section_data[i].vma_offset
328 += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
329 }
330
1b6bc7e0 331 /* Truncate name at first dot. Should maybe also convert to all
aff410f1 332 lower case for convenience on Windows. */
1b6bc7e0
CF
333 read_pe_truncate_name (dll_name);
334
335 /* Iterate through the list of symbols. */
336 for (i = 0; i < nexp; i++)
337 {
338 /* Pointer to the names vector. */
339 unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
340
341 /* Pointer to the function address vector. */
342 unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4);
343
aff410f1 344 /* Find this symbol's section in our own array. */
1b6bc7e0
CF
345 int sectix = 0;
346
347 for (sectix = 0; sectix < PE_SECTION_TABLE_SIZE; ++sectix)
348 {
349 if ((func_rva >= section_data[sectix].rva_start)
350 && (func_rva < section_data[sectix].rva_end))
351 {
352 add_pe_exported_sym (erva + name_rva,
353 func_rva,
354 section_data + sectix, dll_name, objfile);
355 break;
356 }
357 }
358 }
359
aff410f1 360 /* Discard expdata. */
1b6bc7e0
CF
361 do_cleanups (back_to);
362}
This page took 0.572232 seconds and 4 git commands to generate.