Enable querying of IID_FilterGraph interface from filtergraph manager
[wine] / programs / winedbg / pe.c
1 /*
2  * File pe.c - handle PE module information
3  *
4  * Copyright (C) 1996, Eric Youngdale.
5  * Copyright (C) 1999, 2000, Ulrich Weigand.
6  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
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"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
41
42 #define MAX_PATHNAME_LEN 1024
43
44 typedef struct
45 {
46     DWORD  from;
47     DWORD  to;
48
49 } OMAP_DATA;
50
51 typedef struct tagMSC_DBG_INFO
52 {
53     int                         nsect;
54     PIMAGE_SECTION_HEADER       sectp;
55     int                         nomap;
56     OMAP_DATA*                  omapp;
57
58 } MSC_DBG_INFO;
59
60 /***********************************************************************
61  *           DEBUG_LocateDebugInfoFile
62  *
63  * NOTE: dbg_filename must be at least MAX_PATHNAME_LEN bytes in size
64  */
65 static void DEBUG_LocateDebugInfoFile(const char* filename, char* dbg_filename)
66 {
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;
71
72     file = strrchr(filename, '\\');
73     if (file == NULL) file = filename; else file++;
74
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);
85 }
86
87 /***********************************************************************
88  *           DEBUG_MapDebugInfoFile
89  */
90 void*   DEBUG_MapDebugInfoFile(const char* name, DWORD offset, DWORD size,
91                                HANDLE* hFile, HANDLE* hMap)
92 {
93     DWORD       g_offset;       /* offset aligned on map granuality */
94     DWORD       g_size;         /* size to map, with offset aligned */
95     char*       ret;
96
97     *hMap = 0;
98
99     if (name != NULL)
100     {
101         char    filename[MAX_PATHNAME_LEN];
102
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;
107     }
108
109     if (!size)
110     {
111         DWORD file_size = GetFileSize(*hFile, NULL);
112         if (file_size == (DWORD)-1) return NULL;
113         size = file_size - offset;
114     }
115
116     g_offset = offset & ~0xFFFF; /* FIXME: is granularity portable ? */
117     g_size = offset + size - g_offset;
118
119     if ((*hMap = CreateFileMapping(*hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == 0)
120         return NULL;
121
122     if ((ret = MapViewOfFile(*hMap, FILE_MAP_READ, 0, g_offset, g_size)) != NULL)
123         ret += offset - g_offset;
124
125     return ret;
126 }
127
128 /***********************************************************************
129  *           DEBUG_UnmapDebugInfoFile
130  */
131 void    DEBUG_UnmapDebugInfoFile(HANDLE hFile, HANDLE hMap, const void* addr)
132 {
133     if (addr) UnmapViewOfFile((void*)addr);
134     if (hMap) CloseHandle(hMap);
135     if (hFile!=INVALID_HANDLE_VALUE) CloseHandle(hFile);
136 }
137
138 /*========================================================================
139  * Process DBG file.
140  */
141 static enum DbgInfoLoad DEBUG_ProcessDBGFile(DBG_MODULE* module,
142                                              const char* filename, DWORD timestamp)
143 {
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;
150
151     WINE_TRACE("Processing DBG file %s\n", filename);
152
153     file_map = DEBUG_MapDebugInfoFile(filename, 0, 0, &hFile, &hMap);
154     if (!file_map)
155     {
156         WINE_ERR("-Unable to peruse .DBG file %s\n", filename);
157         goto leave;
158     }
159
160     hdr = (PIMAGE_SEPARATE_DEBUG_HEADER) file_map;
161
162     if (hdr->TimeDateStamp != timestamp)
163     {
164         WINE_ERR("Warning - %s has incorrect internal timestamp\n", filename);
165         /*
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.
169          */
170     }
171
172
173     dbg = (PIMAGE_DEBUG_DIRECTORY) 
174         (file_map + sizeof(*hdr) + hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
175          + hdr->ExportedNamesSize);
176
177     nDbg = hdr->DebugDirectorySize / sizeof(*dbg);
178
179     dil = DEBUG_ProcessDebugDirectory(module, file_map, dbg, nDbg);
180
181 leave:
182     DEBUG_UnmapDebugInfoFile(hFile, hMap, file_map);
183     return dil;
184 }
185
186
187 /*========================================================================
188  * Process MSC debug information in PE file.
189  */
190 enum DbgInfoLoad DEBUG_RegisterMSCDebugInfo(DBG_MODULE* module, HANDLE hFile,
191                                             void* _nth, unsigned long nth_ofs)
192 {
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;
201
202     /* Read in section data */
203
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;
209
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;
216
217     /* Read in debug directory */
218
219     nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
220     if (!nDbg)
221         goto leave;
222
223     dbg = (PIMAGE_DEBUG_DIRECTORY) DBG_alloc(nDbg * sizeof(IMAGE_DEBUG_DIRECTORY));
224     if (!dbg)
225         goto leave;
226
227     if (!DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + dir->VirtualAddress,
228                                 dbg, nDbg * sizeof(IMAGE_DEBUG_DIRECTORY)))
229         goto leave;
230
231
232     /* Map in PE file */
233     file_map = DEBUG_MapDebugInfoFile(NULL, 0, 0, &hFile, &hMap);
234     if (!file_map)
235         goto leave;
236
237
238     /* Parse debug directory */
239
240     if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
241     {
242         /* Debug info is stripped to .DBG file */
243
244         PIMAGE_DEBUG_MISC misc = (PIMAGE_DEBUG_MISC)(file_map + dbg->PointerToRawData);
245
246         if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC
247                        || misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
248         {
249             WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
250                      module->module_name);
251             goto leave;
252         }
253
254         dil = DEBUG_ProcessDBGFile(module, misc->Data, nth->FileHeader.TimeDateStamp);
255     }
256     else
257     {
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
265          */
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;
269
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;
276
277         if ((mpd_dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY)) != nDbg)
278             goto leave;
279
280         mpd_dbg = (PIMAGE_DEBUG_DIRECTORY)(file_map + mpd_dir->VirtualAddress);
281
282         dil = DEBUG_ProcessDebugDirectory(module, file_map, mpd_dbg, nDbg);
283     }
284
285
286 leave:
287     module->msc_dbg_info = NULL;
288
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;
293 }
294
295
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
299  */
300 enum DbgInfoLoad DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module, HANDLE hFile,
301                                               void* _nth, unsigned long nth_ofs)
302 {
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;
309
310     pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
311         nth->FileHeader.SizeOfOptionalHeader;
312
313     for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
314     {
315         if (!DEBUG_READ_MEM_VERBOSE((void*)((char*)module->load_addr + pe_seg_ofs),
316                                     &pe_seg, sizeof(pe_seg)))
317             continue;
318
319         if (!strcasecmp(pe_seg.Name, ".stab"))
320         {
321             stabs = pe_seg.VirtualAddress;
322             stabsize = pe_seg.SizeOfRawData;
323         }
324         else if (!strncasecmp(pe_seg.Name, ".stabstr", 8))
325         {
326             stabstr = pe_seg.VirtualAddress;
327             stabstrsize = pe_seg.SizeOfRawData;
328         }
329     }
330
331     if (stabstrsize && stabsize)
332     {
333         char*   s1 = DBG_alloc(stabsize+stabstrsize);
334
335         if (s1)
336         {
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))
340             {
341                 dil = DEBUG_ParseStabs(s1, 0, 0, stabsize, stabsize, stabstrsize);
342             }
343             else
344             {
345                 DEBUG_Printf("couldn't read data block\n");
346             }
347             DBG_free(s1);
348         }
349         else 
350         {
351             DEBUG_Printf("couldn't alloc %d bytes\n", stabsize + stabstrsize);
352         }
353     }
354     else
355     {
356         dil = DIL_NOINFO;
357     }
358     return dil;
359 }
360
361 /***********************************************************************
362  *                      DEBUG_RegisterPEDebugInfo
363  */
364 enum DbgInfoLoad        DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
365                                                   void* _nth, unsigned long nth_ofs)
366 {
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;
378
379     value.type = NULL;
380     value.cookie = DV_TARGET;
381     value.addr.seg = 0;
382     value.addr.off = 0;
383
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;
388
389     DEBUG_AddSymbol(prefix, &value, NULL, SYM_WIN32 | SYM_FUNC);
390
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);
395
396     /* Add start of sections */
397     pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
398         nth->FileHeader.SizeOfOptionalHeader;
399
400     for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
401     {
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);
407     }
408
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)
414     {
415         IMAGE_EXPORT_DIRECTORY  exports;
416         WORD*                   ordinals = NULL;
417         void**                  functions = NULL;
418         DWORD*                  names = NULL;
419         unsigned int            j;
420
421         if (DEBUG_READ_MEM_VERBOSE((char*)base + dir.VirtualAddress,
422                                    &exports, sizeof(exports)) &&
423
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) &&
427
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) &&
431
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))
435         {
436
437             for (i = 0; i < exports.NumberOfNames; i++)
438             {
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);
446             }
447
448             for (i = 0; i < exports.NumberOfFunctions; i++)
449             {
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);
458             }
459         }
460         DBG_free(functions);
461         DBG_free(ordinals);
462         DBG_free(names);
463     }
464     /* no real debug info, only entry points */
465     return DIL_NOINFO;
466 }
467
468 /***********************************************************************
469  *                      DEBUG_LoadPEModule
470  */
471 void    DEBUG_LoadPEModule(const char* name, HANDLE hFile, void* base)
472 {
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;
481
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;
487
488      pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
489          pe_header.FileHeader.SizeOfOptionalHeader;
490
491      for (i = 0; i < pe_header.FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg))
492      {
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;
497      }
498
499      /* FIXME: we make the assumption that hModule == base */
500      wmod = DEBUG_AddModule(name, DMT_PE, base, size, (HMODULE)base);
501
502      if (wmod)
503      {
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;
510      }
511
512      DEBUG_ReportDIL(dil, "32bit DLL", name, base);
513 }