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
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
36 #ifdef HAVE_SYS_STAT_H
37 # include <sys/stat.h>
39 #ifdef HAVE_SYS_MMAN_H
47 #include "wine/mscvpdb.h"
52 * IMAGE_SEPARATE_DEBUG_HEADER
53 * IMAGE_SECTION_HEADER[]
54 * IMAGE_DEBUG_DIRECTORY[]
56 * debug data (typical example)
57 * - IMAGE_DEBUG_TYPE_MISC
58 * - IMAGE_DEBUG_TYPE_FPO
59 * - IMAGE_DEBUG_TYPE_CODEVIEW
67 * (hdr) IMAGE_SEPARATE_DEBUG_HEADER - .DBG-specific file header; holds info that
68 * applies to the file as a whole, including # of COFF sections, file offsets, etc.
69 * (hdr) IMAGE_SECTION_HEADER - list of COFF sections copied verbatim from .EXE;
70 * although this directory contains file offsets, these offsets are meaningless
71 * in the context of the .DBG file, because only the section headers are copied
72 * to the .DBG file...not the binary data it points to.
73 * (hdr) IMAGE_DEBUG_DIRECTORY - list of different formats of debug info contained in file
74 * (see IMAGE_DEBUG_TYPE_* descriptions below); tells where each section starts
75 * (hdr) OMFSignature (CV) - Contains "NBxx" signature, plus file offset telling how far
76 * into the IMAGE_DEBUG_TYPE_CODEVIEW section the OMFDirHeader and OMFDirEntry's sit
77 * (data) IMAGE_DEBUG_TYPE_MISC - usually holds name of original .EXE file
78 * (data) IMAGE_DEBUG_TYPE_FPO - Frame Pointer Optimization data; used for dealing with
79 * optimized stack frames (optional)
80 * (data) IMAGE_DEBUG_TYPE_CODEVIEW - *** THE GOOD STUFF ***
81 * This block of data contains all the symbol tables, line number info, etc.,
82 * that the Visual C++ debugger needs.
83 * (hdr) OMFDirHeader (CV) -
84 * (hdr) OMFDirEntry (CV) - list of subsections within CodeView debug data section
88 * The .DBG file typically has three arrays of directory entries, which tell
89 * the OS or debugger where in the file to look for the actual data
91 * IMAGE_SECTION_HEADER - number of entries determined by:
92 * (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
94 * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
95 * (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
97 * OMFDirEntry - number of entries determined by:
101 extern const IMAGE_NT_HEADERS
* PE_nt_headers
;
102 static const void* cv_base
/* = 0 */;
104 static int dump_cv_sst_module(const OMFDirEntry
* omfde
)
106 const OMFModule
* module
;
107 const OMFSegDesc
* segDesc
;
110 module
= PRD(Offset(cv_base
) + omfde
->lfo
, sizeof(OMFModule
));
111 if (!module
) {printf("Can't get the OMF-Module, aborting\n"); return FALSE
;}
113 printf(" olvNumber: %u\n", module
->ovlNumber
);
114 printf(" iLib: %u\n", module
->iLib
);
115 printf(" cSeg: %u\n", module
->cSeg
);
116 printf(" Style: %c%c\n", module
->Style
[0], module
->Style
[1]);
117 printf(" Name: %.*s\n",
118 *(const BYTE
*)((const char*)(module
+ 1) + sizeof(OMFSegDesc
) * module
->cSeg
),
119 (const char*)(module
+ 1) + sizeof(OMFSegDesc
) * module
->cSeg
+ 1);
121 segDesc
= PRD(Offset(module
+ 1), sizeof(OMFSegDesc
) * module
->cSeg
);
122 if (!segDesc
) {printf("Can't get the OMF-SegDesc, aborting\n"); return FALSE
;}
124 for (i
= 0; i
< module
->cSeg
; i
++)
126 printf (" segment #%2d: offset = [0x%8x], size = [0x%8x]\n",
127 segDesc
->Seg
, segDesc
->Off
, segDesc
->cbSeg
);
133 static int dump_cv_sst_global_pub(const OMFDirEntry
* omfde
)
136 const OMFSymHash
* header
;
139 fileoffset
= Offset(cv_base
) + omfde
->lfo
;
140 printf (" GlobalPub section starts at file offset 0x%lx\n", fileoffset
);
141 printf (" Symbol table starts at 0x%lx\n", fileoffset
+ sizeof (OMFSymHash
));
143 printf ("\n ----- Begin Symbol Table -----\n");
145 header
= PRD(fileoffset
, sizeof(OMFSymHash
));
146 if (!header
) {printf("Can't get OMF-SymHash, aborting\n");return FALSE
;}
148 symbols
= PRD(fileoffset
+ sizeof(OMFSymHash
), header
->cbSymbol
);
149 if (!symbols
) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE
;}
151 codeview_dump_symbols(symbols
, header
->cbSymbol
);
156 static int dump_cv_sst_global_sym(const OMFDirEntry
* omfde
)
158 /*** NOT YET IMPLEMENTED ***/
162 static int dump_cv_sst_static_sym(const OMFDirEntry
* omfde
)
164 /*** NOT YET IMPLEMENTED ***/
168 static int dump_cv_sst_libraries(const OMFDirEntry
* omfde
)
170 /*** NOT YET IMPLEMENTED ***/
174 static int dump_cv_sst_global_types(const OMFDirEntry
* omfde
)
177 const OMFGlobalTypes
*types
;
181 fileoffset
= Offset(cv_base
) + omfde
->lfo
;
182 printf (" GlobalTypes section starts at file offset 0x%lx\n", fileoffset
);
184 printf ("\n ----- Begin Global Types Table -----\n");
186 types
= PRD(fileoffset
, sizeof(OMFGlobalTypes
));
187 if (!types
) {printf("Can't get OMF-GlobalTypes, aborting\n");return FALSE
;}
189 sz
= omfde
->cb
- sizeof(OMFGlobalTypes
) - sizeof(DWORD
) * types
->cTypes
;
190 data
= PRD(fileoffset
+ sizeof(OMFGlobalTypes
) + sizeof(DWORD
) * types
->cTypes
, sz
);
191 if (!data
) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE
;}
193 codeview_dump_types(data
, sz
);
198 static int dump_cv_sst_seg_map(const OMFDirEntry
* omfde
)
200 const OMFSegMap
* segMap
;
201 const OMFSegMapDesc
* segMapDesc
;
204 segMap
= PRD(Offset(cv_base
) + omfde
->lfo
, sizeof(OMFSegMap
));
205 if (!segMap
) {printf("Can't get SegMap, aborting\n");return FALSE
;}
207 printf(" cSeg: %u\n", segMap
->cSeg
);
208 printf(" cSegLog: %u\n", segMap
->cSegLog
);
210 segMapDesc
= PRD(Offset(segMap
+ 1), segMap
->cSeg
* sizeof(OMFSegDesc
));
211 if (!segMapDesc
) {printf("Can't get SegDescr array, aborting\n");return FALSE
;}
213 for (i
= 0; i
< segMap
->cSeg
; i
++)
215 printf(" SegDescr #%2d\n", i
+ 1);
216 printf(" flags: %04X\n", segMapDesc
[i
].flags
);
217 printf(" ovl: %u\n", segMapDesc
[i
].ovl
);
218 printf(" group: %u\n", segMapDesc
[i
].group
);
219 printf(" frame: %u\n", segMapDesc
[i
].frame
);
220 printf(" iSegName: %u\n", segMapDesc
[i
].iSegName
);
221 printf(" iClassName: %u\n", segMapDesc
[i
].iClassName
);
222 printf(" offset: %lu\n", segMapDesc
[i
].offset
);
223 printf(" cbSeg: %lu\n", segMapDesc
[i
].cbSeg
);
229 static int dump_cv_sst_file_index(const OMFDirEntry
* omfde
)
231 /*** NOT YET IMPLEMENTED ***/
235 static int dump_cv_sst_src_module(const OMFDirEntry
* omfde
)
239 const unsigned long* seg_info_dw
;
240 const unsigned short* seg_info_w
;
242 const OMFSourceModule
* sourceModule
;
243 const OMFSourceFile
* sourceFile
;
244 const OMFSourceLine
* sourceLine
;
246 rawdata
= PRD(Offset(cv_base
) + omfde
->lfo
, omfde
->cb
);
247 if (!rawdata
) {printf("Can't get srcModule subsection details, aborting\n");return FALSE
;}
249 /* FIXME: check ptr validity */
250 sourceModule
= (const void*)rawdata
;
251 printf (" Module table: Found %d file(s) and %d segment(s)\n",
252 sourceModule
->cFile
, sourceModule
->cSeg
);
253 for (i
= 0; i
< sourceModule
->cFile
; i
++)
255 printf (" File #%2d begins at an offset of 0x%lx in this section\n",
256 i
+ 1, sourceModule
->baseSrcFile
[i
]);
259 /* FIXME: check ptr validity */
260 seg_info_dw
= (const void*)((const char*)(sourceModule
+ 1) +
261 sizeof(unsigned long) * (sourceModule
->cFile
- 1));
262 seg_info_w
= (const unsigned short*)(&seg_info_dw
[sourceModule
->cSeg
* 2]);
263 for (i
= 0; i
< sourceModule
->cSeg
; i
++)
265 printf (" Segment #%2d start = 0x%lx, end = 0x%lx, seg index = %u\n",
266 i
+ 1, seg_info_dw
[i
* 2], seg_info_dw
[(i
* 2) + 1],
269 ofs
= sizeof(OMFSourceModule
) + sizeof(unsigned long) * (sourceModule
->cFile
- 1) +
270 sourceModule
->cSeg
* (2 * sizeof(unsigned long) + sizeof(unsigned short));
271 ofs
= (ofs
+ 3) & ~3;
273 /* the OMFSourceFile is quite unpleasant to use:
275 * unsigned short number of segments
276 * unsigned short reservered
277 * unsigned long baseSrcLn[# segments]
278 * unsigned long offset[2 * #segments]
279 * odd indices are start offsets
280 * even indices are end offsets
281 * unsigned char string length for file name
282 * char file name (length is previous field)
284 /* FIXME: check ptr validity */
285 sourceFile
= (const void*)(rawdata
+ ofs
);
286 seg_info_dw
= (const void*)((const char*)sourceFile
+ 2 * sizeof(unsigned short) +
287 sourceFile
->cSeg
* sizeof(unsigned long));
289 ofs
+= 2 * sizeof(unsigned short) + 3 * sourceFile
->cSeg
* sizeof(unsigned long);
291 printf(" File table: %.*s\n",
292 *(const BYTE
*)((const char*)sourceModule
+ ofs
), (const char*)sourceModule
+ ofs
+ 1);
294 for (i
= 0; i
< sourceFile
->cSeg
; i
++)
296 printf (" Segment #%2d start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
297 i
+ 1, seg_info_dw
[i
* 2], seg_info_dw
[(i
* 2) + 1], sourceFile
->baseSrcLn
[i
]);
299 /* add file name length */
300 ofs
+= *(const BYTE
*)((const char*)sourceModule
+ ofs
) + 1;
301 ofs
= (ofs
+ 3) & ~3;
303 for (i
= 0; i
< sourceModule
->cSeg
; i
++)
305 sourceLine
= (const void*)(rawdata
+ ofs
);
306 seg_info_dw
= (const void*)((const char*)sourceLine
+ 2 * sizeof(unsigned short));
307 seg_info_w
= (const void*)(&seg_info_dw
[sourceLine
->cLnOff
]);
309 printf (" Line table #%2d: Found %d line numbers for segment index %d\n",
310 i
, sourceLine
->cLnOff
, sourceLine
->Seg
);
312 for (j
= 0; j
< sourceLine
->cLnOff
; j
++)
314 printf (" Pair #%2d: offset = [0x%8lx], linenumber = %d\n",
315 j
+ 1, seg_info_dw
[j
], seg_info_w
[j
]);
317 ofs
+= 2 * sizeof(unsigned short) +
318 sourceLine
->cLnOff
* (sizeof(unsigned long) + sizeof(unsigned short));
319 ofs
= (ofs
+ 3) & ~3;
325 static int dump_cv_sst_align_sym(const OMFDirEntry
* omfde
)
327 const char* rawdata
= PRD(Offset(cv_base
) + omfde
->lfo
, omfde
->cb
);
329 if (!rawdata
) {printf("Can't get srcAlignSym subsection details, aborting\n");return FALSE
;}
330 if (omfde
->cb
< sizeof(DWORD
)) return TRUE
;
331 codeview_dump_symbols(rawdata
+ sizeof(DWORD
), omfde
->cb
- sizeof(DWORD
));
336 static void dump_codeview_all_modules(const OMFDirHeader
*omfdh
)
339 const OMFDirEntry
* dirEntry
;
342 if (!omfdh
|| !omfdh
->cDir
) return;
344 dirEntry
= PRD(Offset(omfdh
+ 1), omfdh
->cDir
* sizeof(OMFDirEntry
));
345 if (!dirEntry
) {printf("Can't read DirEntry array, aborting\n"); return;}
347 for (i
= 0; i
< omfdh
->cDir
; i
++)
349 switch (dirEntry
[i
].SubSection
)
351 case sstModule
: str
= "sstModule"; break;
352 case sstAlignSym
: str
= "sstAlignSym"; break;
353 case sstSrcModule
: str
= "sstSrcModule"; break;
354 case sstLibraries
: str
= "sstLibraries"; break;
355 case sstGlobalSym
: str
= "sstGlobalSym"; break;
356 case sstGlobalPub
: str
= "sstGlobalPub"; break;
357 case sstGlobalTypes
: str
= "sstGlobalTypes"; break;
358 case sstSegMap
: str
= "sstSegMap"; break;
359 case sstFileIndex
: str
= "sstFileIndex"; break;
360 case sstStaticSym
: str
= "sstStaticSym"; break;
361 default: str
= "<undefined>"; break;
363 printf("Module #%2d (%p)\n", i
+ 1, &dirEntry
[i
]);
364 printf(" SubSection: %04X (%s)\n", dirEntry
[i
].SubSection
, str
);
365 printf(" iMod: %d\n", dirEntry
[i
].iMod
);
366 printf(" lfo: %d\n", dirEntry
[i
].lfo
);
367 printf(" cb: %u\n", dirEntry
[i
].cb
);
369 switch (dirEntry
[i
].SubSection
)
371 case sstModule
: dump_cv_sst_module(&dirEntry
[i
]); break;
372 case sstAlignSym
: dump_cv_sst_align_sym(&dirEntry
[i
]); break;
373 case sstSrcModule
: dump_cv_sst_src_module(&dirEntry
[i
]); break;
374 case sstLibraries
: dump_cv_sst_libraries(&dirEntry
[i
]); break;
375 case sstGlobalSym
: dump_cv_sst_global_sym(&dirEntry
[i
]); break;
376 case sstGlobalPub
: dump_cv_sst_global_pub(&dirEntry
[i
]); break;
377 case sstGlobalTypes
: dump_cv_sst_global_types(&dirEntry
[i
]); break;
378 case sstSegMap
: dump_cv_sst_seg_map(&dirEntry
[i
]); break;
379 case sstFileIndex
: dump_cv_sst_file_index(&dirEntry
[i
]); break;
380 case sstStaticSym
: dump_cv_sst_static_sym(&dirEntry
[i
]); break;
381 default: printf("unsupported type %x\n", dirEntry
[i
].SubSection
); break;
389 static void dump_codeview_headers(unsigned long base
, unsigned long len
)
391 const OMFDirHeader
* dirHeader
;
392 const char* signature
;
393 const OMFDirEntry
* dirEntry
;
394 const OMFSignature
* sig
;
396 int modulecount
= 0, alignsymcount
= 0, srcmodulecount
= 0, librariescount
= 0;
397 int globalsymcount
= 0, globalpubcount
= 0, globaltypescount
= 0;
398 int segmapcount
= 0, fileindexcount
= 0, staticsymcount
= 0;
400 cv_base
= PRD(base
, len
);
401 if (!cv_base
) {printf("Can't get full debug content, aborting\n");return;}
405 printf(" CodeView Data\n");
406 printf(" Signature: %.4s\n", signature
);
408 if (memcmp(signature
, "NB10", 4) == 0)
410 const CODEVIEW_PDB_DATA
* pdb_data
;
411 pdb_data
= (const void *)cv_base
;
413 printf(" Filepos: 0x%08lX\n", pdb_data
->filepos
);
414 printf(" TimeStamp: %08X (%s)\n",
415 pdb_data
->timestamp
, get_time_str(pdb_data
->timestamp
));
416 printf(" Dunno: %08X\n", pdb_data
->unknown
);
417 printf(" Filename: %s\n", pdb_data
->name
);
420 if (memcmp(signature
, "RSDS", 4) == 0)
422 const OMFSignatureRSDS
* rsds_data
;
425 rsds_data
= (const void *)cv_base
;
426 printf(" Guid: %s\n",
427 guid_to_string(&rsds_data
->guid
, guid_str
, sizeof(guid_str
)));
428 printf(" Dunno: %08X\n", rsds_data
->unknown
);
429 printf(" Filename: %s\n", rsds_data
->name
);
433 if (memcmp(signature
, "NB09", 4) != 0 && memcmp(signature
, "NB11", 4) != 0)
435 printf("Unsupported signature (%.4s), aborting\n", signature
);
441 printf(" Filepos: 0x%08lX\n", sig
->filepos
);
443 dirHeader
= PRD(Offset(cv_base
) + sig
->filepos
, sizeof(OMFDirHeader
));
444 if (!dirHeader
) {printf("Can't get debug header, aborting\n"); return;}
446 printf(" Size of header: 0x%4X\n", dirHeader
->cbDirHeader
);
447 printf(" Size per entry: 0x%4X\n", dirHeader
->cbDirEntry
);
448 printf(" # of entries: 0x%8X (%d)\n", dirHeader
->cDir
, dirHeader
->cDir
);
449 printf(" Offset to NextDir: 0x%8X\n", dirHeader
->lfoNextDir
);
450 printf(" Flags: 0x%8X\n", dirHeader
->flags
);
452 if (!dirHeader
->cDir
) return;
454 dirEntry
= PRD(Offset(dirHeader
+ 1), sizeof(OMFDirEntry
) * dirHeader
->cDir
);
455 if (!dirEntry
) {printf("Can't get DirEntry array, aborting\n");return;}
457 for (i
= 0; i
< dirHeader
->cDir
; i
++)
459 switch (dirEntry
[i
].SubSection
)
461 case sstModule
: modulecount
++; break;
462 case sstAlignSym
: alignsymcount
++; break;
463 case sstSrcModule
: srcmodulecount
++; break;
464 case sstLibraries
: librariescount
++; break;
465 case sstGlobalSym
: globalsymcount
++; break;
466 case sstGlobalPub
: globalpubcount
++; break;
467 case sstGlobalTypes
: globaltypescount
++; break;
468 case sstSegMap
: segmapcount
++; break;
469 case sstFileIndex
: fileindexcount
++; break;
470 case sstStaticSym
: staticsymcount
++; break;
474 /* This one has to be > 0
476 printf ("\nFound: %d sstModule subsections\n", modulecount
);
478 if (alignsymcount
> 0) printf (" %d sstAlignSym subsections\n", alignsymcount
);
479 if (srcmodulecount
> 0) printf (" %d sstSrcModule subsections\n", srcmodulecount
);
480 if (librariescount
> 0) printf (" %d sstLibraries subsections\n", librariescount
);
481 if (globalsymcount
> 0) printf (" %d sstGlobalSym subsections\n", globalsymcount
);
482 if (globalpubcount
> 0) printf (" %d sstGlobalPub subsections\n", globalpubcount
);
483 if (globaltypescount
> 0) printf (" %d sstGlobalTypes subsections\n", globaltypescount
);
484 if (segmapcount
> 0) printf (" %d sstSegMap subsections\n", segmapcount
);
485 if (fileindexcount
> 0) printf (" %d sstFileIndex subsections\n", fileindexcount
);
486 if (staticsymcount
> 0) printf (" %d sstStaticSym subsections\n", staticsymcount
);
488 dump_codeview_all_modules(dirHeader
);
491 static const char *get_coff_name( const IMAGE_SYMBOL
*coff_sym
, const char *coff_strtab
)
493 static char namebuff
[9];
496 if( coff_sym
->N
.Name
.Short
)
498 memcpy(namebuff
, coff_sym
->N
.ShortName
, 8);
500 nampnt
= &namebuff
[0];
504 nampnt
= coff_strtab
+ coff_sym
->N
.Name
.Long
;
507 if( nampnt
[0] == '_' )
512 void dump_coff(unsigned long coffbase
, unsigned long len
, const void* pmt
)
514 const IMAGE_COFF_SYMBOLS_HEADER
*coff
= (const IMAGE_COFF_SYMBOLS_HEADER
*)PRD(coffbase
, len
);
515 const IMAGE_SYMBOL
*coff_sym
;
516 const IMAGE_SYMBOL
*coff_symbols
=
517 (const IMAGE_SYMBOL
*) ((const char *)coff
+ coff
->LvaToFirstSymbol
);
518 const char *coff_strtab
= (const char *) (coff_symbols
+ coff
->NumberOfSymbols
);
519 const IMAGE_SECTION_HEADER
*sectHead
= pmt
;
524 printf("\nDebug table: COFF format. modbase %p, coffbase %p\n", PRD(0, 0), coff
);
525 printf(" ID | seg:offs [ abs ] | symbol/function name\n");
526 for(i
=0; i
< coff
->NumberOfSymbols
; i
++ )
528 coff_sym
= coff_symbols
+ i
;
529 naux
= coff_sym
->NumberOfAuxSymbols
;
531 if( coff_sym
->StorageClass
== IMAGE_SYM_CLASS_FILE
)
533 printf("file %s\n", (const char *) (coff_sym
+ 1));
538 if( (coff_sym
->StorageClass
== IMAGE_SYM_CLASS_STATIC
)
540 && (coff_sym
->SectionNumber
== 1) )
542 DWORD base
= sectHead
[coff_sym
->SectionNumber
- 1].VirtualAddress
;
544 * This is a normal static function when naux == 0.
545 * Just register it. The current file is the correct
546 * one in this instance.
548 nampnt
= get_coff_name( coff_sym
, coff_strtab
);
550 printf("%05d | %02d:%08x [%08x] | %s\n", i
, coff_sym
->SectionNumber
- 1, coff_sym
->Value
- base
, coff_sym
->Value
, nampnt
);
555 if( (coff_sym
->StorageClass
== IMAGE_SYM_CLASS_EXTERNAL
)
556 && ISFCN(coff_sym
->Type
)
557 && (coff_sym
->SectionNumber
> 0) )
559 DWORD base
= sectHead
[coff_sym
->SectionNumber
- 1].VirtualAddress
;
561 nampnt
= get_coff_name( coff_sym
, coff_strtab
);
563 /* FIXME: add code to find out the file this symbol belongs to,
565 printf("%05d | %02d:%08x [%08x] | %s\n", i
, coff_sym
->SectionNumber
- 1, coff_sym
->Value
- base
, coff_sym
->Value
, nampnt
);
571 * For now, skip past the aux entries.
578 void dump_codeview(unsigned long base
, unsigned long len
)
580 dump_codeview_headers(base
, len
);
583 void dump_frame_pointer_omission(unsigned long base
, unsigned long len
)
586 const FPO_DATA
* last
;
588 /* FPO is used to describe nonstandard stack frames */
589 printf("Range #loc #pmt Prlg #reg Info\n"
590 "-----------------+----+----+----+----+------------\n");
592 fpo
= (const FPO_DATA
*)PRD(base
, len
);
593 if (!fpo
) {printf("Couldn't get FPO blob\n"); return;}
594 last
= (const FPO_DATA
*)((const char*)fpo
+ len
);
596 while (fpo
< last
&& fpo
->ulOffStart
)
598 switch (fpo
->cbFrame
)
600 case FRAME_FPO
: x
= "FRAME_FPO"; break;
601 case FRAME_NONFPO
: x
= "FRAME_NONFPO"; break;
602 case FRAME_TRAP
: x
= "FRAME_TRAP"; break;
603 case FRAME_TSS
: x
= "case FRAME_TSS"; break;
604 default: x
= NULL
; break;
606 printf("%08x-%08x %4u %4u %4u %4u %s%s%s\n",
607 fpo
->ulOffStart
, fpo
->ulOffStart
+ fpo
->cbProcSize
,
608 fpo
->cdwLocals
, fpo
->cdwParams
, fpo
->cbProlog
, fpo
->cbRegs
,
609 x
, fpo
->fHasSEH
? " SEH" : "", fpo
->fUseBP
? " UseBP" : "");
619 struct stab_nlist
* n_next
;
622 unsigned char n_type
;
625 unsigned long n_value
;
628 static const char * const stabs_defs
[] = {
629 NULL
,NULL
,NULL
,NULL
, /* 00 */
630 NULL
,NULL
,NULL
,NULL
, /* 08 */
631 NULL
,NULL
,NULL
,NULL
, /* 10 */
632 NULL
,NULL
,NULL
,NULL
, /* 18 */
633 "GSYM","FNAME","FUN","STSYM", /* 20 */
634 "LCSYM","MAIN","ROSYM","PC", /* 28 */
635 NULL
,"NSYMS","NOMAP",NULL
, /* 30 */
636 "OBJ",NULL
,"OPT",NULL
, /* 38 */
637 "RSYM","M2C","SLINE","DSLINE", /* 40 */
638 "BSLINE","DEFD","FLINE",NULL
, /* 48 */
639 "EHDECL",NULL
,"CATCH",NULL
, /* 50 */
640 NULL
,NULL
,NULL
,NULL
, /* 58 */
641 "SSYM","ENDM","SO",NULL
, /* 60 */
642 NULL
,NULL
,NULL
,NULL
, /* 68 */
643 NULL
,NULL
,NULL
,NULL
, /* 70 */
644 NULL
,NULL
,NULL
,NULL
, /* 78 */
645 "LSYM","BINCL","SOL",NULL
, /* 80 */
646 NULL
,NULL
,NULL
,NULL
, /* 88 */
647 NULL
,NULL
,NULL
,NULL
, /* 90 */
648 NULL
,NULL
,NULL
,NULL
, /* 98 */
649 "PSYM","EINCL","ENTRY",NULL
, /* a0 */
650 NULL
,NULL
,NULL
,NULL
, /* a8 */
651 NULL
,NULL
,NULL
,NULL
, /* b0 */
652 NULL
,NULL
,NULL
,NULL
, /* b8 */
653 "LBRAC","EXCL","SCOPE",NULL
, /* c0 */
654 NULL
,NULL
,NULL
,NULL
, /* c8 */
655 NULL
,NULL
,NULL
,NULL
, /* d0 */
656 NULL
,NULL
,NULL
,NULL
, /* d8 */
657 "RBRAC","BCOMM","ECOMM",NULL
, /* e0 */
658 "ECOML","WITH",NULL
,NULL
, /* e8 */
659 "NBTEXT","NBDATA","NBBSS","NBSTS", /* f0 */
660 "NBLCS",NULL
,NULL
,NULL
/* f8 */
663 void dump_stabs(const void* pv_stabs
, unsigned szstabs
, const char* stabstr
, unsigned szstr
)
669 unsigned int stabbufflen
;
670 const struct stab_nlist
* stab_ptr
= pv_stabs
;
671 const char* strs_end
;
674 nstab
= szstabs
/ sizeof(struct stab_nlist
);
675 strs_end
= stabstr
+ szstr
;
678 * Allocate a buffer into which we can build stab strings for cases
679 * where the stab is continued over multiple lines.
682 stabbuff
= malloc(stabbufflen
);
686 printf("#Sym n_type n_othr n_desc n_value n_strx String\n");
688 for (i
= 0; i
< nstab
; i
++, stab_ptr
++)
690 ptr
= stabstr
+ stab_ptr
->n_un
.n_strx
;
691 if ((ptr
> strs_end
) || (ptr
+ strlen(ptr
) > strs_end
))
693 ptr
= "[[*** bad string ***]]";
695 else if (ptr
[strlen(ptr
) - 1] == '\\')
698 * Indicates continuation. Append this to the buffer, and go onto the
699 * next record. Repeat the process until we find a stab without the
700 * '/' character, as this indicates we have the whole thing.
702 unsigned len
= strlen(ptr
);
703 if (strlen(stabbuff
) + len
> stabbufflen
)
705 stabbufflen
+= 65536;
706 stabbuff
= realloc(stabbuff
, stabbufflen
);
708 strncat(stabbuff
, ptr
, len
- 1);
711 else if (stabbuff
[0] != '\0')
713 strcat(stabbuff
, ptr
);
716 if ((stab_ptr
->n_type
& 1) || !stabs_defs
[stab_ptr
->n_type
/ 2])
717 sprintf(n_buffer
, "<0x%02x>", stab_ptr
->n_type
);
719 sprintf(n_buffer
, "%-6s", stabs_defs
[stab_ptr
->n_type
/ 2]);
720 printf("%4d %s %-8x % 6d %-8lx %-6lx %s\n",
721 i
, n_buffer
, stab_ptr
->n_other
, stab_ptr
->n_desc
, stab_ptr
->n_value
,
722 stab_ptr
->n_un
.n_strx
, ptr
);