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
6 * Copyright 2000 John R. Sheets
13 #include <sys/types.h>
21 #include "cvinclude.h"
26 * IMAGE_SEPARATE_DEBUG_HEADER
27 * IMAGE_SECTION_HEADER[]
28 * IMAGE_DEBUG_DIRECTORY[]
30 * debug data (typical example)
31 * - IMAGE_DEBUG_TYPE_MISC
32 * - IMAGE_DEBUG_TYPE_FPO
33 * - IMAGE_DEBUG_TYPE_CODEVIEW
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
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
65 * IMAGE_SECTION_HEADER - number of entries determined by:
66 * (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
68 * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
69 * (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
71 * OMFDirEntry - number of entries determined by:
75 static void* cv_base /* = 0 */;
77 static int dump_cv_sst_module(OMFDirEntry* omfde)
83 module = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFModule));
84 if (!module) {printf("Can't get the OMF-Module, aborting\n"); return FALSE;}
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);
94 segDesc = PRD(Offset(module + 1), sizeof(OMFSegDesc) * module->cSeg);
95 if (!segDesc) {printf("Can't get the OMF-SegDesc, aborting\n"); return FALSE;}
97 for (i = 0; i < module->cSeg; i++)
99 printf (" segment #%2d: offset = [0x%8lx], size = [0x%8lx]\n",
100 segDesc->Seg, segDesc->Off, segDesc->cbSeg);
106 static int dump_cv_sst_global_pub(OMFDirEntry* omfde)
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));
121 printf ("\n ----- Begin Symbol Table -----\n");
122 printf (" (type) (symbol name) (offset) (len) (seg) (ind)\n");
124 header = PRD(fileoffset, sizeof(OMFSymHash));
125 if (!header) {printf("Can't get OMF-SymHash, aborting\n");return FALSE;}
127 symbols = PRD(fileoffset + sizeof(OMFSymHash), header->cbSymbol);
128 if (!symbols) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;}
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.
137 for (curpos = symbols; curpos < symbols + header->cbSymbol; curpos += recordlen)
139 /* Point to the next PUBSYM32 in the table.
141 sym = (PUBSYM32*)curpos;
143 if (sym->reclen < sizeof(PUBSYM32)) break;
145 symlen = sym->reclen - sizeof(PUBSYM32) + 1;
146 if (symlen > sizeof(nametmp)) {printf("\nsqueeze%d\n", symlen);symlen = sizeof(nametmp) - 1;}
148 memcpy(nametmp, curpos + sizeof (PUBSYM32) + 1, symlen);
149 nametmp[symlen] = '\0';
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);
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.
157 recordlen = (sym->reclen + 3) & ~3;
163 static int dump_cv_sst_global_sym(OMFDirEntry* omfde)
165 /*** NOT YET IMPLEMENTED ***/
169 static int dump_cv_sst_static_sym(OMFDirEntry* omfde)
171 /*** NOT YET IMPLEMENTED ***/
175 static int dump_cv_sst_libraries(OMFDirEntry* omfde)
177 /*** NOT YET IMPLEMENTED ***/
181 static int dump_cv_sst_global_types(OMFDirEntry* omfde)
183 /*** NOT YET IMPLEMENTED ***/
187 static int dump_cv_sst_seg_map(OMFDirEntry* omfde)
190 OMFSegMapDesc* segMapDesc;
193 segMap = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFSegMap));
194 if (!segMap) {printf("Can't get SegMap, aborting\n");return FALSE;}
196 printf(" cSeg: %u\n", segMap->cSeg);
197 printf(" cSegLog: %u\n", segMap->cSegLog);
199 segMapDesc = PRD(Offset(segMap + 1), segMap->cSeg * sizeof(OMFSegDesc));
200 if (!segMapDesc) {printf("Can't get SegDescr array, aborting\n");return FALSE;}
202 for (i = 0; i < segMap->cSeg; i++)
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);
218 static int dump_cv_sst_file_index(OMFDirEntry* omfde)
220 /*** NOT YET IMPLEMENTED ***/
224 static int dump_cv_sst_src_module(OMFDirEntry* omfde)
228 unsigned long* seg_info_dw;
229 unsigned short* seg_info_w;
231 OMFSourceModule* sourceModule;
232 OMFSourceFile* sourceFile;
233 OMFSourceLine* sourceLine;
235 rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb);
236 if (!rawdata) {printf("Can't get srcModule subsection details, aborting\n");return FALSE;}
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++)
244 printf (" File #%2d begins at an offset of 0x%lx in this section\n",
245 i + 1, sourceModule->baseSrcFile[i]);
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++)
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],
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;
262 /* the OMFSourceFile is quite unpleasant to use:
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)
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));
278 ofs += 2 * sizeof(unsigned short) + 3 * sourceFile->cSeg * sizeof(unsigned long);
280 printf(" File table: %.*s\n",
281 *(BYTE*)((char*)sourceModule + ofs), (char*)sourceModule + ofs + 1);
283 for (i = 0; i < sourceFile->cSeg; i++)
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]);
288 /* add file name length */
289 ofs += *(BYTE*)((char*)sourceModule + ofs) + 1;
290 ofs = (ofs + 3) & ~3;
292 for (i = 0; i < sourceModule->cSeg; i++)
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]);
298 printf (" Line table #%2d: Found %d line numbers for segment index %d\n",
299 i, sourceLine->cLnOff, sourceLine->Seg);
301 for (j = 0; j < sourceLine->cLnOff; j++)
303 printf (" Pair #%2d: offset = [0x%8lx], linenumber = %d\n",
304 j + 1, seg_info_dw[j], seg_info_w[j]);
306 ofs += 2 * sizeof(unsigned short) +
307 sourceLine->cLnOff * (sizeof(unsigned long) + sizeof(unsigned short));
308 ofs = (ofs + 3) & ~3;
314 static int dump_cv_sst_align_sym(OMFDirEntry* omfde)
316 /*** NOT YET IMPLEMENTED ***/
321 static void dump_codeview_all_modules(OMFDirHeader *omfdh)
324 OMFDirEntry *dirEntry;
327 if (!omfdh || !omfdh->cDir) return;
329 dirEntry = PRD(Offset(omfdh + 1), omfdh->cDir * sizeof(OMFDirEntry));
330 if (!dirEntry) {printf("Can't read DirEntry array, aborting\n"); return;}
332 for (i = 0; i < omfdh->cDir; i++)
334 switch (dirEntry[i].SubSection)
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;
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);
354 switch (dirEntry[i].SubSection)
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;
374 static void dump_codeview_headers(unsigned long base, unsigned long len)
376 OMFDirHeader *dirHeader;
377 OMFSignature *signature;
378 OMFDirEntry *dirEntry;
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;
384 cv_base = PRD(base, len);
385 if (!cv_base) {printf("Can't get full debug content, aborting\n");return;}
389 printf(" CodeView Data\n");
391 printf(" Signature: %.4s\n", signature->Signature);
392 printf(" Filepos: 0x%08lX\n", signature->filepos);
394 if (memcmp(signature->Signature, "NB10", 4) == 0)
396 struct {DWORD TimeStamp; DWORD Dunno; char Name[1];}* pdb_data;
397 pdb_data = (void*)(signature + 1);
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);
406 if (memcmp(signature->Signature, "NB09", 4) != 0 && memcmp(signature->Signature, "NB11", 4) != 0)
408 printf("Unsupported signature, aborting\n");
412 dirHeader = PRD(Offset(cv_base) + signature->filepos, sizeof(OMFDirHeader));
413 if (!dirHeader) {printf("Can't get debug header, aborting\n"); return;}
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);
421 if (!dirHeader->cDir) return;
423 dirEntry = PRD(Offset(dirHeader + 1), sizeof(OMFDirEntry) * dirHeader->cDir);
424 if (!dirEntry) {printf("Can't get DirEntry array, aborting\n");return;}
426 for (i = 0; i < dirHeader->cDir; i++)
428 switch (dirEntry[i].SubSection)
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;
443 /* This one has to be > 0
445 printf ("\nFound: %d sstModule subsections\n", modulecount);
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);
457 dump_codeview_all_modules(dirHeader);
460 void dump_codeview(unsigned long base, unsigned long len)
462 dump_codeview_headers(base, len);