dbghelp: Keep the file map around for every PE module, so that we can access image...
[wine/multimedia.git] / dlls / dbghelp / pe_module.c
blob171d616a8c29c0733d7bdbbe804bfee3a7db2de1
1 /*
2 * File pe_module.c - handle PE module information
4 * Copyright (C) 1996, Eric Youngdale.
5 * Copyright (C) 1999-2000, Ulrich Weigand.
6 * Copyright (C) 2004-2007, Eric Pouech.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <assert.h>
32 #include "dbghelp_private.h"
33 #include "image_private.h"
34 #include "winternl.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
39 struct pe_module_info
41 struct image_file_map fmap;
44 static void* pe_map_full(struct image_file_map* fmap, IMAGE_NT_HEADERS** nth)
46 if (!fmap->u.pe.full_map)
48 fmap->u.pe.full_map = MapViewOfFile(fmap->u.pe.hMap, FILE_MAP_READ, 0, 0, 0);
50 if (fmap->u.pe.full_map)
52 if (nth) *nth = RtlImageNtHeader(fmap->u.pe.full_map);
53 fmap->u.pe.full_count++;
54 return fmap->u.pe.full_map;
56 return IMAGE_NO_MAP;
59 static void pe_unmap_full(struct image_file_map* fmap)
61 if (fmap->u.pe.full_count && !--fmap->u.pe.full_count)
63 UnmapViewOfFile(fmap->u.pe.full_map);
64 fmap->u.pe.full_map = NULL;
68 /******************************************************************
69 * pe_map_section
71 * Maps a single section into memory from an PE file
73 const char* pe_map_section(struct image_section_map* ism)
75 void* mapping;
76 struct pe_file_map* fmap = &ism->fmap->u.pe;
78 if (ism->sidx >= 0 && ism->sidx < fmap->ntheader.FileHeader.NumberOfSections &&
79 fmap->sect[ism->sidx].mapped == IMAGE_NO_MAP)
81 IMAGE_NT_HEADERS* nth;
82 /* FIXME: that's rather drastic, but that will do for now
83 * that's ok if the full file map exists, but we could be less agressive otherwise and
84 * only map the relevant section
86 if ((mapping = pe_map_full(ism->fmap, &nth)))
88 fmap->sect[ism->sidx].mapped = RtlImageRvaToVa(nth, mapping,
89 fmap->sect[ism->sidx].shdr.VirtualAddress,
90 NULL);
91 return fmap->sect[ism->sidx].mapped;
94 return IMAGE_NO_MAP;
97 /******************************************************************
98 * pe_find_section
100 * Finds a section by name (and type) into memory from an PE file
101 * or its alternate if any
103 BOOL pe_find_section(struct image_file_map* fmap, const char* name,
104 struct image_section_map* ism)
106 const char* sectname;
107 unsigned i;
108 char tmp[IMAGE_SIZEOF_SHORT_NAME + 1];
110 for (i = 0; i < fmap->u.pe.ntheader.FileHeader.NumberOfSections; i++)
112 sectname = (const char*)fmap->u.pe.sect[i].shdr.Name;
113 /* long section names start with a '/' (at least on MinGW32) */
114 if (sectname[0] == '/' && fmap->u.pe.strtable)
115 sectname = fmap->u.pe.strtable + atoi(sectname + 1);
116 else
118 /* the section name may not be null terminated */
119 sectname = memcpy(tmp, sectname, IMAGE_SIZEOF_SHORT_NAME);
120 tmp[IMAGE_SIZEOF_SHORT_NAME] = '\0';
122 if (!strcasecmp(sectname, name))
124 ism->fmap = fmap;
125 ism->sidx = i;
126 return TRUE;
129 ism->fmap = NULL;
130 ism->sidx = -1;
132 return FALSE;
135 /******************************************************************
136 * pe_unmap_section
138 * Unmaps a single section from memory
140 void pe_unmap_section(struct image_section_map* ism)
142 if (ism->sidx >= 0 && ism->sidx < ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections &&
143 ism->fmap->u.pe.sect[ism->sidx].mapped != IMAGE_NO_MAP)
145 pe_unmap_full(ism->fmap);
146 ism->fmap->u.pe.sect[ism->sidx].mapped = IMAGE_NO_MAP;
150 /******************************************************************
151 * pe_get_map_size
153 * Get the size of an PE section
155 unsigned pe_get_map_size(const struct image_section_map* ism)
157 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections)
158 return 0;
159 return ism->fmap->u.pe.sect[ism->sidx].shdr.SizeOfRawData;
162 /******************************************************************
163 * pe_map_file
165 * Maps an PE file into memory (and checks it's a real PE file)
167 static BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_type mt)
169 void* mapping;
171 fmap->modtype = mt;
172 fmap->u.pe.hMap = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
173 if (fmap->u.pe.hMap == 0) return FALSE;
174 fmap->u.pe.full_count = 0;
175 fmap->u.pe.full_map = NULL;
176 if (!(mapping = pe_map_full(fmap, NULL))) goto error;
178 switch (mt)
180 case DMT_PE:
182 IMAGE_NT_HEADERS* nthdr;
183 IMAGE_SECTION_HEADER* section;
184 unsigned i;
186 if (!(nthdr = RtlImageNtHeader(mapping))) goto error;
187 memcpy(&fmap->u.pe.ntheader, nthdr, sizeof(fmap->u.pe.ntheader));
188 section = (IMAGE_SECTION_HEADER*)
189 ((char*)&nthdr->OptionalHeader + nthdr->FileHeader.SizeOfOptionalHeader);
190 fmap->u.pe.sect = HeapAlloc(GetProcessHeap(), 0,
191 nthdr->FileHeader.NumberOfSections * sizeof(fmap->u.pe.sect[0]));
192 if (!fmap->u.pe.sect) goto error;
193 for (i = 0; i < nthdr->FileHeader.NumberOfSections; i++)
195 memcpy(&fmap->u.pe.sect[i].shdr, section + i, sizeof(IMAGE_SECTION_HEADER));
196 fmap->u.pe.sect[i].mapped = IMAGE_NO_MAP;
198 if (nthdr->FileHeader.PointerToSymbolTable && nthdr->FileHeader.NumberOfSymbols)
200 /* FIXME ugly: should rather map the relevant content instead of copying it */
201 const char* src = (const char*)mapping +
202 nthdr->FileHeader.PointerToSymbolTable +
203 nthdr->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL);
204 char* dst;
205 DWORD sz = *(DWORD*)src;
207 if ((dst = HeapAlloc(GetProcessHeap(), 0, sz)))
208 memcpy(dst, src, sz);
209 fmap->u.pe.strtable = dst;
211 else fmap->u.pe.strtable = NULL;
213 break;
214 default: assert(0); goto error;
216 pe_unmap_full(fmap);
218 return TRUE;
219 error:
220 pe_unmap_full(fmap);
221 CloseHandle(fmap->u.pe.hMap);
222 return FALSE;
225 /******************************************************************
226 * pe_unmap_file
228 * Unmaps an PE file from memory (previously mapped with pe_map_file)
230 static void pe_unmap_file(struct image_file_map* fmap)
232 if (fmap->u.pe.hMap != 0)
234 struct image_section_map ism;
235 ism.fmap = fmap;
236 for (ism.sidx = 0; ism.sidx < fmap->u.pe.ntheader.FileHeader.NumberOfSections; ism.sidx++)
238 pe_unmap_section(&ism);
240 while (fmap->u.pe.full_count) pe_unmap_full(fmap);
241 HeapFree(GetProcessHeap(), 0, fmap->u.pe.sect);
242 HeapFree(GetProcessHeap(), 0, (void*)fmap->u.pe.strtable); /* FIXME ugly (see pe_map_file) */
243 CloseHandle(fmap->u.pe.hMap);
244 fmap->u.pe.hMap = NULL;
248 static void pe_module_remove(struct process* pcs, struct module* module)
250 pe_unmap_file(&module->pe_info->fmap);
251 HeapFree(GetProcessHeap(), 0, module->pe_info);
254 /******************************************************************
255 * pe_locate_with_coff_symbol_table
257 * Use the COFF symbol table (if any) from the IMAGE_FILE_HEADER to set the absolute address
258 * of global symbols.
259 * Mingw32 requires this for stabs debug information as address for global variables isn't filled in
260 * (this is similar to what is done in elf_module.c when using the .symtab ELF section)
262 static BOOL pe_locate_with_coff_symbol_table(struct module* module)
264 struct image_file_map* fmap = &module->pe_info->fmap;
265 const IMAGE_SYMBOL* isym;
266 int i, numsym, naux;
267 char tmp[9];
268 const char* name;
269 struct hash_table_iter hti;
270 void* ptr;
271 struct symt_data* sym;
272 const char* mapping;
274 numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols;
275 if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym)
276 return TRUE;
277 if (!(mapping = pe_map_full(fmap, NULL))) return FALSE;
278 isym = (const IMAGE_SYMBOL*)(mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable);
280 for (i = 0; i < numsym; i+= naux, isym += naux)
282 if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
283 isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections)
285 if (isym->N.Name.Short)
287 name = memcpy(tmp, isym->N.ShortName, 8);
288 tmp[8] = '\0';
290 else name = fmap->u.pe.strtable + isym->N.Name.Long;
291 if (name[0] == '_') name++;
292 hash_table_iter_init(&module->ht_symbols, &hti, name);
293 while ((ptr = hash_table_iter_up(&hti)))
295 sym = GET_ENTRY(ptr, struct symt_data, hash_elt);
296 if (sym->symt.tag == SymTagData &&
297 (sym->kind == DataIsGlobal || sym->kind == DataIsFileStatic) &&
298 !strcmp(sym->hash_elt.name, name))
300 TRACE("Changing absolute address for %d.%s: %lx -> %s\n",
301 isym->SectionNumber, name, sym->u.var.offset,
302 wine_dbgstr_longlong(module->module.BaseOfImage +
303 fmap->u.pe.sect[isym->SectionNumber - 1].shdr.VirtualAddress +
304 isym->Value));
305 sym->u.var.offset = module->module.BaseOfImage +
306 fmap->u.pe.sect[isym->SectionNumber - 1].shdr.VirtualAddress + isym->Value;
307 break;
311 naux = isym->NumberOfAuxSymbols + 1;
313 pe_unmap_full(fmap);
314 return TRUE;
317 /******************************************************************
318 * pe_load_coff_symbol_table
320 * Load public symbols out of the COFF symbol table (if any).
322 static BOOL pe_load_coff_symbol_table(struct module* module)
324 struct image_file_map* fmap = &module->pe_info->fmap;
325 const IMAGE_SYMBOL* isym;
326 int i, numsym, naux;
327 const char* strtable;
328 char tmp[9];
329 const char* name;
330 const char* lastfilename = NULL;
331 struct symt_compiland* compiland = NULL;
332 const IMAGE_SECTION_HEADER* sect;
333 const char* mapping;
335 numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols;
336 if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym)
337 return TRUE;
338 if (!(mapping = pe_map_full(fmap, NULL))) return FALSE;
339 isym = (const IMAGE_SYMBOL*)((char*)mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable);
340 /* FIXME: no way to get strtable size */
341 strtable = (const char*)&isym[numsym];
342 sect = IMAGE_FIRST_SECTION(&fmap->u.pe.ntheader);
344 for (i = 0; i < numsym; i+= naux, isym += naux)
346 if (isym->StorageClass == IMAGE_SYM_CLASS_FILE)
348 lastfilename = (const char*)(isym + 1);
349 compiland = NULL;
351 if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
352 isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections)
354 if (isym->N.Name.Short)
356 name = memcpy(tmp, isym->N.ShortName, 8);
357 tmp[8] = '\0';
359 else name = strtable + isym->N.Name.Long;
360 if (name[0] == '_') name++;
362 if (!compiland && lastfilename)
363 compiland = symt_new_compiland(module, 0,
364 source_new(module, NULL, lastfilename));
365 symt_new_public(module, compiland, name,
366 module->module.BaseOfImage + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value,
369 naux = isym->NumberOfAuxSymbols + 1;
371 module->module.SymType = SymCoff;
372 module->module.LineNumbers = FALSE;
373 module->module.GlobalSymbols = FALSE;
374 module->module.TypeInfo = FALSE;
375 module->module.SourceIndexed = FALSE;
376 module->module.Publics = TRUE;
377 pe_unmap_full(fmap);
379 return TRUE;
382 static inline void* pe_get_sect(IMAGE_NT_HEADERS* nth, void* mapping,
383 IMAGE_SECTION_HEADER* sect)
385 return (sect) ? RtlImageRvaToVa(nth, mapping, sect->VirtualAddress, NULL) : NULL;
388 static inline DWORD pe_get_sect_size(IMAGE_SECTION_HEADER* sect)
390 return (sect) ? sect->SizeOfRawData : 0;
393 /******************************************************************
394 * pe_load_stabs
396 * look for stabs information in PE header (it's how the mingw compiler provides
397 * its debugging information)
399 static BOOL pe_load_stabs(const struct process* pcs, struct module* module)
401 struct image_file_map* fmap = &module->pe_info->fmap;
402 struct image_section_map sect_stabs, sect_stabstr;
403 BOOL ret = FALSE;
405 if (pe_find_section(fmap, ".stab", &sect_stabs) && pe_find_section(fmap, ".stabstr", &sect_stabstr))
407 const char* stab;
408 const char* stabstr;
410 stab = image_map_section(&sect_stabs);
411 stabstr = image_map_section(&sect_stabstr);
412 if (stab != IMAGE_NO_MAP && stabstr != IMAGE_NO_MAP)
414 ret = stabs_parse(module,
415 module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase,
416 stab, image_get_map_size(&sect_stabs),
417 stabstr, image_get_map_size(&sect_stabstr),
418 NULL, NULL);
420 image_unmap_section(&sect_stabs);
421 image_unmap_section(&sect_stabstr);
422 if (ret) pe_locate_with_coff_symbol_table(module);
424 TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load");
426 return ret;
429 /******************************************************************
430 * pe_load_dwarf
432 * look for dwarf information in PE header (it's also a way for the mingw compiler
433 * to provide its debugging information)
435 static BOOL pe_load_dwarf(const struct process* pcs, struct module* module)
437 struct image_file_map* fmap = &module->pe_info->fmap;
438 struct image_section_map sect_debuginfo, sect_debugstr, sect_debugabbrev, sect_debugline, sect_debugloc;
439 BOOL ret = FALSE;
441 if (pe_find_section(fmap, ".debug_info", &sect_debuginfo))
443 const BYTE* dw2_debuginfo;
444 const BYTE* dw2_debugabbrev;
445 const BYTE* dw2_debugstr;
446 const BYTE* dw2_debugline;
447 const BYTE* dw2_debugloc;
449 pe_find_section(fmap, ".debug_str", &sect_debugstr);
450 pe_find_section(fmap, ".debug_abbrev", &sect_debugabbrev);
451 pe_find_section(fmap, ".debug_line", &sect_debugline);
452 pe_find_section(fmap, ".debug_loc", &sect_debugloc);
454 dw2_debuginfo = (const BYTE*)image_map_section(&sect_debuginfo);
455 dw2_debugabbrev = (const BYTE*)image_map_section(&sect_debugabbrev);
456 dw2_debugstr = (const BYTE*)image_map_section(&sect_debugstr);
457 dw2_debugline = (const BYTE*)image_map_section(&sect_debugline);
458 dw2_debugloc = (const BYTE*)image_map_section(&sect_debugloc);
460 if (dw2_debuginfo != IMAGE_NO_MAP && dw2_debugabbrev != IMAGE_NO_MAP && dw2_debugstr != IMAGE_NO_MAP)
462 ret = dwarf2_parse(module,
463 module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase,
464 NULL, /* FIXME: some thunks to deal with ? */
465 dw2_debuginfo, image_get_map_size(&sect_debuginfo),
466 dw2_debugabbrev, image_get_map_size(&sect_debugabbrev),
467 dw2_debugstr, image_get_map_size(&sect_debugstr),
468 dw2_debugline, image_get_map_size(&sect_debugline),
469 dw2_debugloc, image_get_map_size(&sect_debugloc));
471 image_unmap_section(&sect_debuginfo);
472 image_unmap_section(&sect_debugabbrev);
473 image_unmap_section(&sect_debugstr);
474 image_unmap_section(&sect_debugline);
475 image_unmap_section(&sect_debugloc);
477 TRACE("%s the DWARF debug info\n", ret ? "successfully loaded" : "failed to load");
479 return ret;
482 /******************************************************************
483 * pe_load_dbg_file
485 * loads a .dbg file
487 static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
488 const char* dbg_name, DWORD timestamp)
490 char tmp[MAX_PATH];
491 HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0;
492 const BYTE* dbg_mapping = NULL;
493 BOOL ret = FALSE;
495 TRACE("Processing DBG file %s\n", debugstr_a(dbg_name));
497 if (path_find_symbol_file(pcs, dbg_name, NULL, timestamp, 0, tmp, &module->module.DbgUnmatched) &&
498 (hFile = CreateFileA(tmp, GENERIC_READ, FILE_SHARE_READ, NULL,
499 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE &&
500 ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
501 ((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
503 const IMAGE_SEPARATE_DEBUG_HEADER* hdr;
504 const IMAGE_SECTION_HEADER* sectp;
505 const IMAGE_DEBUG_DIRECTORY* dbg;
507 hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)dbg_mapping;
508 /* section headers come immediately after debug header */
509 sectp = (const IMAGE_SECTION_HEADER*)(hdr + 1);
510 /* and after that and the exported names comes the debug directory */
511 dbg = (const IMAGE_DEBUG_DIRECTORY*)
512 (dbg_mapping + sizeof(*hdr) +
513 hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
514 hdr->ExportedNamesSize);
516 ret = pe_load_debug_directory(pcs, module, dbg_mapping, sectp,
517 hdr->NumberOfSections, dbg,
518 hdr->DebugDirectorySize / sizeof(*dbg));
520 else
521 ERR("Couldn't find .DBG file %s (%s)\n", debugstr_a(dbg_name), debugstr_a(tmp));
523 if (dbg_mapping) UnmapViewOfFile(dbg_mapping);
524 if (hMap) CloseHandle(hMap);
525 if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
526 return ret;
529 /******************************************************************
530 * pe_load_msc_debug_info
532 * Process MSC debug information in PE file.
534 static BOOL pe_load_msc_debug_info(const struct process* pcs, struct module* module)
536 struct image_file_map* fmap = &module->pe_info->fmap;
537 BOOL ret = FALSE;
538 const IMAGE_DATA_DIRECTORY* dir;
539 const IMAGE_DEBUG_DIRECTORY*dbg = NULL;
540 int nDbg;
541 void* mapping;
542 IMAGE_NT_HEADERS* nth;
544 if (!(mapping = pe_map_full(fmap, &nth))) return FALSE;
545 /* Read in debug directory */
546 dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
547 nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
548 if (!nDbg) goto done;
550 dbg = RtlImageRvaToVa(nth, mapping, dir->VirtualAddress, NULL);
552 /* Parse debug directory */
553 if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
555 /* Debug info is stripped to .DBG file */
556 const IMAGE_DEBUG_MISC* misc = (const IMAGE_DEBUG_MISC*)
557 ((const char*)mapping + dbg->PointerToRawData);
559 if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC ||
560 misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
562 WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
563 debugstr_w(module->module.ModuleName));
565 else
567 ret = pe_load_dbg_file(pcs, module, (const char*)misc->Data, nth->FileHeader.TimeDateStamp);
570 else
572 const IMAGE_SECTION_HEADER *sectp = (const IMAGE_SECTION_HEADER*)((const char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
573 /* Debug info is embedded into PE module */
574 ret = pe_load_debug_directory(pcs, module, mapping, sectp,
575 nth->FileHeader.NumberOfSections, dbg, nDbg);
577 done:
578 pe_unmap_full(fmap);
579 return ret;
582 /***********************************************************************
583 * pe_load_export_debug_info
585 static BOOL pe_load_export_debug_info(const struct process* pcs, struct module* module)
587 struct image_file_map* fmap = &module->pe_info->fmap;
588 unsigned int i;
589 const IMAGE_EXPORT_DIRECTORY* exports;
590 DWORD base = module->module.BaseOfImage;
591 DWORD size;
592 IMAGE_NT_HEADERS* nth;
593 void* mapping;
595 if (dbghelp_options & SYMOPT_NO_PUBLICS) return TRUE;
597 if (!(mapping = pe_map_full(fmap, &nth))) return FALSE;
598 #if 0
599 /* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */
600 /* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */
601 symt_new_public(module, NULL, module->module.ModuleName, base, 1);
602 #endif
604 /* Add entry point */
605 symt_new_public(module, NULL, "EntryPoint",
606 base + nth->OptionalHeader.AddressOfEntryPoint, 1);
607 #if 0
608 /* FIXME: we'd better store addresses linked to sections rather than
609 absolute values */
610 IMAGE_SECTION_HEADER* section;
611 /* Add start of sections */
612 section = (IMAGE_SECTION_HEADER*)
613 ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
614 for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
616 symt_new_public(module, NULL, section->Name,
617 RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), 1);
619 #endif
621 /* Add exported functions */
622 if ((exports = RtlImageDirectoryEntryToData(mapping, FALSE,
623 IMAGE_DIRECTORY_ENTRY_EXPORT, &size)))
625 const WORD* ordinals = NULL;
626 const DWORD_PTR* functions = NULL;
627 const DWORD* names = NULL;
628 unsigned int j;
629 char buffer[16];
631 functions = RtlImageRvaToVa(nth, mapping, exports->AddressOfFunctions, NULL);
632 ordinals = RtlImageRvaToVa(nth, mapping, exports->AddressOfNameOrdinals, NULL);
633 names = RtlImageRvaToVa(nth, mapping, exports->AddressOfNames, NULL);
635 if (functions && ordinals && names)
637 for (i = 0; i < exports->NumberOfNames; i++)
639 if (!names[i]) continue;
640 symt_new_public(module, NULL,
641 RtlImageRvaToVa(nth, mapping, names[i], NULL),
642 base + functions[ordinals[i]], 1);
645 for (i = 0; i < exports->NumberOfFunctions; i++)
647 if (!functions[i]) continue;
648 /* Check if we already added it with a name */
649 for (j = 0; j < exports->NumberOfNames; j++)
650 if ((ordinals[j] == i) && names[j]) break;
651 if (j < exports->NumberOfNames) continue;
652 snprintf(buffer, sizeof(buffer), "%d", i + exports->Base);
653 symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1);
657 /* no real debug info, only entry points */
658 if (module->module.SymType == SymDeferred)
659 module->module.SymType = SymExport;
660 pe_unmap_full(fmap);
662 return TRUE;
665 /******************************************************************
666 * pe_load_debug_info
669 BOOL pe_load_debug_info(const struct process* pcs, struct module* module)
671 BOOL ret = FALSE;
673 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
675 ret = pe_load_stabs(pcs, module) ||
676 pe_load_dwarf(pcs, module) ||
677 pe_load_msc_debug_info(pcs, module) ||
678 pe_load_coff_symbol_table(module);
679 /* if we still have no debug info (we could only get SymExport at this
680 * point), then do the SymExport except if we have an ELF container,
681 * in which case we'll rely on the export's on the ELF side
684 /* FIXME shouldn't we check that? if (!module_get_debug(pcs, module)) */
685 if (pe_load_export_debug_info(pcs, module) && !ret)
686 ret = TRUE;
688 return ret;
691 /******************************************************************
692 * pe_load_native_module
695 struct module* pe_load_native_module(struct process* pcs, const WCHAR* name,
696 HANDLE hFile, DWORD base, DWORD size)
698 struct module* module = NULL;
699 BOOL opened = FALSE;
700 struct pe_module_info* module_info;
701 WCHAR loaded_name[MAX_PATH];
703 loaded_name[0] = '\0';
704 if (!hFile)
706 assert(name);
708 if ((hFile = FindExecutableImageExW(name, pcs->search_path, loaded_name, NULL, NULL)) == NULL)
709 return NULL;
710 opened = TRUE;
712 else if (name) strcpyW(loaded_name, name);
713 else if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
714 FIXME("Trouble ahead (no module name passed in deferred mode)\n");
715 if (!(module_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*module_info))))
716 return NULL;
717 if (pe_map_file(hFile, &module_info->fmap, DMT_PE))
719 if (!base) base = module_info->fmap.u.pe.ntheader.OptionalHeader.ImageBase;
720 if (!size) size = module_info->fmap.u.pe.ntheader.OptionalHeader.SizeOfImage;
722 module = module_new(pcs, loaded_name, DMT_PE, FALSE, base, size,
723 module_info->fmap.u.pe.ntheader.FileHeader.TimeDateStamp,
724 module_info->fmap.u.pe.ntheader.OptionalHeader.CheckSum);
725 if (module)
727 module->pe_info = module_info;
728 module->module_remove = pe_module_remove;
729 if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
730 module->module.SymType = SymDeferred;
731 else
732 pe_load_debug_info(pcs, module);
734 else
736 ERR("could not load the module '%s'\n", debugstr_w(loaded_name));
737 pe_unmap_file(&module_info->fmap);
740 if (!module) HeapFree(GetProcessHeap(), 0, module_info);
742 if (opened) CloseHandle(hFile);
744 return module;
747 /******************************************************************
748 * pe_load_nt_header
751 BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth)
753 IMAGE_DOS_HEADER dos;
755 return ReadProcessMemory(hProc, (char*)(DWORD_PTR)base, &dos, sizeof(dos), NULL) &&
756 dos.e_magic == IMAGE_DOS_SIGNATURE &&
757 ReadProcessMemory(hProc, (char*)(DWORD_PTR)(base + dos.e_lfanew),
758 nth, sizeof(*nth), NULL) &&
759 nth->Signature == IMAGE_NT_SIGNATURE;
762 /******************************************************************
763 * pe_load_builtin_module
766 struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name,
767 DWORD64 base, DWORD64 size)
769 struct module* module = NULL;
771 if (base && pcs->dbg_hdr_addr)
773 IMAGE_NT_HEADERS nth;
775 if (pe_load_nt_header(pcs->handle, base, &nth))
777 if (!size) size = nth.OptionalHeader.SizeOfImage;
778 module = module_new(pcs, name, DMT_PE, FALSE, base, size,
779 nth.FileHeader.TimeDateStamp,
780 nth.OptionalHeader.CheckSum);
783 return module;
786 /***********************************************************************
787 * ImageDirectoryEntryToDataEx (DBGHELP.@)
789 * Search for specified directory in PE image
791 * PARAMS
793 * base [in] Image base address
794 * image [in] TRUE - image has been loaded by loader, FALSE - raw file image
795 * dir [in] Target directory index
796 * size [out] Receives directory size
797 * section [out] Receives pointer to section header of section containing directory data
799 * RETURNS
800 * Success: pointer to directory data
801 * Failure: NULL
804 PVOID WINAPI ImageDirectoryEntryToDataEx( PVOID base, BOOLEAN image, USHORT dir, PULONG size, PIMAGE_SECTION_HEADER *section )
806 const IMAGE_NT_HEADERS *nt;
807 DWORD addr;
809 *size = 0;
810 if (section) *section = NULL;
812 if (!(nt = RtlImageNtHeader( base ))) return NULL;
813 if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL;
814 if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
816 *size = nt->OptionalHeader.DataDirectory[dir].Size;
817 if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)base + addr;
819 return RtlImageRvaToVa( nt, base, addr, section );
822 /***********************************************************************
823 * ImageDirectoryEntryToData (DBGHELP.@)
825 * NOTES
826 * See ImageDirectoryEntryToDataEx
828 PVOID WINAPI ImageDirectoryEntryToData( PVOID base, BOOLEAN image, USHORT dir, PULONG size )
830 return ImageDirectoryEntryToDataEx( base, image, dir, size, NULL );