Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpe_module.c
Go to the documentation of this file.
00001 /* 00002 * File pe_module.c - handle PE module information 00003 * 00004 * Copyright (C) 1996, Eric Youngdale. 00005 * Copyright (C) 1999-2000, Ulrich Weigand. 00006 * Copyright (C) 2004-2007, Eric Pouech. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00021 * 00022 */ 00023 00024 #include "config.h" 00025 #include "wine/port.h" 00026 00027 #include <stdlib.h> 00028 #include <stdio.h> 00029 #include <string.h> 00030 #include <assert.h> 00031 00032 #include "dbghelp_private.h" 00033 #include "image_private.h" 00034 #include "winternl.h" 00035 #include "wine/debug.h" 00036 00037 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); 00038 00039 struct pe_module_info 00040 { 00041 struct image_file_map fmap; 00042 }; 00043 00044 static void* pe_map_full(struct image_file_map* fmap, IMAGE_NT_HEADERS** nth) 00045 { 00046 if (!fmap->u.pe.full_map) 00047 { 00048 fmap->u.pe.full_map = MapViewOfFile(fmap->u.pe.hMap, FILE_MAP_READ, 0, 0, 0); 00049 } 00050 if (fmap->u.pe.full_map) 00051 { 00052 if (nth) *nth = RtlImageNtHeader(fmap->u.pe.full_map); 00053 fmap->u.pe.full_count++; 00054 return fmap->u.pe.full_map; 00055 } 00056 return IMAGE_NO_MAP; 00057 } 00058 00059 static void pe_unmap_full(struct image_file_map* fmap) 00060 { 00061 if (fmap->u.pe.full_count && !--fmap->u.pe.full_count) 00062 { 00063 UnmapViewOfFile(fmap->u.pe.full_map); 00064 fmap->u.pe.full_map = NULL; 00065 } 00066 } 00067 00068 /****************************************************************** 00069 * pe_map_section 00070 * 00071 * Maps a single section into memory from an PE file 00072 */ 00073 const char* pe_map_section(struct image_section_map* ism) 00074 { 00075 void* mapping; 00076 struct pe_file_map* fmap = &ism->fmap->u.pe; 00077 00078 if (ism->sidx >= 0 && ism->sidx < fmap->ntheader.FileHeader.NumberOfSections && 00079 fmap->sect[ism->sidx].mapped == IMAGE_NO_MAP) 00080 { 00081 IMAGE_NT_HEADERS* nth; 00082 00083 if (fmap->sect[ism->sidx].shdr.Misc.VirtualSize > fmap->sect[ism->sidx].shdr.SizeOfRawData) 00084 { 00085 FIXME("Section %ld: virtual (0x%x) > raw (0x%x) size - not supported\n", 00086 ism->sidx, fmap->sect[ism->sidx].shdr.Misc.VirtualSize, 00087 fmap->sect[ism->sidx].shdr.SizeOfRawData); 00088 return IMAGE_NO_MAP; 00089 } 00090 /* FIXME: that's rather drastic, but that will do for now 00091 * that's ok if the full file map exists, but we could be less aggressive otherwise and 00092 * only map the relevant section 00093 */ 00094 if ((mapping = pe_map_full(ism->fmap, &nth))) 00095 { 00096 fmap->sect[ism->sidx].mapped = RtlImageRvaToVa(nth, mapping, 00097 fmap->sect[ism->sidx].shdr.VirtualAddress, 00098 NULL); 00099 return fmap->sect[ism->sidx].mapped; 00100 } 00101 } 00102 return IMAGE_NO_MAP; 00103 } 00104 00105 /****************************************************************** 00106 * pe_find_section 00107 * 00108 * Finds a section by name (and type) into memory from an PE file 00109 * or its alternate if any 00110 */ 00111 BOOL pe_find_section(struct image_file_map* fmap, const char* name, 00112 struct image_section_map* ism) 00113 { 00114 const char* sectname; 00115 unsigned i; 00116 char tmp[IMAGE_SIZEOF_SHORT_NAME + 1]; 00117 00118 for (i = 0; i < fmap->u.pe.ntheader.FileHeader.NumberOfSections; i++) 00119 { 00120 sectname = (const char*)fmap->u.pe.sect[i].shdr.Name; 00121 /* long section names start with a '/' (at least on MinGW32) */ 00122 if (sectname[0] == '/' && fmap->u.pe.strtable) 00123 sectname = fmap->u.pe.strtable + atoi(sectname + 1); 00124 else 00125 { 00126 /* the section name may not be null terminated */ 00127 sectname = memcpy(tmp, sectname, IMAGE_SIZEOF_SHORT_NAME); 00128 tmp[IMAGE_SIZEOF_SHORT_NAME] = '\0'; 00129 } 00130 if (!strcasecmp(sectname, name)) 00131 { 00132 ism->fmap = fmap; 00133 ism->sidx = i; 00134 return TRUE; 00135 } 00136 } 00137 ism->fmap = NULL; 00138 ism->sidx = -1; 00139 00140 return FALSE; 00141 } 00142 00143 /****************************************************************** 00144 * pe_unmap_section 00145 * 00146 * Unmaps a single section from memory 00147 */ 00148 void pe_unmap_section(struct image_section_map* ism) 00149 { 00150 if (ism->sidx >= 0 && ism->sidx < ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections && 00151 ism->fmap->u.pe.sect[ism->sidx].mapped != IMAGE_NO_MAP) 00152 { 00153 pe_unmap_full(ism->fmap); 00154 ism->fmap->u.pe.sect[ism->sidx].mapped = IMAGE_NO_MAP; 00155 } 00156 } 00157 00158 /****************************************************************** 00159 * pe_get_map_rva 00160 * 00161 * Get the RVA of an PE section 00162 */ 00163 DWORD_PTR pe_get_map_rva(const struct image_section_map* ism) 00164 { 00165 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections) 00166 return 0; 00167 return ism->fmap->u.pe.sect[ism->sidx].shdr.VirtualAddress; 00168 } 00169 00170 /****************************************************************** 00171 * pe_get_map_size 00172 * 00173 * Get the size of a PE section 00174 */ 00175 unsigned pe_get_map_size(const struct image_section_map* ism) 00176 { 00177 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections) 00178 return 0; 00179 return ism->fmap->u.pe.sect[ism->sidx].shdr.Misc.VirtualSize; 00180 } 00181 00182 /****************************************************************** 00183 * pe_is_valid_pointer_table 00184 * 00185 * Checks whether the PointerToSymbolTable and NumberOfSymbols in file_header contain 00186 * valid information. 00187 */ 00188 static BOOL pe_is_valid_pointer_table(const IMAGE_NT_HEADERS* nthdr, const void* mapping, DWORD64 sz) 00189 { 00190 DWORD64 offset; 00191 00192 /* is the iSym table inside file size ? (including first DWORD of string table, which is its size) */ 00193 offset = (DWORD64)nthdr->FileHeader.PointerToSymbolTable; 00194 offset += (DWORD64)nthdr->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL); 00195 if (offset + sizeof(DWORD) > sz) return FALSE; 00196 /* is string table (following iSym table) inside file size ? */ 00197 offset += *(DWORD*)((const char*)mapping + offset); 00198 return offset <= sz; 00199 } 00200 00201 /****************************************************************** 00202 * pe_map_file 00203 * 00204 * Maps an PE file into memory (and checks it's a real PE file) 00205 */ 00206 static BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_type mt) 00207 { 00208 void* mapping; 00209 00210 fmap->modtype = mt; 00211 fmap->u.pe.hMap = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); 00212 if (fmap->u.pe.hMap == 0) return FALSE; 00213 fmap->u.pe.full_count = 0; 00214 fmap->u.pe.full_map = NULL; 00215 if (!(mapping = pe_map_full(fmap, NULL))) goto error; 00216 00217 switch (mt) 00218 { 00219 case DMT_PE: 00220 { 00221 IMAGE_NT_HEADERS* nthdr; 00222 IMAGE_SECTION_HEADER* section; 00223 unsigned i; 00224 00225 if (!(nthdr = RtlImageNtHeader(mapping))) goto error; 00226 memcpy(&fmap->u.pe.ntheader, nthdr, sizeof(fmap->u.pe.ntheader)); 00227 section = (IMAGE_SECTION_HEADER*) 00228 ((char*)&nthdr->OptionalHeader + nthdr->FileHeader.SizeOfOptionalHeader); 00229 fmap->u.pe.sect = HeapAlloc(GetProcessHeap(), 0, 00230 nthdr->FileHeader.NumberOfSections * sizeof(fmap->u.pe.sect[0])); 00231 if (!fmap->u.pe.sect) goto error; 00232 for (i = 0; i < nthdr->FileHeader.NumberOfSections; i++) 00233 { 00234 memcpy(&fmap->u.pe.sect[i].shdr, section + i, sizeof(IMAGE_SECTION_HEADER)); 00235 fmap->u.pe.sect[i].mapped = IMAGE_NO_MAP; 00236 } 00237 if (nthdr->FileHeader.PointerToSymbolTable && nthdr->FileHeader.NumberOfSymbols) 00238 { 00239 LARGE_INTEGER li; 00240 00241 if (GetFileSizeEx(file, &li) && pe_is_valid_pointer_table(nthdr, mapping, li.QuadPart)) 00242 { 00243 /* FIXME ugly: should rather map the relevant content instead of copying it */ 00244 const char* src = (const char*)mapping + 00245 nthdr->FileHeader.PointerToSymbolTable + 00246 nthdr->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL); 00247 char* dst; 00248 DWORD sz = *(DWORD*)src; 00249 00250 if ((dst = HeapAlloc(GetProcessHeap(), 0, sz))) 00251 memcpy(dst, src, sz); 00252 fmap->u.pe.strtable = dst; 00253 } 00254 else 00255 { 00256 WARN("Bad coff table... wipping out\n"); 00257 /* we have bad information here, wipe it out */ 00258 fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable = 0; 00259 fmap->u.pe.ntheader.FileHeader.NumberOfSymbols = 0; 00260 fmap->u.pe.strtable = NULL; 00261 } 00262 } 00263 else fmap->u.pe.strtable = NULL; 00264 } 00265 break; 00266 default: assert(0); goto error; 00267 } 00268 pe_unmap_full(fmap); 00269 00270 return TRUE; 00271 error: 00272 pe_unmap_full(fmap); 00273 CloseHandle(fmap->u.pe.hMap); 00274 return FALSE; 00275 } 00276 00277 /****************************************************************** 00278 * pe_unmap_file 00279 * 00280 * Unmaps an PE file from memory (previously mapped with pe_map_file) 00281 */ 00282 static void pe_unmap_file(struct image_file_map* fmap) 00283 { 00284 if (fmap->u.pe.hMap != 0) 00285 { 00286 struct image_section_map ism; 00287 ism.fmap = fmap; 00288 for (ism.sidx = 0; ism.sidx < fmap->u.pe.ntheader.FileHeader.NumberOfSections; ism.sidx++) 00289 { 00290 pe_unmap_section(&ism); 00291 } 00292 while (fmap->u.pe.full_count) pe_unmap_full(fmap); 00293 HeapFree(GetProcessHeap(), 0, fmap->u.pe.sect); 00294 HeapFree(GetProcessHeap(), 0, (void*)fmap->u.pe.strtable); /* FIXME ugly (see pe_map_file) */ 00295 CloseHandle(fmap->u.pe.hMap); 00296 fmap->u.pe.hMap = NULL; 00297 } 00298 } 00299 00300 /****************************************************************** 00301 * pe_map_directory 00302 * 00303 * Maps a directory content out of a PE file 00304 */ 00305 const char* pe_map_directory(struct module* module, int dirno, DWORD* size) 00306 { 00307 IMAGE_NT_HEADERS* nth; 00308 void* mapping; 00309 00310 if (module->type != DMT_PE || !module->format_info[DFI_PE]) return NULL; 00311 if (dirno >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES || 00312 !(mapping = pe_map_full(&module->format_info[DFI_PE]->u.pe_info->fmap, &nth))) 00313 return NULL; 00314 if (size) *size = nth->OptionalHeader.DataDirectory[dirno].Size; 00315 return RtlImageRvaToVa(nth, mapping, 00316 nth->OptionalHeader.DataDirectory[dirno].VirtualAddress, NULL); 00317 } 00318 00319 /****************************************************************** 00320 * pe_unmap_directory 00321 * 00322 * Unmaps a directory content 00323 */ 00324 void pe_unmap_directory(struct image_file_map* fmap, int dirno) 00325 { 00326 pe_unmap_full(fmap); 00327 } 00328 00329 static void pe_module_remove(struct process* pcs, struct module_format* modfmt) 00330 { 00331 pe_unmap_file(&modfmt->u.pe_info->fmap); 00332 HeapFree(GetProcessHeap(), 0, modfmt); 00333 } 00334 00335 /****************************************************************** 00336 * pe_locate_with_coff_symbol_table 00337 * 00338 * Use the COFF symbol table (if any) from the IMAGE_FILE_HEADER to set the absolute address 00339 * of global symbols. 00340 * Mingw32 requires this for stabs debug information as address for global variables isn't filled in 00341 * (this is similar to what is done in elf_module.c when using the .symtab ELF section) 00342 */ 00343 static BOOL pe_locate_with_coff_symbol_table(struct module* module) 00344 { 00345 struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; 00346 const IMAGE_SYMBOL* isym; 00347 int i, numsym, naux; 00348 char tmp[9]; 00349 const char* name; 00350 struct hash_table_iter hti; 00351 void* ptr; 00352 struct symt_data* sym; 00353 const char* mapping; 00354 00355 numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols; 00356 if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym) 00357 return TRUE; 00358 if (!(mapping = pe_map_full(fmap, NULL))) return FALSE; 00359 isym = (const IMAGE_SYMBOL*)(mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable); 00360 00361 for (i = 0; i < numsym; i+= naux, isym += naux) 00362 { 00363 if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && 00364 isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections) 00365 { 00366 if (isym->N.Name.Short) 00367 { 00368 name = memcpy(tmp, isym->N.ShortName, 8); 00369 tmp[8] = '\0'; 00370 } 00371 else name = fmap->u.pe.strtable + isym->N.Name.Long; 00372 if (name[0] == '_') name++; 00373 hash_table_iter_init(&module->ht_symbols, &hti, name); 00374 while ((ptr = hash_table_iter_up(&hti))) 00375 { 00376 sym = GET_ENTRY(ptr, struct symt_data, hash_elt); 00377 if (sym->symt.tag == SymTagData && 00378 (sym->kind == DataIsGlobal || sym->kind == DataIsFileStatic) && 00379 sym->u.var.kind == loc_absolute && 00380 !strcmp(sym->hash_elt.name, name)) 00381 { 00382 TRACE("Changing absolute address for %d.%s: %lx -> %s\n", 00383 isym->SectionNumber, name, sym->u.var.offset, 00384 wine_dbgstr_longlong(module->module.BaseOfImage + 00385 fmap->u.pe.sect[isym->SectionNumber - 1].shdr.VirtualAddress + 00386 isym->Value)); 00387 sym->u.var.offset = module->module.BaseOfImage + 00388 fmap->u.pe.sect[isym->SectionNumber - 1].shdr.VirtualAddress + isym->Value; 00389 break; 00390 } 00391 } 00392 } 00393 naux = isym->NumberOfAuxSymbols + 1; 00394 } 00395 pe_unmap_full(fmap); 00396 return TRUE; 00397 } 00398 00399 /****************************************************************** 00400 * pe_load_coff_symbol_table 00401 * 00402 * Load public symbols out of the COFF symbol table (if any). 00403 */ 00404 static BOOL pe_load_coff_symbol_table(struct module* module) 00405 { 00406 struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; 00407 const IMAGE_SYMBOL* isym; 00408 int i, numsym, naux; 00409 const char* strtable; 00410 char tmp[9]; 00411 const char* name; 00412 const char* lastfilename = NULL; 00413 struct symt_compiland* compiland = NULL; 00414 const IMAGE_SECTION_HEADER* sect; 00415 const char* mapping; 00416 00417 numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols; 00418 if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym) 00419 return TRUE; 00420 if (!(mapping = pe_map_full(fmap, NULL))) return FALSE; 00421 isym = (const IMAGE_SYMBOL*)((const char*)mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable); 00422 /* FIXME: no way to get strtable size */ 00423 strtable = (const char*)&isym[numsym]; 00424 sect = IMAGE_FIRST_SECTION(RtlImageNtHeader((HMODULE)mapping)); 00425 00426 for (i = 0; i < numsym; i+= naux, isym += naux) 00427 { 00428 if (isym->StorageClass == IMAGE_SYM_CLASS_FILE) 00429 { 00430 lastfilename = (const char*)(isym + 1); 00431 compiland = NULL; 00432 } 00433 if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && 00434 isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections) 00435 { 00436 if (isym->N.Name.Short) 00437 { 00438 name = memcpy(tmp, isym->N.ShortName, 8); 00439 tmp[8] = '\0'; 00440 } 00441 else name = strtable + isym->N.Name.Long; 00442 if (name[0] == '_') name++; 00443 00444 if (!compiland && lastfilename) 00445 compiland = symt_new_compiland(module, 0, 00446 source_new(module, NULL, lastfilename)); 00447 00448 if (!(dbghelp_options & SYMOPT_NO_PUBLICS)) 00449 symt_new_public(module, compiland, name, 00450 module->module.BaseOfImage + sect[isym->SectionNumber - 1].VirtualAddress + 00451 isym->Value, 00452 1); 00453 } 00454 naux = isym->NumberOfAuxSymbols + 1; 00455 } 00456 module->module.SymType = SymCoff; 00457 module->module.LineNumbers = FALSE; 00458 module->module.GlobalSymbols = FALSE; 00459 module->module.TypeInfo = FALSE; 00460 module->module.SourceIndexed = FALSE; 00461 module->module.Publics = TRUE; 00462 pe_unmap_full(fmap); 00463 00464 return TRUE; 00465 } 00466 00467 /****************************************************************** 00468 * pe_load_stabs 00469 * 00470 * look for stabs information in PE header (it's how the mingw compiler provides 00471 * its debugging information) 00472 */ 00473 static BOOL pe_load_stabs(const struct process* pcs, struct module* module) 00474 { 00475 struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; 00476 struct image_section_map sect_stabs, sect_stabstr; 00477 BOOL ret = FALSE; 00478 00479 if (pe_find_section(fmap, ".stab", §_stabs) && pe_find_section(fmap, ".stabstr", §_stabstr)) 00480 { 00481 const char* stab; 00482 const char* stabstr; 00483 00484 stab = image_map_section(§_stabs); 00485 stabstr = image_map_section(§_stabstr); 00486 if (stab != IMAGE_NO_MAP && stabstr != IMAGE_NO_MAP) 00487 { 00488 ret = stabs_parse(module, 00489 module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase, 00490 stab, image_get_map_size(§_stabs), 00491 stabstr, image_get_map_size(§_stabstr), 00492 NULL, NULL); 00493 } 00494 image_unmap_section(§_stabs); 00495 image_unmap_section(§_stabstr); 00496 if (ret) pe_locate_with_coff_symbol_table(module); 00497 } 00498 TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load"); 00499 00500 return ret; 00501 } 00502 00503 /****************************************************************** 00504 * pe_load_dwarf 00505 * 00506 * look for dwarf information in PE header (it's also a way for the mingw compiler 00507 * to provide its debugging information) 00508 */ 00509 static BOOL pe_load_dwarf(struct module* module) 00510 { 00511 struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; 00512 BOOL ret = FALSE; 00513 00514 ret = dwarf2_parse(module, 00515 module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase, 00516 NULL, /* FIXME: some thunks to deal with ? */ 00517 fmap); 00518 TRACE("%s the DWARF debug info\n", ret ? "successfully loaded" : "failed to load"); 00519 00520 return ret; 00521 } 00522 00523 /****************************************************************** 00524 * pe_load_dbg_file 00525 * 00526 * loads a .dbg file 00527 */ 00528 static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module, 00529 const char* dbg_name, DWORD timestamp) 00530 { 00531 char tmp[MAX_PATH]; 00532 HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0; 00533 const BYTE* dbg_mapping = NULL; 00534 BOOL ret = FALSE; 00535 00536 TRACE("Processing DBG file %s\n", debugstr_a(dbg_name)); 00537 00538 if (path_find_symbol_file(pcs, dbg_name, NULL, timestamp, 0, tmp, &module->module.DbgUnmatched) && 00539 (hFile = CreateFileA(tmp, GENERIC_READ, FILE_SHARE_READ, NULL, 00540 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE && 00541 ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) && 00542 ((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)) 00543 { 00544 const IMAGE_SEPARATE_DEBUG_HEADER* hdr; 00545 const IMAGE_SECTION_HEADER* sectp; 00546 const IMAGE_DEBUG_DIRECTORY* dbg; 00547 00548 hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)dbg_mapping; 00549 /* section headers come immediately after debug header */ 00550 sectp = (const IMAGE_SECTION_HEADER*)(hdr + 1); 00551 /* and after that and the exported names comes the debug directory */ 00552 dbg = (const IMAGE_DEBUG_DIRECTORY*) 00553 (dbg_mapping + sizeof(*hdr) + 00554 hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + 00555 hdr->ExportedNamesSize); 00556 00557 ret = pe_load_debug_directory(pcs, module, dbg_mapping, sectp, 00558 hdr->NumberOfSections, dbg, 00559 hdr->DebugDirectorySize / sizeof(*dbg)); 00560 } 00561 else 00562 ERR("Couldn't find .DBG file %s (%s)\n", debugstr_a(dbg_name), debugstr_a(tmp)); 00563 00564 if (dbg_mapping) UnmapViewOfFile(dbg_mapping); 00565 if (hMap) CloseHandle(hMap); 00566 if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); 00567 return ret; 00568 } 00569 00570 /****************************************************************** 00571 * pe_load_msc_debug_info 00572 * 00573 * Process MSC debug information in PE file. 00574 */ 00575 static BOOL pe_load_msc_debug_info(const struct process* pcs, struct module* module) 00576 { 00577 struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; 00578 BOOL ret = FALSE; 00579 const IMAGE_DATA_DIRECTORY* dir; 00580 const IMAGE_DEBUG_DIRECTORY*dbg = NULL; 00581 int nDbg; 00582 void* mapping; 00583 IMAGE_NT_HEADERS* nth; 00584 00585 if (!(mapping = pe_map_full(fmap, &nth))) return FALSE; 00586 /* Read in debug directory */ 00587 dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG; 00588 nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY); 00589 if (!nDbg) goto done; 00590 00591 dbg = RtlImageRvaToVa(nth, mapping, dir->VirtualAddress, NULL); 00592 00593 /* Parse debug directory */ 00594 if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) 00595 { 00596 /* Debug info is stripped to .DBG file */ 00597 const IMAGE_DEBUG_MISC* misc = (const IMAGE_DEBUG_MISC*) 00598 ((const char*)mapping + dbg->PointerToRawData); 00599 00600 if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC || 00601 misc->DataType != IMAGE_DEBUG_MISC_EXENAME) 00602 { 00603 ERR("-Debug info stripped, but no .DBG file in module %s\n", 00604 debugstr_w(module->module.ModuleName)); 00605 } 00606 else 00607 { 00608 ret = pe_load_dbg_file(pcs, module, (const char*)misc->Data, nth->FileHeader.TimeDateStamp); 00609 } 00610 } 00611 else 00612 { 00613 const IMAGE_SECTION_HEADER *sectp = (const IMAGE_SECTION_HEADER*)((const char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); 00614 /* Debug info is embedded into PE module */ 00615 ret = pe_load_debug_directory(pcs, module, mapping, sectp, 00616 nth->FileHeader.NumberOfSections, dbg, nDbg); 00617 } 00618 done: 00619 pe_unmap_full(fmap); 00620 return ret; 00621 } 00622 00623 /*********************************************************************** 00624 * pe_load_export_debug_info 00625 */ 00626 static BOOL pe_load_export_debug_info(const struct process* pcs, struct module* module) 00627 { 00628 struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; 00629 unsigned int i; 00630 const IMAGE_EXPORT_DIRECTORY* exports; 00631 DWORD base = module->module.BaseOfImage; 00632 DWORD size; 00633 IMAGE_NT_HEADERS* nth; 00634 void* mapping; 00635 00636 if (dbghelp_options & SYMOPT_NO_PUBLICS) return TRUE; 00637 00638 if (!(mapping = pe_map_full(fmap, &nth))) return FALSE; 00639 #if 0 00640 /* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */ 00641 /* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */ 00642 symt_new_public(module, NULL, module->module.ModuleName, base, 1); 00643 #endif 00644 00645 /* Add entry point */ 00646 symt_new_public(module, NULL, "EntryPoint", 00647 base + nth->OptionalHeader.AddressOfEntryPoint, 1); 00648 #if 0 00649 /* FIXME: we'd better store addresses linked to sections rather than 00650 absolute values */ 00651 IMAGE_SECTION_HEADER* section; 00652 /* Add start of sections */ 00653 section = (IMAGE_SECTION_HEADER*) 00654 ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); 00655 for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) 00656 { 00657 symt_new_public(module, NULL, section->Name, 00658 RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), 1); 00659 } 00660 #endif 00661 00662 /* Add exported functions */ 00663 if ((exports = RtlImageDirectoryEntryToData(mapping, FALSE, 00664 IMAGE_DIRECTORY_ENTRY_EXPORT, &size))) 00665 { 00666 const WORD* ordinals = NULL; 00667 const DWORD_PTR* functions = NULL; 00668 const DWORD* names = NULL; 00669 unsigned int j; 00670 char buffer[16]; 00671 00672 functions = RtlImageRvaToVa(nth, mapping, exports->AddressOfFunctions, NULL); 00673 ordinals = RtlImageRvaToVa(nth, mapping, exports->AddressOfNameOrdinals, NULL); 00674 names = RtlImageRvaToVa(nth, mapping, exports->AddressOfNames, NULL); 00675 00676 if (functions && ordinals && names) 00677 { 00678 for (i = 0; i < exports->NumberOfNames; i++) 00679 { 00680 if (!names[i]) continue; 00681 symt_new_public(module, NULL, 00682 RtlImageRvaToVa(nth, mapping, names[i], NULL), 00683 base + functions[ordinals[i]], 1); 00684 } 00685 00686 for (i = 0; i < exports->NumberOfFunctions; i++) 00687 { 00688 if (!functions[i]) continue; 00689 /* Check if we already added it with a name */ 00690 for (j = 0; j < exports->NumberOfNames; j++) 00691 if ((ordinals[j] == i) && names[j]) break; 00692 if (j < exports->NumberOfNames) continue; 00693 snprintf(buffer, sizeof(buffer), "%d", i + exports->Base); 00694 symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1); 00695 } 00696 } 00697 } 00698 /* no real debug info, only entry points */ 00699 if (module->module.SymType == SymDeferred) 00700 module->module.SymType = SymExport; 00701 pe_unmap_full(fmap); 00702 00703 return TRUE; 00704 } 00705 00706 /****************************************************************** 00707 * pe_load_debug_info 00708 * 00709 */ 00710 BOOL pe_load_debug_info(const struct process* pcs, struct module* module) 00711 { 00712 BOOL ret = FALSE; 00713 00714 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) 00715 { 00716 ret = pe_load_stabs(pcs, module); 00717 ret = pe_load_dwarf(module) || ret; 00718 ret = pe_load_msc_debug_info(pcs, module) || ret; 00719 ret = ret || pe_load_coff_symbol_table(module); /* FIXME */ 00720 /* if we still have no debug info (we could only get SymExport at this 00721 * point), then do the SymExport except if we have an ELF container, 00722 * in which case we'll rely on the export's on the ELF side 00723 */ 00724 } 00725 /* FIXME shouldn't we check that? if (!module_get_debug(pcs, module)) */ 00726 if (pe_load_export_debug_info(pcs, module) && !ret) 00727 ret = TRUE; 00728 00729 return ret; 00730 } 00731 00732 /****************************************************************** 00733 * pe_load_native_module 00734 * 00735 */ 00736 struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, 00737 HANDLE hFile, DWORD64 base, DWORD size) 00738 { 00739 struct module* module = NULL; 00740 BOOL opened = FALSE; 00741 struct module_format* modfmt; 00742 WCHAR loaded_name[MAX_PATH]; 00743 00744 loaded_name[0] = '\0'; 00745 if (!hFile) 00746 { 00747 assert(name); 00748 00749 if ((hFile = FindExecutableImageExW(name, pcs->search_path, loaded_name, NULL, NULL)) == NULL) 00750 return NULL; 00751 opened = TRUE; 00752 } 00753 else if (name) strcpyW(loaded_name, name); 00754 else if (dbghelp_options & SYMOPT_DEFERRED_LOADS) 00755 FIXME("Trouble ahead (no module name passed in deferred mode)\n"); 00756 if (!(modfmt = HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct pe_module_info)))) 00757 return NULL; 00758 modfmt->u.pe_info = (struct pe_module_info*)(modfmt + 1); 00759 if (pe_map_file(hFile, &modfmt->u.pe_info->fmap, DMT_PE)) 00760 { 00761 if (!base) base = modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.ImageBase; 00762 if (!size) size = modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.SizeOfImage; 00763 00764 module = module_new(pcs, loaded_name, DMT_PE, FALSE, base, size, 00765 modfmt->u.pe_info->fmap.u.pe.ntheader.FileHeader.TimeDateStamp, 00766 modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.CheckSum); 00767 if (module) 00768 { 00769 modfmt->module = module; 00770 modfmt->remove = pe_module_remove; 00771 modfmt->loc_compute = NULL; 00772 00773 module->format_info[DFI_PE] = modfmt; 00774 if (dbghelp_options & SYMOPT_DEFERRED_LOADS) 00775 module->module.SymType = SymDeferred; 00776 else 00777 pe_load_debug_info(pcs, module); 00778 module->reloc_delta = base - modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.ImageBase; 00779 } 00780 else 00781 { 00782 ERR("could not load the module '%s'\n", debugstr_w(loaded_name)); 00783 pe_unmap_file(&modfmt->u.pe_info->fmap); 00784 } 00785 } 00786 if (!module) HeapFree(GetProcessHeap(), 0, modfmt); 00787 00788 if (opened) CloseHandle(hFile); 00789 00790 return module; 00791 } 00792 00793 /****************************************************************** 00794 * pe_load_nt_header 00795 * 00796 */ 00797 BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth) 00798 { 00799 IMAGE_DOS_HEADER dos; 00800 00801 return ReadProcessMemory(hProc, (char*)(DWORD_PTR)base, &dos, sizeof(dos), NULL) && 00802 dos.e_magic == IMAGE_DOS_SIGNATURE && 00803 ReadProcessMemory(hProc, (char*)(DWORD_PTR)(base + dos.e_lfanew), 00804 nth, sizeof(*nth), NULL) && 00805 nth->Signature == IMAGE_NT_SIGNATURE; 00806 } 00807 00808 /****************************************************************** 00809 * pe_load_builtin_module 00810 * 00811 */ 00812 struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name, 00813 DWORD64 base, DWORD64 size) 00814 { 00815 struct module* module = NULL; 00816 00817 if (base && pcs->dbg_hdr_addr) 00818 { 00819 IMAGE_NT_HEADERS nth; 00820 00821 if (pe_load_nt_header(pcs->handle, base, &nth)) 00822 { 00823 if (!size) size = nth.OptionalHeader.SizeOfImage; 00824 module = module_new(pcs, name, DMT_PE, FALSE, base, size, 00825 nth.FileHeader.TimeDateStamp, 00826 nth.OptionalHeader.CheckSum); 00827 } 00828 } 00829 return module; 00830 } 00831 00832 /*********************************************************************** 00833 * ImageDirectoryEntryToDataEx (DBGHELP.@) 00834 * 00835 * Search for specified directory in PE image 00836 * 00837 * PARAMS 00838 * 00839 * base [in] Image base address 00840 * image [in] TRUE - image has been loaded by loader, FALSE - raw file image 00841 * dir [in] Target directory index 00842 * size [out] Receives directory size 00843 * section [out] Receives pointer to section header of section containing directory data 00844 * 00845 * RETURNS 00846 * Success: pointer to directory data 00847 * Failure: NULL 00848 * 00849 */ 00850 PVOID WINAPI ImageDirectoryEntryToDataEx( PVOID base, BOOLEAN image, USHORT dir, PULONG size, PIMAGE_SECTION_HEADER *section ) 00851 { 00852 const IMAGE_NT_HEADERS *nt; 00853 DWORD addr; 00854 00855 *size = 0; 00856 if (section) *section = NULL; 00857 00858 if (!(nt = RtlImageNtHeader( base ))) return NULL; 00859 if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL; 00860 if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL; 00861 00862 *size = nt->OptionalHeader.DataDirectory[dir].Size; 00863 if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)base + addr; 00864 00865 return RtlImageRvaToVa( nt, base, addr, section ); 00866 } 00867 00868 /*********************************************************************** 00869 * ImageDirectoryEntryToData (DBGHELP.@) 00870 * 00871 * NOTES 00872 * See ImageDirectoryEntryToDataEx 00873 */ 00874 PVOID WINAPI ImageDirectoryEntryToData( PVOID base, BOOLEAN image, USHORT dir, PULONG size ) 00875 { 00876 return ImageDirectoryEntryToDataEx( base, image, dir, size, NULL ); 00877 } Generated on Sat May 26 2012 04:22:00 for ReactOS by
1.7.6.1
|