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