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
24 #include "wine/port.h"
33 #define PATH_MAX MAX_PATH
35 #include "wine/exception.h"
36 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(winedbg
);
42 #define MAX_PATHNAME_LEN 1024
51 typedef struct tagMSC_DBG_INFO
54 PIMAGE_SECTION_HEADER sectp
;
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);
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
);
82 lstrcpyn(dbg_filename
, filename
, MAX_PATHNAME_LEN
);
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 */
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
)
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)
122 if ((ret
= MapViewOfFile(*hMap
, FILE_MAP_READ
, 0, g_offset
, g_size
)) != NULL
)
123 ret
+= offset
- g_offset
;
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 /*========================================================================
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
;
151 WINE_TRACE("Processing DBG file %s\n", filename
);
153 file_map
= DEBUG_MapDebugInfoFile(filename
, 0, 0, &hFile
, &hMap
);
156 WINE_ERR("-Unable to peruse .DBG file %s\n", filename
);
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
);
182 DEBUG_UnmapDebugInfoFile(hFile
, hMap
, file_map
);
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
;
198 MSC_DBG_INFO extra_info
= { 0, NULL
, 0, NULL
};
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
)
210 if (!DEBUG_READ_MEM_VERBOSE((char*)module
->load_addr
+
211 nth_ofs
+ OFFSET_OF(IMAGE_NT_HEADERS
, OptionalHeader
) +
212 nth
->FileHeader
.SizeOfOptionalHeader
,
214 extra_info
.nsect
* sizeof(IMAGE_SECTION_HEADER
)))
217 /* Read in debug directory */
219 nDbg
= dir
->Size
/ sizeof(IMAGE_DEBUG_DIRECTORY
);
223 dbg
= (PIMAGE_DEBUG_DIRECTORY
) DBG_alloc(nDbg
* sizeof(IMAGE_DEBUG_DIRECTORY
));
227 if (!DEBUG_READ_MEM_VERBOSE((char*)module
->load_addr
+ dir
->VirtualAddress
,
228 dbg
, nDbg
* sizeof(IMAGE_DEBUG_DIRECTORY
)))
233 file_map
= DEBUG_MapDebugInfoFile(NULL
, 0, 0, &hFile
, &hMap
);
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
);
254 dil
= DEBUG_ProcessDBGFile(module
, misc
->Data
, nth
->FileHeader
.TimeDateStamp
);
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
;
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)
275 mpd_dir
= mpd_nth
->OptionalHeader
.DataDirectory
+ IMAGE_DIRECTORY_ENTRY_DEBUG
;
277 if ((mpd_dir
->Size
/ sizeof(IMAGE_DEBUG_DIRECTORY
)) != nDbg
)
280 mpd_dbg
= (PIMAGE_DEBUG_DIRECTORY
)(file_map
+ mpd_dir
->VirtualAddress
);
282 dil
= DEBUG_ProcessDebugDirectory(module
, file_map
, mpd_dbg
, nDbg
);
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
);
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
)))
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
);
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
);
345 DEBUG_Printf("couldn't read data block\n");
351 DEBUG_Printf("couldn't alloc %d bytes\n", stabsize
+ stabstrsize
);
361 /***********************************************************************
362 * DEBUG_RegisterPEDebugInfo
364 enum DbgInfoLoad
DEBUG_RegisterPEDebugInfo(DBG_MODULE
* wmod
, HANDLE hFile
,
365 void* _nth
, unsigned long nth_ofs
)
371 IMAGE_SECTION_HEADER pe_seg
;
373 IMAGE_DATA_DIRECTORY dir
;
376 IMAGE_NT_HEADERS
* nth
= (PIMAGE_NT_HEADERS
)_nth
;
377 void* base
= wmod
->load_addr
;
380 value
.cookie
= DV_TARGET
;
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
)))
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 */
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
;
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
++)
440 !DEBUG_READ_MEM_VERBOSE((char*)base
+ names
[i
], bufstr
, sizeof(bufstr
)))
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
);
464 /* no real debug info, only entry points */
468 /***********************************************************************
471 void DEBUG_LoadPEModule(const char* name
, HANDLE hFile
, void* base
)
473 IMAGE_NT_HEADERS pe_header
;
475 DBG_MODULE
* wmod
= NULL
;
477 IMAGE_SECTION_HEADER pe_seg
;
480 enum DbgInfoLoad dil
= DIL_ERROR
;
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
)))
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
)))
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
);
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
);
512 DEBUG_ReportDIL(dil
, "32bit DLL", name
, base
);