Make it possible to add auxiliary values to the existing array; this
[wine.git] / programs / winedbg / pe.c
blobef021f6e895055cafb41baed47f361e097782df7
1 /*
2 * File pe.c - handle PE module information
4 * Copyright (C) 1996, Eric Youngdale.
5 * Copyright (C) 1999, 2000, Ulrich Weigand.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 #ifndef PATH_MAX
33 #define PATH_MAX MAX_PATH
34 #endif
35 #include "wine/exception.h"
36 #include "wine/debug.h"
37 #include "excpt.h"
38 #include "debugger.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
42 #define MAX_PATHNAME_LEN 1024
44 typedef struct
46 DWORD from;
47 DWORD to;
49 } OMAP_DATA;
51 typedef struct tagMSC_DBG_INFO
53 int nsect;
54 PIMAGE_SECTION_HEADER sectp;
55 int nomap;
56 OMAP_DATA* omapp;
58 } MSC_DBG_INFO;
60 /***********************************************************************
61 * DEBUG_LocateDebugInfoFile
63 * NOTE: dbg_filename must be at least MAX_PATHNAME_LEN bytes in size
65 static void DEBUG_LocateDebugInfoFile(const char* filename, char* dbg_filename)
67 char* str1 = DBG_alloc(MAX_PATHNAME_LEN);
68 char* str2 = DBG_alloc(MAX_PATHNAME_LEN*10);
69 const char* file;
70 char* name_part;
72 file = strrchr(filename, '\\');
73 if (file == NULL) file = filename; else file++;
75 if ((GetEnvironmentVariable("_NT_SYMBOL_PATH", str1, MAX_PATHNAME_LEN) &&
76 (SearchPath(str1, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part))) ||
77 (GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", str1, MAX_PATHNAME_LEN) &&
78 (SearchPath(str1, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part))) ||
79 (SearchPath(NULL, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part)))
80 lstrcpyn(dbg_filename, str2, MAX_PATHNAME_LEN);
81 else
82 lstrcpyn(dbg_filename, filename, MAX_PATHNAME_LEN);
83 DBG_free(str1);
84 DBG_free(str2);
87 /***********************************************************************
88 * DEBUG_MapDebugInfoFile
90 void* DEBUG_MapDebugInfoFile(const char* name, DWORD offset, DWORD size,
91 HANDLE* hFile, HANDLE* hMap)
93 DWORD g_offset; /* offset aligned on map granuality */
94 DWORD g_size; /* size to map, with offset aligned */
95 char* ret;
97 *hMap = 0;
99 if (name != NULL)
101 char filename[MAX_PATHNAME_LEN];
103 DEBUG_LocateDebugInfoFile(name, filename);
104 if ((*hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
105 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
106 return NULL;
109 if (!size)
111 DWORD file_size = GetFileSize(*hFile, NULL);
112 if (file_size == (DWORD)-1) return NULL;
113 size = file_size - offset;
116 g_offset = offset & ~0xFFFF; /* FIXME: is granularity portable ? */
117 g_size = offset + size - g_offset;
119 if ((*hMap = CreateFileMapping(*hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == 0)
120 return NULL;
122 if ((ret = MapViewOfFile(*hMap, FILE_MAP_READ, 0, g_offset, g_size)) != NULL)
123 ret += offset - g_offset;
125 return ret;
128 /***********************************************************************
129 * DEBUG_UnmapDebugInfoFile
131 void DEBUG_UnmapDebugInfoFile(HANDLE hFile, HANDLE hMap, const void* addr)
133 if (addr) UnmapViewOfFile((void*)addr);
134 if (hMap) CloseHandle(hMap);
135 if (hFile!=INVALID_HANDLE_VALUE) CloseHandle(hFile);
138 /*========================================================================
139 * Process DBG file.
141 static enum DbgInfoLoad DEBUG_ProcessDBGFile(DBG_MODULE* module,
142 const char* filename, DWORD timestamp)
144 enum DbgInfoLoad dil = DIL_ERROR;
145 HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0;
146 const BYTE* file_map = NULL;
147 PIMAGE_SEPARATE_DEBUG_HEADER hdr;
148 PIMAGE_DEBUG_DIRECTORY dbg;
149 int nDbg;
151 WINE_TRACE("Processing DBG file %s\n", filename);
153 file_map = DEBUG_MapDebugInfoFile(filename, 0, 0, &hFile, &hMap);
154 if (!file_map)
156 WINE_ERR("-Unable to peruse .DBG file %s\n", filename);
157 goto leave;
160 hdr = (PIMAGE_SEPARATE_DEBUG_HEADER) file_map;
162 if (hdr->TimeDateStamp != timestamp)
164 WINE_ERR("Warning - %s has incorrect internal timestamp\n", filename);
166 * Well, sometimes this happens to DBG files which ARE REALLY the right .DBG
167 * files but nonetheless this check fails. Anyway, WINDBG (debugger for
168 * Windows by Microsoft) loads debug symbols which have incorrect timestamps.
173 dbg = (PIMAGE_DEBUG_DIRECTORY)
174 (file_map + sizeof(*hdr) + hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
175 + hdr->ExportedNamesSize);
177 nDbg = hdr->DebugDirectorySize / sizeof(*dbg);
179 dil = DEBUG_ProcessDebugDirectory(module, file_map, dbg, nDbg);
181 leave:
182 DEBUG_UnmapDebugInfoFile(hFile, hMap, file_map);
183 return dil;
187 /*========================================================================
188 * Process MSC debug information in PE file.
190 enum DbgInfoLoad DEBUG_RegisterMSCDebugInfo(DBG_MODULE* module, HANDLE hFile,
191 void* _nth, unsigned long nth_ofs)
193 enum DbgInfoLoad dil = DIL_ERROR;
194 PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth;
195 PIMAGE_DATA_DIRECTORY dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
196 PIMAGE_DEBUG_DIRECTORY dbg = NULL;
197 int nDbg;
198 MSC_DBG_INFO extra_info = { 0, NULL, 0, NULL };
199 HANDLE hMap = 0;
200 const BYTE* file_map = NULL;
202 /* Read in section data */
204 module->msc_dbg_info = &extra_info;
205 extra_info.nsect = nth->FileHeader.NumberOfSections;
206 extra_info.sectp = DBG_alloc(extra_info.nsect * sizeof(IMAGE_SECTION_HEADER));
207 if (!extra_info.sectp)
208 goto leave;
210 if (!DEBUG_READ_MEM_VERBOSE((char*)module->load_addr +
211 nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
212 nth->FileHeader.SizeOfOptionalHeader,
213 extra_info.sectp,
214 extra_info.nsect * sizeof(IMAGE_SECTION_HEADER)))
215 goto leave;
217 /* Read in debug directory */
219 nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
220 if (!nDbg)
221 goto leave;
223 dbg = (PIMAGE_DEBUG_DIRECTORY) DBG_alloc(nDbg * sizeof(IMAGE_DEBUG_DIRECTORY));
224 if (!dbg)
225 goto leave;
227 if (!DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + dir->VirtualAddress,
228 dbg, nDbg * sizeof(IMAGE_DEBUG_DIRECTORY)))
229 goto leave;
232 /* Map in PE file */
233 file_map = DEBUG_MapDebugInfoFile(NULL, 0, 0, &hFile, &hMap);
234 if (!file_map)
235 goto leave;
238 /* Parse debug directory */
240 if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
242 /* Debug info is stripped to .DBG file */
244 PIMAGE_DEBUG_MISC misc = (PIMAGE_DEBUG_MISC)(file_map + dbg->PointerToRawData);
246 if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC
247 || misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
249 WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
250 module->module_name);
251 goto leave;
254 dil = DEBUG_ProcessDBGFile(module, misc->Data, nth->FileHeader.TimeDateStamp);
256 else
258 /* Debug info is embedded into PE module */
259 /* FIXME: the nDBG information we're manipulating comes from the debuggee
260 * address space. However, the following code will be made against the
261 * version mapped in the debugger address space. There are cases (for example
262 * when the PE sections are compressed in the file and become decompressed
263 * in the debuggee address space) where the two don't match.
264 * Therefore, redo the DBG information lookup with the mapped data
266 PIMAGE_NT_HEADERS mpd_nth = (PIMAGE_NT_HEADERS)(file_map + nth_ofs);
267 PIMAGE_DATA_DIRECTORY mpd_dir;
268 PIMAGE_DEBUG_DIRECTORY mpd_dbg = NULL;
270 /* sanity checks */
271 if (mpd_nth->Signature != IMAGE_NT_SIGNATURE ||
272 mpd_nth->FileHeader.NumberOfSections != nth->FileHeader.NumberOfSections ||
273 (mpd_nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) != 0)
274 goto leave;
275 mpd_dir = mpd_nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
277 if ((mpd_dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY)) != nDbg)
278 goto leave;
280 mpd_dbg = (PIMAGE_DEBUG_DIRECTORY)(file_map + mpd_dir->VirtualAddress);
282 dil = DEBUG_ProcessDebugDirectory(module, file_map, mpd_dbg, nDbg);
286 leave:
287 module->msc_dbg_info = NULL;
289 DEBUG_UnmapDebugInfoFile(0, hMap, file_map);
290 if (extra_info.sectp) DBG_free(extra_info.sectp);
291 if (dbg) DBG_free(dbg);
292 return dil;
296 /*========================================================================
297 * look for stabs information in PE header (it's how mingw compiler provides its
298 * debugging information), and also wine PE <-> ELF linking through .wsolnk sections
300 enum DbgInfoLoad DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module, HANDLE hFile,
301 void* _nth, unsigned long nth_ofs)
303 IMAGE_SECTION_HEADER pe_seg;
304 unsigned long pe_seg_ofs;
305 int i, stabsize = 0, stabstrsize = 0;
306 unsigned int stabs = 0, stabstr = 0;
307 PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth;
308 enum DbgInfoLoad dil = DIL_ERROR;
310 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
311 nth->FileHeader.SizeOfOptionalHeader;
313 for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
315 if (!DEBUG_READ_MEM_VERBOSE((void*)((char*)module->load_addr + pe_seg_ofs),
316 &pe_seg, sizeof(pe_seg)))
317 continue;
319 if (!strcasecmp(pe_seg.Name, ".stab"))
321 stabs = pe_seg.VirtualAddress;
322 stabsize = pe_seg.SizeOfRawData;
324 else if (!strncasecmp(pe_seg.Name, ".stabstr", 8))
326 stabstr = pe_seg.VirtualAddress;
327 stabstrsize = pe_seg.SizeOfRawData;
331 if (stabstrsize && stabsize)
333 char* s1 = DBG_alloc(stabsize+stabstrsize);
335 if (s1)
337 if (DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabs, s1, stabsize) &&
338 DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabstr,
339 s1 + stabsize, stabstrsize))
341 dil = DEBUG_ParseStabs(s1, 0, 0, stabsize, stabsize, stabstrsize);
343 else
345 DEBUG_Printf("couldn't read data block\n");
347 DBG_free(s1);
349 else
351 DEBUG_Printf("couldn't alloc %d bytes\n", stabsize + stabstrsize);
354 else
356 dil = DIL_NOINFO;
358 return dil;
361 /***********************************************************************
362 * DEBUG_RegisterPEDebugInfo
364 enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
365 void* _nth, unsigned long nth_ofs)
367 DBG_VALUE value;
368 char buffer[512];
369 char bufstr[256];
370 unsigned int i;
371 IMAGE_SECTION_HEADER pe_seg;
372 DWORD pe_seg_ofs;
373 IMAGE_DATA_DIRECTORY dir;
374 DWORD dir_ofs;
375 const char* prefix;
376 IMAGE_NT_HEADERS* nth = (PIMAGE_NT_HEADERS)_nth;
377 void* base = wmod->load_addr;
379 value.type = NULL;
380 value.cookie = DV_TARGET;
381 value.addr.seg = 0;
382 value.addr.off = 0;
384 /* Add start of DLL */
385 value.addr.off = (unsigned long)base;
386 if ((prefix = strrchr(wmod->module_name, '\\'))) prefix++;
387 else prefix = wmod->module_name;
389 DEBUG_AddSymbol(prefix, &value, NULL, SYM_WIN32 | SYM_FUNC);
391 /* Add entry point */
392 snprintf(buffer, sizeof(buffer), "%s.EntryPoint", prefix);
393 value.addr.off = (unsigned long)base + nth->OptionalHeader.AddressOfEntryPoint;
394 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
396 /* Add start of sections */
397 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
398 nth->FileHeader.SizeOfOptionalHeader;
400 for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
402 if (!DEBUG_READ_MEM_VERBOSE((char*)base + pe_seg_ofs, &pe_seg, sizeof(pe_seg)))
403 continue;
404 snprintf(buffer, sizeof(buffer), "%s.%s", prefix, pe_seg.Name);
405 value.addr.off = (unsigned long)base + pe_seg.VirtualAddress;
406 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
409 /* Add exported functions */
410 dir_ofs = nth_ofs +
411 OFFSET_OF(IMAGE_NT_HEADERS,
412 OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
413 if (DEBUG_READ_MEM_VERBOSE((char*)base + dir_ofs, &dir, sizeof(dir)) && dir.Size)
415 IMAGE_EXPORT_DIRECTORY exports;
416 WORD* ordinals = NULL;
417 void** functions = NULL;
418 DWORD* names = NULL;
419 unsigned int j;
421 if (DEBUG_READ_MEM_VERBOSE((char*)base + dir.VirtualAddress,
422 &exports, sizeof(exports)) &&
424 ((functions = DBG_alloc(sizeof(functions[0]) * exports.NumberOfFunctions))) &&
425 DEBUG_READ_MEM_VERBOSE((char*)base + exports.AddressOfFunctions,
426 functions, sizeof(functions[0]) * exports.NumberOfFunctions) &&
428 ((ordinals = DBG_alloc(sizeof(ordinals[0]) * exports.NumberOfNames))) &&
429 DEBUG_READ_MEM_VERBOSE((char*)base + (DWORD)exports.AddressOfNameOrdinals,
430 ordinals, sizeof(ordinals[0]) * exports.NumberOfNames) &&
432 ((names = DBG_alloc(sizeof(names[0]) * exports.NumberOfNames))) &&
433 DEBUG_READ_MEM_VERBOSE((char*)base + (DWORD)exports.AddressOfNames,
434 names, sizeof(names[0]) * exports.NumberOfNames))
437 for (i = 0; i < exports.NumberOfNames; i++)
439 if (!names[i] ||
440 !DEBUG_READ_MEM_VERBOSE((char*)base + names[i], bufstr, sizeof(bufstr)))
441 continue;
442 bufstr[sizeof(bufstr) - 1] = 0;
443 snprintf(buffer, sizeof(buffer), "%s.%s", prefix, bufstr);
444 value.addr.off = (unsigned long)base + (DWORD)functions[ordinals[i]];
445 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
448 for (i = 0; i < exports.NumberOfFunctions; i++)
450 if (!functions[i]) continue;
451 /* Check if we already added it with a name */
452 for (j = 0; j < exports.NumberOfNames; j++)
453 if ((ordinals[j] == i) && names[j]) break;
454 if (j < exports.NumberOfNames) continue;
455 snprintf(buffer, sizeof(buffer), "%s.%ld", prefix, i + exports.Base);
456 value.addr.off = (unsigned long)base + (DWORD)functions[i];
457 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
460 DBG_free(functions);
461 DBG_free(ordinals);
462 DBG_free(names);
464 /* no real debug info, only entry points */
465 return DIL_NOINFO;
468 /***********************************************************************
469 * DEBUG_LoadPEModule
471 void DEBUG_LoadPEModule(const char* name, HANDLE hFile, void* base)
473 IMAGE_NT_HEADERS pe_header;
474 DWORD nth_ofs;
475 DBG_MODULE* wmod = NULL;
476 int i;
477 IMAGE_SECTION_HEADER pe_seg;
478 DWORD pe_seg_ofs;
479 DWORD size = 0;
480 enum DbgInfoLoad dil = DIL_ERROR;
482 /* grab PE Header */
483 if (!DEBUG_READ_MEM_VERBOSE((char*)base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew),
484 &nth_ofs, sizeof(nth_ofs)) ||
485 !DEBUG_READ_MEM_VERBOSE((char*)base + nth_ofs, &pe_header, sizeof(pe_header)))
486 return;
488 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
489 pe_header.FileHeader.SizeOfOptionalHeader;
491 for (i = 0; i < pe_header.FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
493 if (!DEBUG_READ_MEM_VERBOSE((char*)base + pe_seg_ofs, &pe_seg, sizeof(pe_seg)))
494 continue;
495 if (size < pe_seg.VirtualAddress + pe_seg.SizeOfRawData)
496 size = pe_seg.VirtualAddress + pe_seg.SizeOfRawData;
499 /* FIXME: we make the assumption that hModule == base */
500 wmod = DEBUG_AddModule(name, DMT_PE, base, size, (HMODULE)base);
502 if (wmod)
504 dil = DEBUG_RegisterStabsDebugInfo(wmod, hFile, &pe_header, nth_ofs);
505 if (dil != DIL_LOADED)
506 dil = DEBUG_RegisterMSCDebugInfo(wmod, hFile, &pe_header, nth_ofs);
507 if (dil != DIL_LOADED)
508 dil = DEBUG_RegisterPEDebugInfo(wmod, hFile, &pe_header, nth_ofs);
509 wmod->dil = dil;
512 DEBUG_ReportDIL(dil, "32bit DLL", name, base);