GDB (API)
|
00001 /* Read the export table symbols from a portable executable and 00002 convert to internal format, for GDB. Used as a last resort if no 00003 debugging symbols recognized. 00004 00005 Copyright (C) 2003-2013 Free Software Foundation, Inc. 00006 00007 This file is part of GDB. 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program. If not, see <http://www.gnu.org/licenses/>. 00021 00022 Contributed by Raoul M. Gough (RaoulGough@yahoo.co.uk). */ 00023 00024 #include "defs.h" 00025 00026 #include "coff-pe-read.h" 00027 00028 #include "bfd.h" 00029 #include "gdbtypes.h" 00030 00031 #include "command.h" 00032 #include "gdbcmd.h" 00033 #include "symtab.h" 00034 #include "symfile.h" 00035 #include "objfiles.h" 00036 #include "common/common-utils.h" 00037 #include "coff/internal.h" 00038 00039 #include <ctype.h> 00040 00041 /* Internal section information */ 00042 00043 /* Coff PE read debugging flag: 00044 default value is 0, 00045 value 1 outputs problems encountered while parsing PE file, 00046 value above 1 also lists all generated minimal symbols. */ 00047 static unsigned int debug_coff_pe_read; 00048 00049 struct read_pe_section_data 00050 { 00051 CORE_ADDR vma_offset; /* Offset to loaded address of section. */ 00052 unsigned long rva_start; /* Start offset within the pe. */ 00053 unsigned long rva_end; /* End offset within the pe. */ 00054 enum minimal_symbol_type ms_type; /* Type to assign symbols in 00055 section. */ 00056 char *section_name; /* Recorded section name. */ 00057 }; 00058 00059 #define IMAGE_SCN_CNT_CODE 0x20 00060 #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x40 00061 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x80 00062 #define PE_SECTION_INDEX_TEXT 0 00063 #define PE_SECTION_INDEX_DATA 1 00064 #define PE_SECTION_INDEX_BSS 2 00065 #define PE_SECTION_TABLE_SIZE 3 00066 #define PE_SECTION_INDEX_INVALID -1 00067 00068 /* Get the index of the named section in our own array, which contains 00069 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID 00070 if passed an unrecognised section name. */ 00071 00072 static int 00073 read_pe_section_index (const char *section_name) 00074 { 00075 if (strcmp (section_name, ".text") == 0) 00076 { 00077 return PE_SECTION_INDEX_TEXT; 00078 } 00079 00080 else if (strcmp (section_name, ".data") == 0) 00081 { 00082 return PE_SECTION_INDEX_DATA; 00083 } 00084 00085 else if (strcmp (section_name, ".bss") == 0) 00086 { 00087 return PE_SECTION_INDEX_BSS; 00088 } 00089 00090 else 00091 { 00092 return PE_SECTION_INDEX_INVALID; 00093 } 00094 } 00095 00096 /* Get the index of the named section in our own full arrayi. 00097 text, data and bss in that order. Return PE_SECTION_INDEX_INVALID 00098 if passed an unrecognised section name. */ 00099 00100 static int 00101 get_pe_section_index (const char *section_name, 00102 struct read_pe_section_data *sections, 00103 int nb_sections) 00104 { 00105 int i; 00106 00107 for (i = 0; i < nb_sections; i++) 00108 if (strcmp (sections[i].section_name, section_name) == 0) 00109 return i; 00110 return PE_SECTION_INDEX_INVALID; 00111 } 00112 00113 /* Structure used by get_section_vmas function below 00114 to access section_data array and the size of the array 00115 stored in nb_sections field. */ 00116 struct pe_sections_info 00117 { 00118 int nb_sections; 00119 struct read_pe_section_data *sections; 00120 }; 00121 00122 /* Record the virtual memory address of a section. */ 00123 00124 static void 00125 get_section_vmas (bfd *abfd, asection *sectp, void *context) 00126 { 00127 struct pe_sections_info *data = context; 00128 struct read_pe_section_data *sections = data->sections; 00129 int sectix = get_pe_section_index (sectp->name, sections, 00130 data->nb_sections); 00131 00132 if (sectix != PE_SECTION_INDEX_INVALID) 00133 { 00134 /* Data within the section start at rva_start in the pe and at 00135 bfd_get_section_vma() within memory. Store the offset. */ 00136 00137 sections[sectix].vma_offset 00138 = bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start; 00139 } 00140 } 00141 00142 /* Create a minimal symbol entry for an exported symbol. 00143 SYM_NAME contains the exported name or NULL if exported by ordinal, 00144 FUNC_RVA contains the Relative Virtual Address of the symbol, 00145 ORDINAL is the ordinal index value of the symbol, 00146 SECTION_DATA contains information about the section in which the 00147 symbol is declared, 00148 DLL_NAME is the internal name of the DLL file, 00149 OBJFILE is the objfile struct of DLL_NAME. */ 00150 00151 static void 00152 add_pe_exported_sym (const char *sym_name, 00153 unsigned long func_rva, 00154 int ordinal, 00155 const struct read_pe_section_data *section_data, 00156 const char *dll_name, struct objfile *objfile) 00157 { 00158 char *qualified_name, *bare_name; 00159 /* Add the stored offset to get the loaded address of the symbol. */ 00160 CORE_ADDR vma = func_rva + section_data->vma_offset; 00161 00162 /* Generate a (hopefully unique) qualified name using the first part 00163 of the dll name, e.g. KERNEL32!AddAtomA. This matches the style 00164 used by windbg from the "Microsoft Debugging Tools for Windows". */ 00165 00166 if (sym_name == NULL || *sym_name == '\0') 00167 bare_name = xstrprintf ("#%d", ordinal); 00168 else 00169 bare_name = xstrdup (sym_name); 00170 00171 qualified_name = xstrprintf ("%s!%s", dll_name, bare_name); 00172 00173 if ((section_data->ms_type == mst_unknown) && debug_coff_pe_read) 00174 fprintf_unfiltered (gdb_stdlog , _("Unknown section type for \"%s\"" 00175 " for entry \"%s\" in dll \"%s\"\n"), 00176 section_data->section_name, sym_name, dll_name); 00177 00178 prim_record_minimal_symbol (qualified_name, vma, 00179 section_data->ms_type, objfile); 00180 00181 /* Enter the plain name as well, which might not be unique. */ 00182 prim_record_minimal_symbol (bare_name, vma, section_data->ms_type, objfile); 00183 if (debug_coff_pe_read > 1) 00184 fprintf_unfiltered (gdb_stdlog, _("Adding exported symbol \"%s\"" 00185 " in dll \"%s\"\n"), sym_name, dll_name); 00186 xfree (qualified_name); 00187 xfree (bare_name); 00188 } 00189 00190 /* Create a minimal symbol entry for an exported forward symbol. 00191 Return 1 if the forwarded function was found 0 otherwise. 00192 SYM_NAME contains the exported name or NULL if exported by ordinal, 00193 FORWARD_DLL_NAME is the name of the DLL in which the target symobl resides, 00194 FORWARD_FUNC_NAME is the name of the target symbol in that DLL, 00195 ORDINAL is the ordinal index value of the symbol, 00196 DLL_NAME is the internal name of the DLL file, 00197 OBJFILE is the objfile struct of DLL_NAME. */ 00198 00199 static int 00200 add_pe_forwarded_sym (const char *sym_name, const char *forward_dll_name, 00201 const char *forward_func_name, int ordinal, 00202 const char *dll_name, struct objfile *objfile) 00203 { 00204 CORE_ADDR vma; 00205 struct bound_minimal_symbol msymbol; 00206 enum minimal_symbol_type msymtype; 00207 char *qualified_name, *bare_name; 00208 int forward_dll_name_len = strlen (forward_dll_name); 00209 int forward_func_name_len = strlen (forward_func_name); 00210 int forward_len = forward_dll_name_len + forward_func_name_len + 2; 00211 char *forward_qualified_name = alloca (forward_len); 00212 00213 xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name, 00214 forward_func_name); 00215 00216 00217 msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name); 00218 00219 if (!msymbol.minsym) 00220 { 00221 int i; 00222 00223 for (i = 0; i < forward_dll_name_len; i++) 00224 forward_qualified_name[i] = tolower (forward_qualified_name[i]); 00225 msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name); 00226 } 00227 00228 if (!msymbol.minsym) 00229 { 00230 if (debug_coff_pe_read) 00231 fprintf_unfiltered (gdb_stdlog, _("Unable to find function \"%s\" in" 00232 " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"), 00233 forward_func_name, forward_dll_name, sym_name, 00234 dll_name); 00235 return 0; 00236 } 00237 00238 if (debug_coff_pe_read > 1) 00239 fprintf_unfiltered (gdb_stdlog, _("Adding forwarded exported symbol" 00240 " \"%s\" in dll \"%s\", pointing to \"%s\"\n"), 00241 sym_name, dll_name, forward_qualified_name); 00242 00243 vma = SYMBOL_VALUE_ADDRESS (msymbol.minsym); 00244 msymtype = MSYMBOL_TYPE (msymbol.minsym); 00245 00246 /* Generate a (hopefully unique) qualified name using the first part 00247 of the dll name, e.g. KERNEL32!AddAtomA. This matches the style 00248 used by windbg from the "Microsoft Debugging Tools for Windows". */ 00249 00250 if (sym_name == NULL || *sym_name == '\0') 00251 bare_name = xstrprintf ("#%d", ordinal); 00252 else 00253 bare_name = xstrdup (sym_name); 00254 00255 qualified_name = xstrprintf ("%s!%s", dll_name, bare_name); 00256 00257 prim_record_minimal_symbol (qualified_name, vma, msymtype, objfile); 00258 00259 /* Enter the plain name as well, which might not be unique. */ 00260 prim_record_minimal_symbol (bare_name, vma, msymtype, objfile); 00261 xfree (qualified_name); 00262 xfree (bare_name); 00263 00264 return 1; 00265 } 00266 00267 /* Truncate a dll_name at the last dot character. */ 00268 00269 static void 00270 read_pe_truncate_name (char *dll_name) 00271 { 00272 char *last_point = strrchr (dll_name, '.'); 00273 00274 if (last_point != NULL) 00275 *last_point = '\0'; 00276 } 00277 00278 /* Low-level support functions, direct from the ld module pe-dll.c. */ 00279 static unsigned int 00280 pe_get16 (bfd *abfd, int where) 00281 { 00282 unsigned char b[2]; 00283 00284 bfd_seek (abfd, (file_ptr) where, SEEK_SET); 00285 bfd_bread (b, (bfd_size_type) 2, abfd); 00286 return b[0] + (b[1] << 8); 00287 } 00288 00289 static unsigned int 00290 pe_get32 (bfd *abfd, int where) 00291 { 00292 unsigned char b[4]; 00293 00294 bfd_seek (abfd, (file_ptr) where, SEEK_SET); 00295 bfd_bread (b, (bfd_size_type) 4, abfd); 00296 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); 00297 } 00298 00299 static unsigned int 00300 pe_as16 (void *ptr) 00301 { 00302 unsigned char *b = ptr; 00303 00304 return b[0] + (b[1] << 8); 00305 } 00306 00307 static unsigned int 00308 pe_as32 (void *ptr) 00309 { 00310 unsigned char *b = ptr; 00311 00312 return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); 00313 } 00314 00315 /* Read the (non-debug) export symbol table from a portable 00316 executable. Code originally lifted from the ld function 00317 pe_implied_import_dll in pe-dll.c. */ 00318 00319 void 00320 read_pe_exported_syms (struct objfile *objfile) 00321 { 00322 bfd *dll = objfile->obfd; 00323 unsigned long nbnormal, nbforward; 00324 unsigned long pe_header_offset, opthdr_ofs, num_entries, i; 00325 unsigned long export_opthdrrva, export_opthdrsize; 00326 unsigned long export_rva, export_size, nsections, secptr, expptr; 00327 unsigned long exp_funcbase; 00328 unsigned char *expdata, *erva; 00329 unsigned long name_rvas, ordinals, nexp, ordbase; 00330 char *dll_name = (char *) dll->filename; 00331 int otherix = PE_SECTION_TABLE_SIZE; 00332 int is_pe64 = 0; 00333 int is_pe32 = 0; 00334 00335 /* Array elements are for text, data and bss in that order 00336 Initialization with RVA_START > RVA_END guarantees that 00337 unused sections won't be matched. */ 00338 struct read_pe_section_data *section_data; 00339 struct pe_sections_info pe_sections_info; 00340 00341 struct cleanup *back_to = make_cleanup (null_cleanup, 0); 00342 00343 char const *target = bfd_get_target (objfile->obfd); 00344 00345 section_data = xzalloc (PE_SECTION_TABLE_SIZE 00346 * sizeof (struct read_pe_section_data)); 00347 00348 make_cleanup (free_current_contents, §ion_data); 00349 00350 for (i=0; i < PE_SECTION_TABLE_SIZE; i++) 00351 { 00352 section_data[i].vma_offset = 0; 00353 section_data[i].rva_start = 1; 00354 section_data[i].rva_end = 0; 00355 }; 00356 section_data[PE_SECTION_INDEX_TEXT].ms_type = mst_text; 00357 section_data[PE_SECTION_INDEX_TEXT].section_name = ".text"; 00358 section_data[PE_SECTION_INDEX_DATA].ms_type = mst_data; 00359 section_data[PE_SECTION_INDEX_DATA].section_name = ".data"; 00360 section_data[PE_SECTION_INDEX_BSS].ms_type = mst_bss; 00361 section_data[PE_SECTION_INDEX_BSS].section_name = ".bss"; 00362 00363 is_pe64 = (strcmp (target, "pe-x86-64") == 0 00364 || strcmp (target, "pei-x86-64") == 0); 00365 is_pe32 = (strcmp (target, "pe-i386") == 0 00366 || strcmp (target, "pei-i386") == 0 00367 || strcmp (target, "pe-arm-wince-little") == 0 00368 || strcmp (target, "pei-arm-wince-little") == 0); 00369 if (!is_pe32 && !is_pe64) 00370 { 00371 /* This is not a recognized PE format file. Abort now, because 00372 the code is untested on anything else. *FIXME* test on 00373 further architectures and loosen or remove this test. */ 00374 do_cleanups (back_to); 00375 return; 00376 } 00377 00378 /* Get pe_header, optional header and numbers of export entries. */ 00379 pe_header_offset = pe_get32 (dll, 0x3c); 00380 opthdr_ofs = pe_header_offset + 4 + 20; 00381 if (is_pe64) 00382 num_entries = pe_get32 (dll, opthdr_ofs + 108); 00383 else 00384 num_entries = pe_get32 (dll, opthdr_ofs + 92); 00385 00386 if (num_entries < 1) /* No exports. */ 00387 { 00388 do_cleanups (back_to); 00389 return; 00390 } 00391 if (is_pe64) 00392 { 00393 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112); 00394 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116); 00395 } 00396 else 00397 { 00398 export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96); 00399 export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100); 00400 } 00401 nsections = pe_get16 (dll, pe_header_offset + 4 + 2); 00402 secptr = (pe_header_offset + 4 + 20 + 00403 pe_get16 (dll, pe_header_offset + 4 + 16)); 00404 expptr = 0; 00405 export_size = 0; 00406 00407 /* Get the rva and size of the export section. */ 00408 for (i = 0; i < nsections; i++) 00409 { 00410 char sname[8]; 00411 unsigned long secptr1 = secptr + 40 * i; 00412 unsigned long vaddr = pe_get32 (dll, secptr1 + 12); 00413 unsigned long vsize = pe_get32 (dll, secptr1 + 16); 00414 unsigned long fptr = pe_get32 (dll, secptr1 + 20); 00415 00416 bfd_seek (dll, (file_ptr) secptr1, SEEK_SET); 00417 bfd_bread (sname, (bfd_size_type) sizeof (sname), dll); 00418 00419 if ((strcmp (sname, ".edata") == 0) 00420 || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize)) 00421 { 00422 if (strcmp (sname, ".edata") != 0) 00423 { 00424 if (debug_coff_pe_read) 00425 fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll " 00426 "\"%s\" is in section \"%s\"\n"), 00427 dll_name, sname); 00428 } 00429 else if (export_opthdrrva != vaddr && debug_coff_pe_read) 00430 fprintf_unfiltered (gdb_stdlog, _("Wrong value of export RVA" 00431 " for dll \"%s\": 0x%lx instead of 0x%lx\n"), 00432 dll_name, export_opthdrrva, vaddr); 00433 expptr = fptr + (export_opthdrrva - vaddr); 00434 break; 00435 } 00436 } 00437 00438 export_rva = export_opthdrrva; 00439 export_size = export_opthdrsize; 00440 00441 if (export_size == 0) 00442 { 00443 /* Empty export table. */ 00444 do_cleanups (back_to); 00445 return; 00446 } 00447 00448 /* Scan sections and store the base and size of the relevant 00449 sections. */ 00450 for (i = 0; i < nsections; i++) 00451 { 00452 unsigned long secptr1 = secptr + 40 * i; 00453 unsigned long vsize = pe_get32 (dll, secptr1 + 8); 00454 unsigned long vaddr = pe_get32 (dll, secptr1 + 12); 00455 unsigned long characteristics = pe_get32 (dll, secptr1 + 36); 00456 char sec_name[SCNNMLEN + 1]; 00457 int sectix; 00458 00459 bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET); 00460 bfd_bread (sec_name, (bfd_size_type) SCNNMLEN, dll); 00461 sec_name[SCNNMLEN] = '\0'; 00462 00463 sectix = read_pe_section_index (sec_name); 00464 00465 if (sectix != PE_SECTION_INDEX_INVALID) 00466 { 00467 section_data[sectix].rva_start = vaddr; 00468 section_data[sectix].rva_end = vaddr + vsize; 00469 } 00470 else 00471 { 00472 char *name; 00473 00474 section_data = xrealloc (section_data, (otherix + 1) 00475 * sizeof (struct read_pe_section_data)); 00476 name = xstrdup (sec_name); 00477 section_data[otherix].section_name = name; 00478 make_cleanup (xfree, name); 00479 section_data[otherix].rva_start = vaddr; 00480 section_data[otherix].rva_end = vaddr + vsize; 00481 section_data[otherix].vma_offset = 0; 00482 if (characteristics & IMAGE_SCN_CNT_CODE) 00483 section_data[otherix].ms_type = mst_text; 00484 else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) 00485 section_data[otherix].ms_type = mst_data; 00486 else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) 00487 section_data[otherix].ms_type = mst_bss; 00488 else 00489 section_data[otherix].ms_type = mst_unknown; 00490 otherix++; 00491 } 00492 } 00493 00494 expdata = (unsigned char *) xmalloc (export_size); 00495 make_cleanup (xfree, expdata); 00496 00497 bfd_seek (dll, (file_ptr) expptr, SEEK_SET); 00498 bfd_bread (expdata, (bfd_size_type) export_size, dll); 00499 erva = expdata - export_rva; 00500 00501 nexp = pe_as32 (expdata + 24); 00502 name_rvas = pe_as32 (expdata + 32); 00503 ordinals = pe_as32 (expdata + 36); 00504 ordbase = pe_as32 (expdata + 16); 00505 exp_funcbase = pe_as32 (expdata + 28); 00506 00507 /* Use internal dll name instead of full pathname. */ 00508 dll_name = (char *) (pe_as32 (expdata + 12) + erva); 00509 00510 pe_sections_info.nb_sections = otherix; 00511 pe_sections_info.sections = section_data; 00512 00513 bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info); 00514 00515 /* Adjust the vma_offsets in case this PE got relocated. This 00516 assumes that *all* sections share the same relocation offset 00517 as the text section. */ 00518 for (i = 0; i < otherix; i++) 00519 { 00520 section_data[i].vma_offset 00521 += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); 00522 } 00523 00524 /* Truncate name at first dot. Should maybe also convert to all 00525 lower case for convenience on Windows. */ 00526 read_pe_truncate_name (dll_name); 00527 00528 if (debug_coff_pe_read) 00529 fprintf_unfiltered (gdb_stdlog, _("DLL \"%s\" has %ld export entries," 00530 " base=%ld\n"), dll_name, nexp, ordbase); 00531 nbforward = 0; 00532 nbnormal = 0; 00533 /* Iterate through the list of symbols. */ 00534 for (i = 0; i < nexp; i++) 00535 { 00536 /* Pointer to the names vector. */ 00537 unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4); 00538 /* Retrieve ordinal value. */ 00539 00540 unsigned long ordinal = pe_as16 (erva + ordinals + i * 2); 00541 00542 00543 /* Pointer to the function address vector. */ 00544 /* This is relatived to ordinal value. */ 00545 unsigned long func_rva = pe_as32 (erva + exp_funcbase + 00546 ordinal * 4); 00547 00548 /* Find this symbol's section in our own array. */ 00549 int sectix = 0; 00550 int section_found = 0; 00551 00552 /* First handle forward cases. */ 00553 if (func_rva >= export_rva && func_rva < export_rva + export_size) 00554 { 00555 char *forward_name = (char *) (erva + func_rva); 00556 char *funcname = (char *) (erva + name_rva); 00557 char *forward_dll_name = forward_name; 00558 char *forward_func_name = forward_name; 00559 char *sep = strrchr (forward_name, '.'); 00560 00561 if (sep) 00562 { 00563 int len = (int) (sep - forward_name); 00564 00565 forward_dll_name = alloca (len + 1); 00566 strncpy (forward_dll_name, forward_name, len); 00567 forward_dll_name[len] = '\0'; 00568 forward_func_name = ++sep; 00569 } 00570 if (add_pe_forwarded_sym (funcname, forward_dll_name, 00571 forward_func_name, ordinal, 00572 dll_name, objfile) != 0) 00573 ++nbforward; 00574 continue; 00575 } 00576 00577 for (sectix = 0; sectix < otherix; ++sectix) 00578 { 00579 if ((func_rva >= section_data[sectix].rva_start) 00580 && (func_rva < section_data[sectix].rva_end)) 00581 { 00582 char *sym_name = (char *) (erva + name_rva); 00583 00584 section_found = 1; 00585 add_pe_exported_sym (sym_name, func_rva, ordinal, 00586 section_data + sectix, dll_name, objfile); 00587 ++nbnormal; 00588 break; 00589 } 00590 } 00591 if (!section_found) 00592 { 00593 char *funcname = (char *) (erva + name_rva); 00594 00595 if (name_rva == 0) 00596 { 00597 add_pe_exported_sym (NULL, func_rva, ordinal, 00598 section_data, dll_name, objfile); 00599 ++nbnormal; 00600 } 00601 else if (debug_coff_pe_read) 00602 fprintf_unfiltered (gdb_stdlog, _("Export name \"%s\" ord. %lu," 00603 " RVA 0x%lx in dll \"%s\" not handled\n"), 00604 funcname, ordinal, func_rva, dll_name); 00605 } 00606 } 00607 00608 if (debug_coff_pe_read) 00609 fprintf_unfiltered (gdb_stdlog, _("Finished reading \"%s\", exports %ld," 00610 " forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal, 00611 nbforward, nbnormal + nbforward, nexp); 00612 /* Discard expdata and section_data. */ 00613 do_cleanups (back_to); 00614 } 00615 00616 /* Extract from ABFD the offset of the .text section. 00617 This offset is mainly related to the offset within the file. 00618 The value was previously expected to be 0x1000 for all files, 00619 but some Windows OS core DLLs seem to use 0x10000 section alignement 00620 which modified the return value of that function. 00621 Still return default 0x1000 value if ABFD is NULL or 00622 if '.text' section is not found, but that should not happen... */ 00623 00624 #define DEFAULT_COFF_PE_TEXT_SECTION_OFFSET 0x1000 00625 00626 CORE_ADDR 00627 pe_text_section_offset (struct bfd *abfd) 00628 00629 { 00630 unsigned long pe_header_offset, i; 00631 unsigned long nsections, secptr; 00632 int is_pe64 = 0; 00633 int is_pe32 = 0; 00634 char const *target; 00635 00636 if (!abfd) 00637 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET; 00638 00639 target = bfd_get_target (abfd); 00640 00641 is_pe64 = (strcmp (target, "pe-x86-64") == 0 00642 || strcmp (target, "pei-x86-64") == 0); 00643 is_pe32 = (strcmp (target, "pe-i386") == 0 00644 || strcmp (target, "pei-i386") == 0 00645 || strcmp (target, "pe-arm-wince-little") == 0 00646 || strcmp (target, "pei-arm-wince-little") == 0); 00647 00648 if (!is_pe32 && !is_pe64) 00649 { 00650 /* This is not a recognized PE format file. Abort now, because 00651 the code is untested on anything else. *FIXME* test on 00652 further architectures and loosen or remove this test. */ 00653 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET; 00654 } 00655 00656 /* Get pe_header, optional header and numbers of sections. */ 00657 pe_header_offset = pe_get32 (abfd, 0x3c); 00658 nsections = pe_get16 (abfd, pe_header_offset + 4 + 2); 00659 secptr = (pe_header_offset + 4 + 20 + 00660 pe_get16 (abfd, pe_header_offset + 4 + 16)); 00661 00662 /* Get the rva and size of the export section. */ 00663 for (i = 0; i < nsections; i++) 00664 { 00665 char sname[SCNNMLEN + 1]; 00666 unsigned long secptr1 = secptr + 40 * i; 00667 unsigned long vaddr = pe_get32 (abfd, secptr1 + 12); 00668 00669 bfd_seek (abfd, (file_ptr) secptr1, SEEK_SET); 00670 bfd_bread (sname, (bfd_size_type) SCNNMLEN, abfd); 00671 sname[SCNNMLEN] = '\0'; 00672 if (strcmp (sname, ".text") == 0) 00673 return vaddr; 00674 } 00675 00676 return DEFAULT_COFF_PE_TEXT_SECTION_OFFSET; 00677 } 00678 00679 /* Implements "show debug coff_pe_read" command. */ 00680 00681 static void 00682 show_debug_coff_pe_read (struct ui_file *file, int from_tty, 00683 struct cmd_list_element *c, const char *value) 00684 { 00685 fprintf_filtered (file, _("Coff PE read debugging is %s.\n"), value); 00686 } 00687 00688 /* Provide a prototype to silence -Wmissing-prototypes. */ 00689 00690 void _initialize_coff_pe_read (void); 00691 00692 /* Adds "Set/show debug coff_pe_read" commands. */ 00693 00694 void 00695 _initialize_coff_pe_read (void) 00696 { 00697 add_setshow_zuinteger_cmd ("coff-pe-read", class_maintenance, 00698 &debug_coff_pe_read, 00699 _("Set coff PE read debugging."), 00700 _("Show coff PE read debugging."), 00701 _("When set, debugging messages for coff reading " 00702 "of exported symbols are displayed."), 00703 NULL, show_debug_coff_pe_read, 00704 &setdebuglist, &showdebuglist); 00705 }