dbghelp: Create the notion of image (PE, ELF modules) to uniformize some handlings.
[wine/multimedia.git] / dlls / dbghelp / pe_module.c
blob4d83889624d2888ecb0bb12510d4331842f1da14
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 static void* pe_map_full(struct image_file_map* fmap, IMAGE_NT_HEADERS** nth)
41 if (!fmap->u.pe.full_map)
43 fmap->u.pe.full_map = MapViewOfFile(fmap->u.pe.hMap, FILE_MAP_READ, 0, 0, 0);
45 if (fmap->u.pe.full_map)
47 if (nth) *nth = RtlImageNtHeader(fmap->u.pe.full_map);
48 fmap->u.pe.full_count++;
49 return fmap->u.pe.full_map;
51 return IMAGE_NO_MAP;
54 static void pe_unmap_full(struct image_file_map* fmap)
56 if (fmap->u.pe.full_count && !--fmap->u.pe.full_count)
58 UnmapViewOfFile(fmap->u.pe.full_map);
59 fmap->u.pe.full_map = NULL;
63 /******************************************************************
64 * pe_map_section
66 * Maps a single section into memory from an PE file
68 const char* pe_map_section(struct image_section_map* ism)
70 void* mapping;
71 struct pe_file_map* fmap = &ism->fmap->u.pe;
73 if (ism->sidx >= 0 && ism->sidx < fmap->ntheader.FileHeader.NumberOfSections &&
74 fmap->sect[ism->sidx].mapped == IMAGE_NO_MAP)
76 IMAGE_NT_HEADERS* nth;
77 /* FIXME: that's rather drastic, but that will do for now
78 * that's ok if the full file map exists, but we could be less agressive otherwise and
79 * only map the relevant section
81 if ((mapping = pe_map_full(ism->fmap, &nth)))
83 fmap->sect[ism->sidx].mapped = RtlImageRvaToVa(nth, mapping,
84 fmap->sect[ism->sidx].shdr.VirtualAddress,
85 NULL);
86 return fmap->sect[ism->sidx].mapped;
89 return IMAGE_NO_MAP;
92 /******************************************************************
93 * pe_find_section
95 * Finds a section by name (and type) into memory from an PE file
96 * or its alternate if any
98 BOOL pe_find_section(struct image_file_map* fmap, const char* name,
99 struct image_section_map* ism)
101 const char* sectname;
102 unsigned i;
103 char tmp[IMAGE_SIZEOF_SHORT_NAME + 1];
105 for (i = 0; i < fmap->u.pe.ntheader.FileHeader.NumberOfSections; i++)
107 sectname = (const char*)fmap->u.pe.sect[i].shdr.Name;
108 /* long section names start with a '/' (at least on MinGW32) */
109 if (sectname[0] == '/' && fmap->u.pe.strtable)
110 sectname = fmap->u.pe.strtable + atoi(sectname + 1);
111 else
113 /* the section name may not be null terminated */
114 sectname = memcpy(tmp, sectname, IMAGE_SIZEOF_SHORT_NAME);
115 tmp[IMAGE_SIZEOF_SHORT_NAME] = '\0';
117 if (!strcasecmp(sectname, name))
119 ism->fmap = fmap;
120 ism->sidx = i;
121 return TRUE;
124 ism->fmap = NULL;
125 ism->sidx = -1;
127 return FALSE;
130 /******************************************************************
131 * pe_unmap_section
133 * Unmaps a single section from memory
135 void pe_unmap_section(struct image_section_map* ism)
137 if (ism->sidx >= 0 && ism->sidx < ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections &&
138 ism->fmap->u.pe.sect[ism->sidx].mapped != IMAGE_NO_MAP)
140 pe_unmap_full(ism->fmap);
141 ism->fmap->u.pe.sect[ism->sidx].mapped = IMAGE_NO_MAP;
145 /******************************************************************
146 * pe_get_map_size
148 * Get the size of an PE section
150 unsigned pe_get_map_size(const struct image_section_map* ism)
152 if (ism->sidx < 0 || ism->sidx >= ism->fmap->u.pe.ntheader.FileHeader.NumberOfSections)
153 return 0;
154 return ism->fmap->u.pe.sect[ism->sidx].shdr.SizeOfRawData;
157 /******************************************************************
158 * pe_map_file
160 * Maps an PE file into memory (and checks it's a real PE file)
162 static BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_type mt)
164 void* mapping;
166 fmap->modtype = mt;
167 fmap->u.pe.hMap = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
168 if (fmap->u.pe.hMap == 0) return FALSE;
169 fmap->u.pe.full_count = 0;
170 fmap->u.pe.full_map = NULL;
171 if (!(mapping = pe_map_full(fmap, NULL))) goto error;
173 switch (mt)
175 case DMT_PE:
177 IMAGE_NT_HEADERS* nthdr;
178 IMAGE_SECTION_HEADER* section;
179 unsigned i;
181 if (!(nthdr = RtlImageNtHeader(mapping))) goto error;
182 memcpy(&fmap->u.pe.ntheader, nthdr, sizeof(fmap->u.pe.ntheader));
183 section = (IMAGE_SECTION_HEADER*)
184 ((char*)&nthdr->OptionalHeader + nthdr->FileHeader.SizeOfOptionalHeader);
185 fmap->u.pe.sect = HeapAlloc(GetProcessHeap(), 0,
186 nthdr->FileHeader.NumberOfSections * sizeof(fmap->u.pe.sect[0]));
187 if (!fmap->u.pe.sect) goto error;
188 for (i = 0; i < nthdr->FileHeader.NumberOfSections; i++)
190 memcpy(&fmap->u.pe.sect[i].shdr, section + i, sizeof(IMAGE_SECTION_HEADER));
191 fmap->u.pe.sect[i].mapped = IMAGE_NO_MAP;
193 if (nthdr->FileHeader.PointerToSymbolTable && nthdr->FileHeader.NumberOfSymbols)
195 /* FIXME ugly: should rather map the relevant content instead of copying it */
196 const char* src = (const char*)mapping +
197 nthdr->FileHeader.PointerToSymbolTable +
198 nthdr->FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL);
199 char* dst;
200 DWORD sz = *(DWORD*)src;
202 if ((dst = HeapAlloc(GetProcessHeap(), 0, sz)))
203 memcpy(dst, src, sz);
204 fmap->u.pe.strtable = dst;
206 else fmap->u.pe.strtable = NULL;
208 break;
209 default: assert(0); goto error;
211 pe_unmap_full(fmap);
213 return TRUE;
214 error:
215 pe_unmap_full(fmap);
216 CloseHandle(fmap->u.pe.hMap);
217 return FALSE;
220 /******************************************************************
221 * pe_unmap_file
223 * Unmaps an PE file from memory (previously mapped with pe_map_file)
225 static void pe_unmap_file(struct image_file_map* fmap)
227 if (fmap->u.pe.hMap != 0)
229 struct image_section_map ism;
230 ism.fmap = fmap;
231 for (ism.sidx = 0; ism.sidx < fmap->u.pe.ntheader.FileHeader.NumberOfSections; ism.sidx++)
233 pe_unmap_section(&ism);
235 while (fmap->u.pe.full_count) pe_unmap_full(fmap);
236 HeapFree(GetProcessHeap(), 0, fmap->u.pe.sect);
237 HeapFree(GetProcessHeap(), 0, (void*)fmap->u.pe.strtable); /* FIXME ugly (see pe_map_file) */
238 CloseHandle(fmap->u.pe.hMap);
242 /******************************************************************
243 * pe_locate_with_coff_symbol_table
245 * Use the COFF symbol table (if any) from the IMAGE_FILE_HEADER to set the absolute address
246 * of global symbols.
247 * Mingw32 requires this for stabs debug information as address for global variables isn't filled in
248 * (this is similar to what is done in elf_module.c when using the .symtab ELF section)
250 static BOOL pe_locate_with_coff_symbol_table(struct module* module, struct image_file_map* fmap)
252 const IMAGE_SYMBOL* isym;
253 int i, numsym, naux;
254 char tmp[9];
255 const char* name;
256 struct hash_table_iter hti;
257 void* ptr;
258 struct symt_data* sym;
259 const char* mapping;
261 numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols;
262 if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym)
263 return TRUE;
264 if (!(mapping = pe_map_full(fmap, NULL))) return FALSE;
265 isym = (const IMAGE_SYMBOL*)(mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable);
267 for (i = 0; i < numsym; i+= naux, isym += naux)
269 if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
270 isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections)
272 if (isym->N.Name.Short)
274 name = memcpy(tmp, isym->N.ShortName, 8);
275 tmp[8] = '\0';
277 else name = fmap->u.pe.strtable + isym->N.Name.Long;
278 if (name[0] == '_') name++;
279 hash_table_iter_init(&module->ht_symbols, &hti, name);
280 while ((ptr = hash_table_iter_up(&hti)))
282 sym = GET_ENTRY(ptr, struct symt_data, hash_elt);
283 if (sym->symt.tag == SymTagData &&
284 (sym->kind == DataIsGlobal || sym->kind == DataIsFileStatic) &&
285 !strcmp(sym->hash_elt.name, name))
287 TRACE("Changing absolute address for %d.%s: %lx -> %s\n",
288 isym->SectionNumber, name, sym->u.var.offset,
289 wine_dbgstr_longlong(module->module.BaseOfImage +
290 fmap->u.pe.sect[isym->SectionNumber - 1].shdr.VirtualAddress +
291 isym->Value));
292 sym->u.var.offset = module->module.BaseOfImage +
293 fmap->u.pe.sect[isym->SectionNumber - 1].shdr.VirtualAddress + isym->Value;
294 break;
298 naux = isym->NumberOfAuxSymbols + 1;
300 pe_unmap_full(fmap);
301 return TRUE;
304 /******************************************************************
305 * pe_load_coff_symbol_table
307 * Load public symbols out of the COFF symbol table (if any).
309 static BOOL pe_load_coff_symbol_table(struct module* module, struct image_file_map* fmap)
311 const IMAGE_SYMBOL* isym;
312 int i, numsym, naux;
313 const char* strtable;
314 char tmp[9];
315 const char* name;
316 const char* lastfilename = NULL;
317 struct symt_compiland* compiland = NULL;
318 const IMAGE_SECTION_HEADER* sect;
319 const char* mapping;
321 numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols;
322 if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym)
323 return TRUE;
324 if (!(mapping = pe_map_full(fmap, NULL))) return FALSE;
325 isym = (const IMAGE_SYMBOL*)((char*)mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable);
326 /* FIXME: no way to get strtable size */
327 strtable = (const char*)&isym[numsym];
328 sect = IMAGE_FIRST_SECTION(&fmap->u.pe.ntheader);
330 for (i = 0; i < numsym; i+= naux, isym += naux)
332 if (isym->StorageClass == IMAGE_SYM_CLASS_FILE)
334 lastfilename = (const char*)(isym + 1);
335 compiland = NULL;
337 if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
338 isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections)
340 if (isym->N.Name.Short)
342 name = memcpy(tmp, isym->N.ShortName, 8);
343 tmp[8] = '\0';
345 else name = strtable + isym->N.Name.Long;
346 if (name[0] == '_') name++;
348 if (!compiland && lastfilename)
349 compiland = symt_new_compiland(module, 0,
350 source_new(module, NULL, lastfilename));
351 symt_new_public(module, compiland, name,
352 module->module.BaseOfImage + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value,
355 naux = isym->NumberOfAuxSymbols + 1;
357 module->module.SymType = SymCoff;
358 module->module.LineNumbers = FALSE;
359 module->module.GlobalSymbols = FALSE;
360 module->module.TypeInfo = FALSE;
361 module->module.SourceIndexed = FALSE;
362 module->module.Publics = TRUE;
363 pe_unmap_full(fmap);
365 return TRUE;
368 static inline void* pe_get_sect(IMAGE_NT_HEADERS* nth, void* mapping,
369 IMAGE_SECTION_HEADER* sect)
371 return (sect) ? RtlImageRvaToVa(nth, mapping, sect->VirtualAddress, NULL) : NULL;
374 static inline DWORD pe_get_sect_size(IMAGE_SECTION_HEADER* sect)
376 return (sect) ? sect->SizeOfRawData : 0;
379 /******************************************************************
380 * pe_load_stabs
382 * look for stabs information in PE header (it's how the mingw compiler provides
383 * its debugging information)
385 static BOOL pe_load_stabs(const struct process* pcs, struct module* module, struct image_file_map* fmap)
387 struct image_section_map sect_stabs, sect_stabstr;
388 BOOL ret = FALSE;
390 if (pe_find_section(fmap, ".stab", &sect_stabs) && pe_find_section(fmap, ".stabstr", &sect_stabstr))
392 const char* stab;
393 const char* stabstr;
395 stab = image_map_section(&sect_stabs);
396 stabstr = image_map_section(&sect_stabstr);
397 if (stab != IMAGE_NO_MAP && stabstr != IMAGE_NO_MAP)
399 ret = stabs_parse(module,
400 module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase,
401 stab, image_get_map_size(&sect_stabs),
402 stabstr, image_get_map_size(&sect_stabstr),
403 NULL, NULL);
405 image_unmap_section(&sect_stabs);
406 image_unmap_section(&sect_stabstr);
407 if (ret) pe_locate_with_coff_symbol_table(module, fmap);
409 TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load");
411 return ret;
414 /******************************************************************
415 * pe_load_dwarf
417 * look for dwarf information in PE header (it's also a way for the mingw compiler
418 * to provide its debugging information)
420 static BOOL pe_load_dwarf(const struct process* pcs, struct module* module,
421 struct image_file_map* fmap)
423 struct image_section_map sect_debuginfo, sect_debugstr, sect_debugabbrev, sect_debugline, sect_debugloc;
424 BOOL ret = FALSE;
426 if (pe_find_section(fmap, ".debug_info", &sect_debuginfo))
428 const BYTE* dw2_debuginfo;
429 const BYTE* dw2_debugabbrev;
430 const BYTE* dw2_debugstr;
431 const BYTE* dw2_debugline;
432 const BYTE* dw2_debugloc;
434 pe_find_section(fmap, ".debug_str", &sect_debugstr);
435 pe_find_section(fmap, ".debug_abbrev", &sect_debugabbrev);
436 pe_find_section(fmap, ".debug_line", &sect_debugline);
437 pe_find_section(fmap, ".debug_loc", &sect_debugloc);
439 dw2_debuginfo = (const BYTE*)image_map_section(&sect_debuginfo);
440 dw2_debugabbrev = (const BYTE*)image_map_section(&sect_debugabbrev);
441 dw2_debugstr = (const BYTE*)image_map_section(&sect_debugstr);
442 dw2_debugline = (const BYTE*)image_map_section(&sect_debugline);
443 dw2_debugloc = (const BYTE*)image_map_section(&sect_debugloc);
445 if (dw2_debuginfo != IMAGE_NO_MAP && dw2_debugabbrev != IMAGE_NO_MAP && dw2_debugstr != IMAGE_NO_MAP)
447 ret = dwarf2_parse(module,
448 module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase,
449 NULL, /* FIXME: some thunks to deal with ? */
450 dw2_debuginfo, image_get_map_size(&sect_debuginfo),
451 dw2_debugabbrev, image_get_map_size(&sect_debugabbrev),
452 dw2_debugstr, image_get_map_size(&sect_debugstr),
453 dw2_debugline, image_get_map_size(&sect_debugline),
454 dw2_debugloc, image_get_map_size(&sect_debugloc));
456 image_unmap_section(&sect_debuginfo);
457 image_unmap_section(&sect_debugabbrev);
458 image_unmap_section(&sect_debugstr);
459 image_unmap_section(&sect_debugline);
460 image_unmap_section(&sect_debugloc);
462 TRACE("%s the DWARF debug info\n", ret ? "successfully loaded" : "failed to load");
464 return ret;
467 /******************************************************************
468 * pe_load_dbg_file
470 * loads a .dbg file
472 static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
473 const char* dbg_name, DWORD timestamp)
475 char tmp[MAX_PATH];
476 HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0;
477 const BYTE* dbg_mapping = NULL;
478 BOOL ret = FALSE;
480 TRACE("Processing DBG file %s\n", debugstr_a(dbg_name));
482 if (path_find_symbol_file(pcs, dbg_name, NULL, timestamp, 0, tmp, &module->module.DbgUnmatched) &&
483 (hFile = CreateFileA(tmp, GENERIC_READ, FILE_SHARE_READ, NULL,
484 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE &&
485 ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
486 ((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
488 const IMAGE_SEPARATE_DEBUG_HEADER* hdr;
489 const IMAGE_SECTION_HEADER* sectp;
490 const IMAGE_DEBUG_DIRECTORY* dbg;
492 hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)dbg_mapping;
493 /* section headers come immediately after debug header */
494 sectp = (const IMAGE_SECTION_HEADER*)(hdr + 1);
495 /* and after that and the exported names comes the debug directory */
496 dbg = (const IMAGE_DEBUG_DIRECTORY*)
497 (dbg_mapping + sizeof(*hdr) +
498 hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
499 hdr->ExportedNamesSize);
501 ret = pe_load_debug_directory(pcs, module, dbg_mapping, sectp,
502 hdr->NumberOfSections, dbg,
503 hdr->DebugDirectorySize / sizeof(*dbg));
505 else
506 ERR("Couldn't find .DBG file %s (%s)\n", debugstr_a(dbg_name), debugstr_a(tmp));
508 if (dbg_mapping) UnmapViewOfFile(dbg_mapping);
509 if (hMap) CloseHandle(hMap);
510 if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
511 return ret;
514 /******************************************************************
515 * pe_load_msc_debug_info
517 * Process MSC debug information in PE file.
519 static BOOL pe_load_msc_debug_info(const struct process* pcs, struct module* module, struct image_file_map* fmap)
521 BOOL ret = FALSE;
522 const IMAGE_DATA_DIRECTORY* dir;
523 const IMAGE_DEBUG_DIRECTORY*dbg = NULL;
524 int nDbg;
525 void* mapping;
526 IMAGE_NT_HEADERS* nth;
528 if (!(mapping = pe_map_full(fmap, &nth))) return FALSE;
529 /* Read in debug directory */
530 dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
531 nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
532 if (!nDbg) goto done;
534 dbg = RtlImageRvaToVa(nth, mapping, dir->VirtualAddress, NULL);
536 /* Parse debug directory */
537 if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
539 /* Debug info is stripped to .DBG file */
540 const IMAGE_DEBUG_MISC* misc = (const IMAGE_DEBUG_MISC*)
541 ((const char*)mapping + dbg->PointerToRawData);
543 if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC ||
544 misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
546 WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
547 debugstr_w(module->module.ModuleName));
549 else
551 ret = pe_load_dbg_file(pcs, module, (const char*)misc->Data, nth->FileHeader.TimeDateStamp);
554 else
556 const IMAGE_SECTION_HEADER *sectp = (const IMAGE_SECTION_HEADER*)((const char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
557 /* Debug info is embedded into PE module */
558 ret = pe_load_debug_directory(pcs, module, mapping, sectp,
559 nth->FileHeader.NumberOfSections, dbg, nDbg);
561 done:
562 pe_unmap_full(fmap);
563 return ret;
566 /***********************************************************************
567 * pe_load_export_debug_info
569 static BOOL pe_load_export_debug_info(const struct process* pcs, struct module* module, struct image_file_map* fmap)
571 unsigned int i;
572 const IMAGE_EXPORT_DIRECTORY* exports;
573 DWORD base = module->module.BaseOfImage;
574 DWORD size;
575 IMAGE_NT_HEADERS* nth;
576 void* mapping;
578 if (dbghelp_options & SYMOPT_NO_PUBLICS) return TRUE;
580 if (!(mapping = pe_map_full(fmap, &nth))) return FALSE;
581 #if 0
582 /* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */
583 /* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */
584 symt_new_public(module, NULL, module->module.ModuleName, base, 1);
585 #endif
587 /* Add entry point */
588 symt_new_public(module, NULL, "EntryPoint",
589 base + nth->OptionalHeader.AddressOfEntryPoint, 1);
590 #if 0
591 /* FIXME: we'd better store addresses linked to sections rather than
592 absolute values */
593 IMAGE_SECTION_HEADER* section;
594 /* Add start of sections */
595 section = (IMAGE_SECTION_HEADER*)
596 ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
597 for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
599 symt_new_public(module, NULL, section->Name,
600 RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), 1);
602 #endif
604 /* Add exported functions */
605 if ((exports = RtlImageDirectoryEntryToData(mapping, FALSE,
606 IMAGE_DIRECTORY_ENTRY_EXPORT, &size)))
608 const WORD* ordinals = NULL;
609 const DWORD_PTR* functions = NULL;
610 const DWORD* names = NULL;
611 unsigned int j;
612 char buffer[16];
614 functions = RtlImageRvaToVa(nth, mapping, exports->AddressOfFunctions, NULL);
615 ordinals = RtlImageRvaToVa(nth, mapping, exports->AddressOfNameOrdinals, NULL);
616 names = RtlImageRvaToVa(nth, mapping, exports->AddressOfNames, NULL);
618 if (functions && ordinals && names)
620 for (i = 0; i < exports->NumberOfNames; i++)
622 if (!names[i]) continue;
623 symt_new_public(module, NULL,
624 RtlImageRvaToVa(nth, mapping, names[i], NULL),
625 base + functions[ordinals[i]], 1);
628 for (i = 0; i < exports->NumberOfFunctions; i++)
630 if (!functions[i]) continue;
631 /* Check if we already added it with a name */
632 for (j = 0; j < exports->NumberOfNames; j++)
633 if ((ordinals[j] == i) && names[j]) break;
634 if (j < exports->NumberOfNames) continue;
635 snprintf(buffer, sizeof(buffer), "%d", i + exports->Base);
636 symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1);
640 /* no real debug info, only entry points */
641 if (module->module.SymType == SymDeferred)
642 module->module.SymType = SymExport;
643 pe_unmap_full(fmap);
645 return TRUE;
648 /******************************************************************
649 * pe_load_debug_info
652 BOOL pe_load_debug_info_internal(const struct process* pcs, struct module* module,
653 struct image_file_map* fmap)
655 BOOL ret = FALSE;
657 if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
659 ret = pe_load_stabs(pcs, module, fmap) ||
660 pe_load_dwarf(pcs, module, fmap) ||
661 pe_load_msc_debug_info(pcs, module, fmap) ||
662 pe_load_coff_symbol_table(module, fmap);
663 /* if we still have no debug info (we could only get SymExport at this
664 * point), then do the SymExport except if we have an ELF container,
665 * in which case we'll rely on the export's on the ELF side
668 /* FIXME shouldn't we check that? if (!module_get_debug(pcs, module))l */
669 if (pe_load_export_debug_info(pcs, module, fmap) && !ret)
670 ret = TRUE;
672 return ret;
675 BOOL pe_load_debug_info(const struct process* pcs, struct module* module)
677 BOOL ret = FALSE;
678 HANDLE hFile;
679 struct image_file_map fmap;
681 hFile = CreateFileW(module->module.LoadedImageName, GENERIC_READ, FILE_SHARE_READ,
682 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
683 if (hFile == INVALID_HANDLE_VALUE) return FALSE;
684 if (pe_map_file(hFile, &fmap, DMT_PE))
686 ret = pe_load_debug_info_internal(pcs, module, &fmap);
687 pe_unmap_file(&fmap);
689 CloseHandle(hFile);
691 return ret;
694 /******************************************************************
695 * pe_load_native_module
698 struct module* pe_load_native_module(struct process* pcs, const WCHAR* name,
699 HANDLE hFile, DWORD base, DWORD size)
701 struct module* module = NULL;
702 BOOL opened = FALSE;
703 struct image_file_map fmap;
704 WCHAR loaded_name[MAX_PATH];
706 loaded_name[0] = '\0';
707 if (!hFile)
709 assert(name);
711 if ((hFile = FindExecutableImageExW(name, pcs->search_path, loaded_name, NULL, NULL)) == NULL)
712 return NULL;
713 opened = TRUE;
715 else if (name) strcpyW(loaded_name, name);
716 else if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
717 FIXME("Trouble ahead (no module name passed in deferred mode)\n");
719 if (pe_map_file(hFile, &fmap, DMT_PE))
721 if (!base) base = fmap.u.pe.ntheader.OptionalHeader.ImageBase;
722 if (!size) size = fmap.u.pe.ntheader.OptionalHeader.SizeOfImage;
724 module = module_new(pcs, loaded_name, DMT_PE, FALSE, base, size,
725 fmap.u.pe.ntheader.FileHeader.TimeDateStamp,
726 fmap.u.pe.ntheader.OptionalHeader.CheckSum);
727 if (module)
729 if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
730 module->module.SymType = SymDeferred;
731 else
732 pe_load_debug_info_internal(pcs, module, &fmap);
734 else ERR("could not load the module '%s'\n", debugstr_w(loaded_name));
735 pe_unmap_file(&fmap);
737 if (opened) CloseHandle(hFile);
739 return module;
742 /******************************************************************
743 * pe_load_nt_header
746 BOOL pe_load_nt_header(HANDLE hProc, DWORD64 base, IMAGE_NT_HEADERS* nth)
748 IMAGE_DOS_HEADER dos;
750 return ReadProcessMemory(hProc, (char*)(DWORD_PTR)base, &dos, sizeof(dos), NULL) &&
751 dos.e_magic == IMAGE_DOS_SIGNATURE &&
752 ReadProcessMemory(hProc, (char*)(DWORD_PTR)(base + dos.e_lfanew),
753 nth, sizeof(*nth), NULL) &&
754 nth->Signature == IMAGE_NT_SIGNATURE;
757 /******************************************************************
758 * pe_load_builtin_module
761 struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name,
762 DWORD64 base, DWORD64 size)
764 struct module* module = NULL;
766 if (base && pcs->dbg_hdr_addr)
768 IMAGE_NT_HEADERS nth;
770 if (pe_load_nt_header(pcs->handle, base, &nth))
772 if (!size) size = nth.OptionalHeader.SizeOfImage;
773 module = module_new(pcs, name, DMT_PE, FALSE, base, size,
774 nth.FileHeader.TimeDateStamp,
775 nth.OptionalHeader.CheckSum);
778 return module;
781 /***********************************************************************
782 * ImageDirectoryEntryToDataEx (DBGHELP.@)
784 * Search for specified directory in PE image
786 * PARAMS
788 * base [in] Image base address
789 * image [in] TRUE - image has been loaded by loader, FALSE - raw file image
790 * dir [in] Target directory index
791 * size [out] Receives directory size
792 * section [out] Receives pointer to section header of section containing directory data
794 * RETURNS
795 * Success: pointer to directory data
796 * Failure: NULL
799 PVOID WINAPI ImageDirectoryEntryToDataEx( PVOID base, BOOLEAN image, USHORT dir, PULONG size, PIMAGE_SECTION_HEADER *section )
801 const IMAGE_NT_HEADERS *nt;
802 DWORD addr;
804 *size = 0;
805 if (section) *section = NULL;
807 if (!(nt = RtlImageNtHeader( base ))) return NULL;
808 if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL;
809 if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
811 *size = nt->OptionalHeader.DataDirectory[dir].Size;
812 if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)base + addr;
814 return RtlImageRvaToVa( nt, base, addr, section );
817 /***********************************************************************
818 * ImageDirectoryEntryToData (DBGHELP.@)
820 * NOTES
821 * See ImageDirectoryEntryToDataEx
823 PVOID WINAPI ImageDirectoryEntryToData( PVOID base, BOOLEAN image, USHORT dir, PULONG size )
825 return ImageDirectoryEntryToDataEx( base, image, dir, size, NULL );