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