Some dumb fixes.
[wine] / tools / winedump / debug.c
1 /*
2  * Made after:
3  *      CVDump - Parses through a Visual Studio .DBG file in CodeView 4 format
4  *      and dumps the info to STDOUT in a human-readable format
5  *
6  *      Copyright 2000 John R. Sheets
7  */
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <time.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/mman.h>
16 #include <fcntl.h>
17
18 #include "winnt.h"
19 #include "winedump.h"
20 #include "pe.h"
21 #include "cvinclude.h"
22
23 /*
24  * .DBG File Layout:
25  *
26  * IMAGE_SEPARATE_DEBUG_HEADER
27  * IMAGE_SECTION_HEADER[]
28  * IMAGE_DEBUG_DIRECTORY[]
29  * OMFSignature
30  * debug data (typical example)
31  *   - IMAGE_DEBUG_TYPE_MISC
32  *   - IMAGE_DEBUG_TYPE_FPO
33  *   - IMAGE_DEBUG_TYPE_CODEVIEW
34  * OMFDirHeader
35  * OMFDirEntry[]
36  */
37
38 /*
39  * Descriptions:
40  *
41  * (hdr)  IMAGE_SEPARATE_DEBUG_HEADER - .DBG-specific file header; holds info that 
42  *        applies to the file as a whole, including # of COFF sections, file offsets, etc.
43  * (hdr)  IMAGE_SECTION_HEADER - list of COFF sections copied verbatim from .EXE;
44  *        although this directory contains file offsets, these offsets are meaningless
45  *        in the context of the .DBG file, because only the section headers are copied
46  *        to the .DBG file...not the binary data it points to.
47  * (hdr)  IMAGE_DEBUG_DIRECTORY - list of different formats of debug info contained in file
48  *        (see IMAGE_DEBUG_TYPE_* descriptions below); tells where each section starts
49  * (hdr)  OMFSignature (CV) - Contains "NBxx" signature, plus file offset telling how far
50  *        into the IMAGE_DEBUG_TYPE_CODEVIEW section the OMFDirHeader and OMFDirEntry's sit
51  * (data) IMAGE_DEBUG_TYPE_MISC - usually holds name of original .EXE file
52  * (data) IMAGE_DEBUG_TYPE_FPO - Frame Pointer Optimization data; used for dealing with
53  *        optimized stack frames (optional)
54  * (data) IMAGE_DEBUG_TYPE_CODEVIEW - *** THE GOOD STUFF ***
55  *        This block of data contains all the symbol tables, line number info, etc.,
56  *        that the Visual C++ debugger needs.
57  * (hdr)  OMFDirHeader (CV) - 
58  * (hdr)  OMFDirEntry (CV) - list of subsections within CodeView debug data section
59  */
60
61 /*
62  * The .DBG file typically has three arrays of directory entries, which tell
63  * the OS or debugger where in the file to look for the actual data
64  *
65  * IMAGE_SECTION_HEADER - number of entries determined by:
66  *    (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
67  *
68  * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
69  *    (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
70  *
71  * OMFDirEntry - number of entries determined by:
72  *    (OMFDirHeader.cDir)
73  */
74
75 static  void*           cv_base /* = 0 */;
76
77 static int dump_cv_sst_module(OMFDirEntry* omfde)
78 {
79     OMFModule*  module;
80     OMFSegDesc* segDesc;
81     int         i;
82
83     module = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFModule));
84     if (!module) {printf("Can't get the OMF-Module, aborting\n"); return FALSE;}
85
86     printf("    olvNumber:          %u\n", module->ovlNumber);
87     printf("    iLib:               %u\n", module->iLib);
88     printf("    cSeg:               %u\n", module->cSeg);
89     printf("    Style:              %c%c\n", module->Style[0], module->Style[1]);
90     printf("    Name:               %.*s\n", 
91            *(BYTE*)((char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg),
92            (char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg + 1);
93
94     segDesc = PRD(Offset(module + 1), sizeof(OMFSegDesc) * module->cSeg);
95     if (!segDesc) {printf("Can't get the OMF-SegDesc, aborting\n"); return FALSE;}
96
97     for (i = 0; i < module->cSeg; i++)
98     {
99         printf ("      segment #%2d: offset = [0x%8lx], size = [0x%8lx]\n",
100                 segDesc->Seg, segDesc->Off, segDesc->cbSeg);
101         segDesc++;
102     }
103     return TRUE;
104 }
105
106 static int dump_cv_sst_global_pub(OMFDirEntry* omfde)
107 {
108     long        fileoffset;
109     OMFSymHash* header;
110     BYTE*       symbols;
111     BYTE*       curpos;
112     PUBSYM32*   sym;
113     unsigned    symlen;
114     int         recordlen;
115     char        nametmp[256];
116
117     fileoffset = Offset(cv_base) + omfde->lfo;
118     printf ("    GlobalPub section starts at file offset 0x%lx\n", fileoffset);
119     printf ("    Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash));
120
121     printf ("\n                           ----- Begin Symbol Table -----\n");
122     printf ("      (type)      (symbol name)                 (offset)      (len) (seg) (ind)\n");
123
124     header = PRD(fileoffset, sizeof(OMFSymHash));
125     if (!header) {printf("Can't get OMF-SymHash, aborting\n");return FALSE;}
126
127     symbols = PRD(fileoffset + sizeof(OMFSymHash), header->cbSymbol);
128     if (!symbols) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;}
129
130     /* We don't know how many symbols are in this block of memory...only what
131      * the total size of the block is.  Because the symbol's name is tacked
132      * on to the end of the PUBSYM32 struct, each symbol may take up a different
133      * # of bytes.  This makes it harder to parse through the symbol table,
134      * since we won't know the exact location of the following symbol until we've
135      * already parsed the current one.
136      */
137     for (curpos = symbols; curpos < symbols + header->cbSymbol; curpos += recordlen)
138     {
139         /* Point to the next PUBSYM32 in the table.
140          */
141         sym = (PUBSYM32*)curpos;
142
143         if (sym->reclen < sizeof(PUBSYM32)) break;
144
145         symlen = sym->reclen - sizeof(PUBSYM32) + 1;
146         if (symlen > sizeof(nametmp)) {printf("\nsqueeze%d\n", symlen);symlen = sizeof(nametmp) - 1;}
147
148         memcpy(nametmp, curpos + sizeof (PUBSYM32) + 1, symlen);
149         nametmp[symlen] = '\0';
150
151         printf ("      0x%04x  %-30.30s  [0x%8lx]  [0x%4x]  %d     %ld\n",
152                 sym->rectyp, nametmp, sym->off, sym->reclen, sym->seg, sym->typind);
153
154         /* The entire record is null-padded to the nearest 4-byte
155          * boundary, so we must do a little extra math to keep things straight.
156          */
157         recordlen = (sym->reclen + 3) & ~3;
158     }
159
160     return TRUE;
161 }
162
163 static int dump_cv_sst_global_sym(OMFDirEntry* omfde)
164 {
165     /*** NOT YET IMPLEMENTED ***/
166     return TRUE;
167 }
168
169 static int dump_cv_sst_static_sym(OMFDirEntry* omfde)
170 {
171     /*** NOT YET IMPLEMENTED ***/
172     return TRUE;
173 }
174
175 static int dump_cv_sst_libraries(OMFDirEntry* omfde)
176 {
177     /*** NOT YET IMPLEMENTED ***/
178     return TRUE;
179 }
180
181 static int dump_cv_sst_global_types(OMFDirEntry* omfde)
182 {
183     /*** NOT YET IMPLEMENTED ***/
184     return TRUE;
185 }
186
187 static int dump_cv_sst_seg_map(OMFDirEntry* omfde)
188 {
189     OMFSegMap*          segMap;
190     OMFSegMapDesc*      segMapDesc;
191     int         i;
192
193     segMap = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFSegMap));
194     if (!segMap) {printf("Can't get SegMap, aborting\n");return FALSE;}
195
196     printf("    cSeg:          %u\n", segMap->cSeg);
197     printf("    cSegLog:       %u\n", segMap->cSegLog);
198
199     segMapDesc = PRD(Offset(segMap + 1), segMap->cSeg * sizeof(OMFSegDesc));
200     if (!segMapDesc) {printf("Can't get SegDescr array, aborting\n");return FALSE;}
201     
202     for (i = 0; i < segMap->cSeg; i++)
203     {
204         printf("    SegDescr #%2d\n", i + 1);
205         printf("      flags:         %04X\n", segMapDesc[i].flags);
206         printf("      ovl:           %u\n", segMapDesc[i].ovl);
207         printf("      group:         %u\n", segMapDesc[i].group);
208         printf("      frame:         %u\n", segMapDesc[i].frame);
209         printf("      iSegName:      %u\n", segMapDesc[i].iSegName);
210         printf("      iClassName:    %u\n", segMapDesc[i].iClassName);
211         printf("      offset:        %lu\n", segMapDesc[i].offset);
212         printf("      cbSeg:         %lu\n", segMapDesc[i].cbSeg);
213     }
214
215     return TRUE;
216 }
217
218 static int dump_cv_sst_file_index(OMFDirEntry* omfde)
219 {
220     /*** NOT YET IMPLEMENTED ***/
221     return TRUE;
222 }
223
224 static int dump_cv_sst_src_module(OMFDirEntry* omfde)
225 {
226     int                 i, j;
227     BYTE*               rawdata;
228     unsigned long*      seg_info_dw;
229     unsigned short*     seg_info_w;
230     unsigned            ofs;
231     OMFSourceModule*    sourceModule;
232     OMFSourceFile*      sourceFile;
233     OMFSourceLine*      sourceLine;
234
235     rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb);
236     if (!rawdata) {printf("Can't get srcModule subsection details, aborting\n");return FALSE;}
237
238     /* FIXME: check ptr validity */
239     sourceModule = (void*)rawdata;
240     printf ("    Module table: Found %d file(s) and %d segment(s)\n", 
241             sourceModule->cFile, sourceModule->cSeg);
242     for (i = 0; i < sourceModule->cFile; i++)
243     {
244         printf ("      File #%2d begins at an offset of 0x%lx in this section\n",
245                 i + 1, sourceModule->baseSrcFile[i]);
246     }
247
248     /* FIXME: check ptr validity */
249     seg_info_dw = (void*)((char*)(sourceModule + 1) + 
250                           sizeof(unsigned long) * (sourceModule->cFile - 1));
251     seg_info_w = (unsigned short*)(&seg_info_dw[sourceModule->cSeg * 2]);
252     for (i = 0; i <  sourceModule->cSeg; i++)
253     {
254         printf ("      Segment #%2d start = 0x%lx, end = 0x%lx, seg index = %u\n",
255                 i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], 
256                 seg_info_w[i]);
257     }
258     ofs = sizeof(OMFSourceModule) + sizeof(unsigned long) * (sourceModule->cFile - 1) + 
259         sourceModule->cSeg * (2 * sizeof(unsigned long) + sizeof(unsigned short));
260     ofs = (ofs + 3) & ~3;
261
262     /* the OMFSourceFile is quite unpleasant to use:
263      * we have first:
264      *  unsigned short  number of segments
265      *  unsigned short  reservered
266      *  unsigned long   baseSrcLn[# segments]
267      *  unsigned long   offset[2 * #segments]
268      *                          odd indices are start offsets
269      *                          even indices are end offsets
270      *  unsigned char   string length for file name
271      *  char            file name (length is previous field)
272      */
273     /* FIXME: check ptr validity */
274     sourceFile = (void*)(rawdata + ofs);
275     seg_info_dw = (void*)((char*)sourceFile + 2 * sizeof(unsigned short) + 
276                           sourceFile->cSeg * sizeof(unsigned long));
277
278     ofs += 2 * sizeof(unsigned short) + 3 * sourceFile->cSeg * sizeof(unsigned long);
279
280     printf("    File table: %.*s\n", 
281            *(BYTE*)((char*)sourceModule + ofs), (char*)sourceModule + ofs + 1);
282
283     for (i = 0; i < sourceFile->cSeg; i++)
284     {
285         printf ("      Segment #%2d start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
286                 i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], sourceFile->baseSrcLn[i]);
287     }
288     /* add file name length */
289     ofs += *(BYTE*)((char*)sourceModule + ofs) + 1;
290     ofs = (ofs + 3) & ~3;
291
292     for (i = 0; i < sourceModule->cSeg; i++) 
293     {
294         sourceLine = (void*)(rawdata + ofs);
295         seg_info_dw = (void*)((char*)sourceLine + 2 * sizeof(unsigned short));
296         seg_info_w = (void*)(&seg_info_dw[sourceLine->cLnOff]);
297         
298         printf ("    Line table #%2d: Found %d line numbers for segment index %d\n",
299                 i, sourceLine->cLnOff, sourceLine->Seg);
300         
301         for (j = 0; j < sourceLine->cLnOff; j++)
302         {
303             printf ("      Pair #%2d: offset = [0x%8lx], linenumber = %d\n",
304                     j + 1, seg_info_dw[j], seg_info_w[j]);
305         }
306         ofs += 2 * sizeof(unsigned short) + 
307             sourceLine->cLnOff * (sizeof(unsigned long) + sizeof(unsigned short));
308         ofs = (ofs + 3) & ~3;
309     }
310
311     return TRUE;
312 }
313
314 static int dump_cv_sst_align_sym(OMFDirEntry* omfde)
315 {
316     /*** NOT YET IMPLEMENTED ***/
317
318     return TRUE;
319 }
320
321 static void dump_codeview_all_modules(OMFDirHeader *omfdh)
322 {
323     unsigned            i;
324     OMFDirEntry        *dirEntry;
325     const char*         str;
326
327     if (!omfdh || !omfdh->cDir) return;
328
329     dirEntry = PRD(Offset(omfdh + 1), omfdh->cDir * sizeof(OMFDirEntry));
330     if (!dirEntry) {printf("Can't read DirEntry array, aborting\n"); return;}
331
332     for (i = 0; i < omfdh->cDir; i++)
333     {
334         switch (dirEntry[i].SubSection)
335         {
336         case sstModule:         str = "sstModule";      break;
337         case sstAlignSym:       str = "sstAlignSym";    break;
338         case sstSrcModule:      str = "sstSrcModule";   break;
339         case sstLibraries:      str = "sstLibraries";   break;
340         case sstGlobalSym:      str = "sstGlobalSym";   break;
341         case sstGlobalPub:      str = "sstGlobalPub";   break;
342         case sstGlobalTypes:    str = "sstGlobalTypes"; break;
343         case sstSegMap:         str = "sstSegMap";      break;
344         case sstFileIndex:      str = "sstFileIndex";   break;
345         case sstStaticSym:      str = "sstStaticSym";   break;
346         default:                str = "<undefined>";    break;
347         }
348         printf("Module #%2d (%p)\n", i + 1, &dirEntry[i]);
349         printf("  SubSection:            %04X (%s)\n", dirEntry[i].SubSection, str);
350         printf("  iMod:                  %d\n", dirEntry[i].iMod);
351         printf("  lfo:                   %ld\n", dirEntry[i].lfo);
352         printf("  cb:                    %lu\n", dirEntry[i].cb);
353
354         switch (dirEntry[i].SubSection)
355         {
356         case sstModule:         dump_cv_sst_module(&dirEntry[i]);       break;
357         case sstAlignSym:       dump_cv_sst_align_sym(&dirEntry[i]);    break;
358         case sstSrcModule:      dump_cv_sst_src_module(&dirEntry[i]);   break;
359         case sstLibraries:      dump_cv_sst_libraries(&dirEntry[i]);    break;
360         case sstGlobalSym:      dump_cv_sst_global_sym(&dirEntry[i]);   break;
361         case sstGlobalPub:      dump_cv_sst_global_pub(&dirEntry[i]);   break;
362         case sstGlobalTypes:    dump_cv_sst_global_types(&dirEntry[i]); break;
363         case sstSegMap:         dump_cv_sst_seg_map(&dirEntry[i]);      break;
364         case sstFileIndex:      dump_cv_sst_file_index(&dirEntry[i]);   break;
365         case sstStaticSym:      dump_cv_sst_static_sym(&dirEntry[i]);   break;
366         default:                printf("unsupported type %x\n", dirEntry[i].SubSection); break;
367         }
368         printf("\n");
369     }
370
371     return;
372 }
373
374 static void dump_codeview_headers(unsigned long base, unsigned long len)
375 {
376     OMFDirHeader        *dirHeader;
377     OMFSignature        *signature;
378     OMFDirEntry         *dirEntry;
379     unsigned            i;
380     int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0;
381     int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0;
382     int segmapcount = 0, fileindexcount = 0, staticsymcount = 0;
383     
384     cv_base = PRD(base, len);
385     if (!cv_base) {printf("Can't get full debug content, aborting\n");return;}
386
387     signature = cv_base;
388
389     printf("    CodeView Data\n");
390
391     printf("      Signature:         %.4s\n", signature->Signature);
392     printf("      Filepos:           0x%08lX\n", signature->filepos);
393
394     if (memcmp(signature->Signature, "NB10", 4) == 0)
395     {
396         struct {DWORD TimeStamp; DWORD  Dunno; char Name[1];}* pdb_data;
397         pdb_data = (void*)(signature + 1);
398
399         printf("        TimeStamp:            %08lX (%s)\n", 
400                pdb_data->TimeStamp, get_time_str(pdb_data->TimeStamp));
401         printf("        Dunno:                %08lX\n", pdb_data->Dunno);
402         printf("        Filename:             %s\n", pdb_data->Name);
403         return;
404     } 
405
406     if (memcmp(signature->Signature, "NB09", 4) != 0 && memcmp(signature->Signature, "NB11", 4) != 0)
407     {
408         printf("Unsupported signature, aborting\n");
409         return;
410     }
411
412     dirHeader = PRD(Offset(cv_base) + signature->filepos, sizeof(OMFDirHeader));
413     if (!dirHeader) {printf("Can't get debug header, aborting\n"); return;}
414
415     printf("      Size of header:    0x%4X\n", dirHeader->cbDirHeader);
416     printf("      Size per entry:    0x%4X\n", dirHeader->cbDirEntry);
417     printf("      # of entries:      0x%8lX (%ld)\n", dirHeader->cDir, dirHeader->cDir);
418     printf("      Offset to NextDir: 0x%8lX\n", dirHeader->lfoNextDir);
419     printf("      Flags:             0x%8lX\n", dirHeader->flags);
420
421     if (!dirHeader->cDir) return;
422
423     dirEntry = PRD(Offset(dirHeader + 1), sizeof(OMFDirEntry) * dirHeader->cDir);
424     if (!dirEntry) {printf("Can't get DirEntry array, aborting\n");return;}
425
426     for (i = 0; i < dirHeader->cDir; i++)
427     {
428         switch (dirEntry[i].SubSection)
429         {
430         case sstModule:         modulecount++;          break;
431         case sstAlignSym:       alignsymcount++;        break;
432         case sstSrcModule:      srcmodulecount++;       break;
433         case sstLibraries:      librariescount++;       break;
434         case sstGlobalSym:      globalsymcount++;       break;
435         case sstGlobalPub:      globalpubcount++;       break;
436         case sstGlobalTypes:    globaltypescount++;     break;
437         case sstSegMap:         segmapcount++;          break;
438         case sstFileIndex:      fileindexcount++;       break;
439         case sstStaticSym:      staticsymcount++;       break;
440         }       
441     }
442
443     /* This one has to be > 0
444      */
445     printf ("\nFound: %d sstModule subsections\n", modulecount);
446
447     if (alignsymcount > 0)    printf ("       %d sstAlignSym subsections\n", alignsymcount);
448     if (srcmodulecount > 0)   printf ("       %d sstSrcModule subsections\n", srcmodulecount);
449     if (librariescount > 0)   printf ("       %d sstLibraries subsections\n", librariescount);
450     if (globalsymcount > 0)   printf ("       %d sstGlobalSym subsections\n", globalsymcount);
451     if (globalpubcount > 0)   printf ("       %d sstGlobalPub subsections\n", globalpubcount);
452     if (globaltypescount > 0) printf ("       %d sstGlobalTypes subsections\n", globaltypescount);
453     if (segmapcount > 0)      printf ("       %d sstSegMap subsections\n", segmapcount);
454     if (fileindexcount > 0)   printf ("       %d sstFileIndex subsections\n", fileindexcount);
455     if (staticsymcount > 0)   printf ("       %d sstStaticSym subsections\n", staticsymcount);
456
457     dump_codeview_all_modules(dirHeader);
458 }
459
460 void    dump_codeview(unsigned long base, unsigned long len)
461 {
462     dump_codeview_headers(base, len);
463 }
464