ntdll: Rename local variables in heap_reallocate.
[wine.git] / tools / winedump / debug.c
blob9cc17f62e2beb6e4caa5fa9ecacfeb21b7bb19a9
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
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
23 #include "config.h"
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <time.h>
30 #include "../tools.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winedump.h"
34 #include "wine/mscvpdb.h"
37 * .DBG File Layout:
39 * IMAGE_SEPARATE_DEBUG_HEADER
40 * IMAGE_SECTION_HEADER[]
41 * IMAGE_DEBUG_DIRECTORY[]
42 * OMFSignature
43 * debug data (typical example)
44 * - IMAGE_DEBUG_TYPE_MISC
45 * - IMAGE_DEBUG_TYPE_FPO
46 * - IMAGE_DEBUG_TYPE_CODEVIEW
47 * OMFDirHeader
48 * OMFDirEntry[]
52 * Descriptions:
54 * (hdr) IMAGE_SEPARATE_DEBUG_HEADER - .DBG-specific file header; holds info that
55 * applies to the file as a whole, including # of COFF sections, file offsets, etc.
56 * (hdr) IMAGE_SECTION_HEADER - list of COFF sections copied verbatim from .EXE;
57 * although this directory contains file offsets, these offsets are meaningless
58 * in the context of the .DBG file, because only the section headers are copied
59 * to the .DBG file... not the binary data it points to.
60 * (hdr) IMAGE_DEBUG_DIRECTORY - list of different formats of debug info contained in file
61 * (see IMAGE_DEBUG_TYPE_* descriptions below); tells where each section starts
62 * (hdr) OMFSignature (CV) - Contains "NBxx" signature, plus file offset telling how far
63 * into the IMAGE_DEBUG_TYPE_CODEVIEW section the OMFDirHeader and OMFDirEntry's sit
64 * (data) IMAGE_DEBUG_TYPE_MISC - usually holds name of original .EXE file
65 * (data) IMAGE_DEBUG_TYPE_FPO - Frame Pointer Optimization data; used for dealing with
66 * optimized stack frames (optional)
67 * (data) IMAGE_DEBUG_TYPE_CODEVIEW - *** THE GOOD STUFF ***
68 * This block of data contains all the symbol tables, line number info, etc.,
69 * that the Visual C++ debugger needs.
70 * (hdr) OMFDirHeader (CV) -
71 * (hdr) OMFDirEntry (CV) - list of subsections within CodeView debug data section
75 * The .DBG file typically has three arrays of directory entries, which tell
76 * the OS or debugger where in the file to look for the actual data
78 * IMAGE_SECTION_HEADER - number of entries determined by:
79 * (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
81 * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
82 * (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
84 * OMFDirEntry - number of entries determined by:
85 * (OMFDirHeader.cDir)
88 extern const IMAGE_NT_HEADERS* PE_nt_headers;
89 static const void* cv_base /* = 0 */;
91 static BOOL dump_cv_sst_module(const OMFDirEntry* omfde)
93 const OMFModule* module;
94 const OMFSegDesc* segDesc;
95 int i;
97 module = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFModule));
98 if (!module) {printf("Can't get the OMF-Module, aborting\n"); return FALSE;}
100 printf(" olvNumber: %u\n", module->ovlNumber);
101 printf(" iLib: %u\n", module->iLib);
102 printf(" cSeg: %u\n", module->cSeg);
103 printf(" Style: %c%c\n", module->Style[0], module->Style[1]);
104 printf(" Name: %.*s\n",
105 *(const BYTE*)((const char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg),
106 (const char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg + 1);
108 segDesc = PRD(Offset(module + 1), sizeof(OMFSegDesc) * module->cSeg);
109 if (!segDesc) {printf("Can't get the OMF-SegDesc, aborting\n"); return FALSE;}
111 for (i = 0; i < module->cSeg; i++)
113 printf (" segment #%2d: offset = [0x%8x], size = [0x%8x]\n",
114 segDesc->Seg, segDesc->Off, segDesc->cbSeg);
115 segDesc++;
117 return TRUE;
120 static BOOL dump_cv_sst_global_pub(const OMFDirEntry* omfde)
122 long fileoffset;
123 const OMFSymHash* header;
124 const BYTE* symbols;
126 fileoffset = Offset(cv_base) + omfde->lfo;
127 printf (" GlobalPub section starts at file offset 0x%lx\n", fileoffset);
128 printf (" Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash));
130 printf ("\n ----- Begin Symbol Table -----\n");
132 header = PRD(fileoffset, sizeof(OMFSymHash));
133 if (!header) {printf("Can't get OMF-SymHash, aborting\n");return FALSE;}
135 symbols = PRD(fileoffset + sizeof(OMFSymHash), header->cbSymbol);
136 if (!symbols) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;}
138 codeview_dump_symbols(symbols, 0, header->cbSymbol);
140 return TRUE;
143 static BOOL dump_cv_sst_global_sym(const OMFDirEntry* omfde)
145 /*** NOT YET IMPLEMENTED ***/
146 return TRUE;
149 static BOOL dump_cv_sst_static_sym(const OMFDirEntry* omfde)
151 /*** NOT YET IMPLEMENTED ***/
152 return TRUE;
155 static BOOL dump_cv_sst_libraries(const OMFDirEntry* omfde)
157 /*** NOT YET IMPLEMENTED ***/
158 return TRUE;
161 static BOOL dump_cv_sst_global_types(const OMFDirEntry* omfde)
163 long fileoffset;
164 const OMFGlobalTypes*types;
165 const BYTE* data;
166 unsigned sz;
168 fileoffset = Offset(cv_base) + omfde->lfo;
169 printf (" GlobalTypes section starts at file offset 0x%lx\n", fileoffset);
171 printf ("\n ----- Begin Global Types Table -----\n");
173 types = PRD(fileoffset, sizeof(OMFGlobalTypes));
174 if (!types) {printf("Can't get OMF-GlobalTypes, aborting\n");return FALSE;}
176 sz = omfde->cb - sizeof(OMFGlobalTypes) - sizeof(DWORD) * types->cTypes;
177 data = PRD(fileoffset + sizeof(OMFGlobalTypes) + sizeof(DWORD) * types->cTypes, sz);
178 if (!data) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;}
180 /* doc says:
181 * - for NB07 & NB08 (that we don't support yet), offsets are from types
182 * - for NB09, offsets are from data
183 * For now, we only support the latter
185 codeview_dump_types_from_offsets(data, (const DWORD*)(types + 1), types->cTypes);
187 return TRUE;
190 static BOOL dump_cv_sst_seg_map(const OMFDirEntry* omfde)
192 const OMFSegMap* segMap;
193 const OMFSegMapDesc* segMapDesc;
194 int i;
196 segMap = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFSegMap));
197 if (!segMap) {printf("Can't get SegMap, aborting\n");return FALSE;}
199 printf(" cSeg: %u\n", segMap->cSeg);
200 printf(" cSegLog: %u\n", segMap->cSegLog);
202 segMapDesc = PRD(Offset(segMap + 1), segMap->cSeg * sizeof(OMFSegDesc));
203 if (!segMapDesc) {printf("Can't get SegDescr array, aborting\n");return FALSE;}
205 for (i = 0; i < segMap->cSeg; i++)
207 printf(" SegDescr #%2d\n", i + 1);
208 printf(" flags: %04X\n", segMapDesc[i].flags);
209 printf(" ovl: %u\n", segMapDesc[i].ovl);
210 printf(" group: %u\n", segMapDesc[i].group);
211 printf(" frame: %u\n", segMapDesc[i].frame);
212 printf(" iSegName: %u\n", segMapDesc[i].iSegName);
213 printf(" iClassName: %u\n", segMapDesc[i].iClassName);
214 printf(" offset: %u\n", segMapDesc[i].offset);
215 printf(" cbSeg: %u\n", segMapDesc[i].cbSeg);
218 return TRUE;
221 static BOOL dump_cv_sst_file_index(const OMFDirEntry* omfde)
223 /*** NOT YET IMPLEMENTED ***/
224 return TRUE;
227 static BOOL dump_cv_sst_src_module(const OMFDirEntry* omfde)
229 int i, j;
230 const BYTE* rawdata;
231 const unsigned int *seg_info_dw;
232 const unsigned short* seg_info_w;
233 unsigned ofs;
234 const OMFSourceModule* sourceModule;
235 const OMFSourceFile* sourceFile;
236 const OMFSourceLine* sourceLine;
238 rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb);
239 if (!rawdata) {printf("Can't get srcModule subsection details, aborting\n");return FALSE;}
241 /* FIXME: check ptr validity */
242 sourceModule = (const void*)rawdata;
243 printf (" Module table: Found %d file(s) and %d segment(s)\n",
244 sourceModule->cFile, sourceModule->cSeg);
245 for (i = 0; i < sourceModule->cFile; i++)
247 printf (" File #%2d begins at an offset of 0x%x in this section\n",
248 i + 1, sourceModule->baseSrcFile[i]);
251 /* FIXME: check ptr validity */
252 seg_info_dw = (const void*)((const char*)(sourceModule + 1) +
253 sizeof(unsigned int) * (sourceModule->cFile - 1));
254 seg_info_w = (const unsigned short*)(&seg_info_dw[sourceModule->cSeg * 2]);
255 for (i = 0; i < sourceModule->cSeg; i++)
257 printf (" Segment #%2d start = 0x%x, end = 0x%x, seg index = %u\n",
258 i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1],
259 seg_info_w[i]);
261 ofs = sizeof(OMFSourceModule) + sizeof(unsigned int) * (sourceModule->cFile - 1) +
262 sourceModule->cSeg * (2 * sizeof(unsigned int) + sizeof(unsigned short));
263 ofs = (ofs + 3) & ~3;
265 /* the OMFSourceFile is quite unpleasant to use:
266 * we have first:
267 * unsigned short number of segments
268 * unsigned short reserved
269 * unsigned int baseSrcLn[# segments]
270 * unsigned int offset[2 * #segments]
271 * odd indices are start offsets
272 * even indices are end offsets
273 * unsigned char string length for file name
274 * char file name (length is previous field)
276 /* FIXME: check ptr validity */
277 sourceFile = (const void*)(rawdata + ofs);
278 seg_info_dw = (const void*)((const char*)sourceFile + 2 * sizeof(unsigned short) +
279 sourceFile->cSeg * sizeof(unsigned int));
281 ofs += 2 * sizeof(unsigned short) + 3 * sourceFile->cSeg * sizeof(unsigned int);
283 printf(" File table: %.*s\n",
284 *(const BYTE*)((const char*)sourceModule + ofs), (const char*)sourceModule + ofs + 1);
286 for (i = 0; i < sourceFile->cSeg; i++)
288 printf (" Segment #%2d start = 0x%x, end = 0x%x, offset = 0x%x\n",
289 i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], sourceFile->baseSrcLn[i]);
291 /* add file name length */
292 ofs += *(const BYTE*)((const char*)sourceModule + ofs) + 1;
293 ofs = (ofs + 3) & ~3;
295 for (i = 0; i < sourceModule->cSeg; i++)
297 sourceLine = (const void*)(rawdata + ofs);
298 seg_info_dw = (const void*)((const char*)sourceLine + 2 * sizeof(unsigned short));
299 seg_info_w = (const void*)(&seg_info_dw[sourceLine->cLnOff]);
301 printf (" Line table #%2d: Found %d line numbers for segment index %d\n",
302 i, sourceLine->cLnOff, sourceLine->Seg);
304 for (j = 0; j < sourceLine->cLnOff; j++)
306 printf (" Pair #%2d: offset = [0x%8x], linenumber = %d\n",
307 j + 1, seg_info_dw[j], seg_info_w[j]);
309 ofs += 2 * sizeof(unsigned short) +
310 sourceLine->cLnOff * (sizeof(unsigned int) + sizeof(unsigned short));
311 ofs = (ofs + 3) & ~3;
314 return TRUE;
317 static BOOL dump_cv_sst_align_sym(const OMFDirEntry* omfde)
319 const char* rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb);
321 if (!rawdata) {printf("Can't get srcAlignSym subsection details, aborting\n");return FALSE;}
322 if (omfde->cb < sizeof(DWORD)) return TRUE;
323 codeview_dump_symbols(rawdata, sizeof(DWORD), omfde->cb);
325 return TRUE;
328 static void dump_codeview_all_modules(const OMFDirHeader *omfdh)
330 unsigned i;
331 const OMFDirEntry* dirEntry;
332 const char* str;
334 if (!omfdh || !omfdh->cDir) return;
336 dirEntry = PRD(Offset(omfdh + 1), omfdh->cDir * sizeof(OMFDirEntry));
337 if (!dirEntry) {printf("Can't read DirEntry array, aborting\n"); return;}
339 for (i = 0; i < omfdh->cDir; i++)
341 switch (dirEntry[i].SubSection)
343 case sstModule: str = "sstModule"; break;
344 case sstAlignSym: str = "sstAlignSym"; break;
345 case sstSrcModule: str = "sstSrcModule"; break;
346 case sstLibraries: str = "sstLibraries"; break;
347 case sstGlobalSym: str = "sstGlobalSym"; break;
348 case sstGlobalPub: str = "sstGlobalPub"; break;
349 case sstGlobalTypes: str = "sstGlobalTypes"; break;
350 case sstSegMap: str = "sstSegMap"; break;
351 case sstFileIndex: str = "sstFileIndex"; break;
352 case sstStaticSym: str = "sstStaticSym"; break;
353 default: str = "<undefined>"; break;
355 printf("Module #%2d (%p)\n", i + 1, &dirEntry[i]);
356 printf(" SubSection: %04X (%s)\n", dirEntry[i].SubSection, str);
357 printf(" iMod: %d\n", dirEntry[i].iMod);
358 printf(" lfo: %d\n", dirEntry[i].lfo);
359 printf(" cb: %u\n", dirEntry[i].cb);
361 switch (dirEntry[i].SubSection)
363 case sstModule: dump_cv_sst_module(&dirEntry[i]); break;
364 case sstAlignSym: dump_cv_sst_align_sym(&dirEntry[i]); break;
365 case sstSrcModule: dump_cv_sst_src_module(&dirEntry[i]); break;
366 case sstLibraries: dump_cv_sst_libraries(&dirEntry[i]); break;
367 case sstGlobalSym: dump_cv_sst_global_sym(&dirEntry[i]); break;
368 case sstGlobalPub: dump_cv_sst_global_pub(&dirEntry[i]); break;
369 case sstGlobalTypes: dump_cv_sst_global_types(&dirEntry[i]); break;
370 case sstSegMap: dump_cv_sst_seg_map(&dirEntry[i]); break;
371 case sstFileIndex: dump_cv_sst_file_index(&dirEntry[i]); break;
372 case sstStaticSym: dump_cv_sst_static_sym(&dirEntry[i]); break;
373 default: printf("unsupported type %x\n", dirEntry[i].SubSection); break;
375 printf("\n");
378 return;
381 static void dump_codeview_headers(unsigned long base, unsigned long len)
383 const OMFDirHeader* dirHeader;
384 const char* signature;
385 const OMFDirEntry* dirEntry;
386 const OMFSignature* sig;
387 unsigned i;
388 int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0;
389 int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0;
390 int segmapcount = 0, fileindexcount = 0, staticsymcount = 0;
392 cv_base = PRD(base, len);
393 if (!cv_base) {printf("Can't get full debug content, aborting\n");return;}
395 signature = cv_base;
397 printf(" CodeView Data\n");
398 printf(" Signature: %.4s\n", signature);
400 if (memcmp(signature, "NB10", 4) == 0)
402 const CODEVIEW_PDB_DATA* pdb_data;
403 pdb_data = cv_base;
405 printf(" Filepos: 0x%08X\n", pdb_data->filepos);
406 printf(" TimeStamp: %08X (%s)\n",
407 pdb_data->timestamp, get_time_str(pdb_data->timestamp));
408 printf(" Age: %08X\n", pdb_data->age);
409 printf(" Filename: %s\n", pdb_data->name);
410 return;
412 if (memcmp(signature, "RSDS", 4) == 0)
414 const OMFSignatureRSDS* rsds_data;
416 rsds_data = cv_base;
417 printf(" Guid: %s\n", get_guid_str(&rsds_data->guid));
418 printf(" Age: %08X\n", rsds_data->age);
419 printf(" Filename: %s\n", rsds_data->name);
420 return;
423 if (memcmp(signature, "NB09", 4) != 0 && memcmp(signature, "NB11", 4) != 0)
425 printf("Unsupported signature (%.4s), aborting\n", signature);
426 return;
429 sig = cv_base;
431 printf(" Filepos: 0x%08X\n", sig->filepos);
433 dirHeader = PRD(Offset(cv_base) + sig->filepos, sizeof(OMFDirHeader));
434 if (!dirHeader) {printf("Can't get debug header, aborting\n"); return;}
436 printf(" Size of header: 0x%4X\n", dirHeader->cbDirHeader);
437 printf(" Size per entry: 0x%4X\n", dirHeader->cbDirEntry);
438 printf(" # of entries: 0x%8X (%d)\n", dirHeader->cDir, dirHeader->cDir);
439 printf(" Offset to NextDir: 0x%8X\n", dirHeader->lfoNextDir);
440 printf(" Flags: 0x%8X\n", dirHeader->flags);
442 if (!dirHeader->cDir) return;
444 dirEntry = PRD(Offset(dirHeader + 1), sizeof(OMFDirEntry) * dirHeader->cDir);
445 if (!dirEntry) {printf("Can't get DirEntry array, aborting\n");return;}
447 for (i = 0; i < dirHeader->cDir; i++)
449 switch (dirEntry[i].SubSection)
451 case sstModule: modulecount++; break;
452 case sstAlignSym: alignsymcount++; break;
453 case sstSrcModule: srcmodulecount++; break;
454 case sstLibraries: librariescount++; break;
455 case sstGlobalSym: globalsymcount++; break;
456 case sstGlobalPub: globalpubcount++; break;
457 case sstGlobalTypes: globaltypescount++; break;
458 case sstSegMap: segmapcount++; break;
459 case sstFileIndex: fileindexcount++; break;
460 case sstStaticSym: staticsymcount++; break;
464 /* This one has to be > 0
466 printf ("\nFound: %d sstModule subsections\n", modulecount);
468 if (alignsymcount > 0) printf (" %d sstAlignSym subsections\n", alignsymcount);
469 if (srcmodulecount > 0) printf (" %d sstSrcModule subsections\n", srcmodulecount);
470 if (librariescount > 0) printf (" %d sstLibraries subsections\n", librariescount);
471 if (globalsymcount > 0) printf (" %d sstGlobalSym subsections\n", globalsymcount);
472 if (globalpubcount > 0) printf (" %d sstGlobalPub subsections\n", globalpubcount);
473 if (globaltypescount > 0) printf (" %d sstGlobalTypes subsections\n", globaltypescount);
474 if (segmapcount > 0) printf (" %d sstSegMap subsections\n", segmapcount);
475 if (fileindexcount > 0) printf (" %d sstFileIndex subsections\n", fileindexcount);
476 if (staticsymcount > 0) printf (" %d sstStaticSym subsections\n", staticsymcount);
478 dump_codeview_all_modules(dirHeader);
481 static const char *get_coff_name( const IMAGE_SYMBOL *coff_sym, const char *coff_strtab )
483 static char namebuff[9];
484 const char* nampnt;
486 if( coff_sym->N.Name.Short )
488 memcpy(namebuff, coff_sym->N.ShortName, 8);
489 namebuff[8] = '\0';
490 nampnt = namebuff;
492 else
494 nampnt = coff_strtab + coff_sym->N.Name.Long;
497 if( nampnt[0] == '_' )
498 nampnt++;
499 return nampnt;
502 static const char* storage_class(BYTE sc)
504 static char tmp[7];
505 switch (sc)
507 case IMAGE_SYM_CLASS_STATIC: return "static";
508 case IMAGE_SYM_CLASS_EXTERNAL: return "extrnl";
509 case IMAGE_SYM_CLASS_LABEL: return "label ";
511 sprintf(tmp, "#%d", sc);
512 return tmp;
515 void dump_coff_symbol_table(const IMAGE_SYMBOL *coff_symbols, unsigned num_sym,
516 const IMAGE_SECTION_HEADER *sectHead)
518 const IMAGE_SYMBOL *coff_sym;
519 const char *coff_strtab = (const char *) (coff_symbols + num_sym);
520 unsigned int i;
521 const char *nampnt;
522 int naux;
524 printf("\nDebug table: COFF format.\n");
525 printf(" ID | seg:offs [ abs ] | Kind | symbol/function name\n");
526 for (i=0; i < num_sym; i++)
528 coff_sym = coff_symbols + i;
529 naux = coff_sym->NumberOfAuxSymbols;
531 switch (coff_sym->StorageClass)
533 case IMAGE_SYM_CLASS_FILE:
534 printf("file %s\n", (const char *) (coff_sym + 1));
535 break;
536 case IMAGE_SYM_CLASS_STATIC:
537 case IMAGE_SYM_CLASS_EXTERNAL:
538 case IMAGE_SYM_CLASS_LABEL:
539 if (coff_sym->SectionNumber > 0)
541 UINT base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress;
542 nampnt = get_coff_name( coff_sym, coff_strtab );
544 printf("%05d | %02d:%08x [%08x] | %s | %s\n",
545 i, coff_sym->SectionNumber - 1, (UINT)coff_sym->Value,
546 base + (UINT)coff_sym->Value,
547 storage_class(coff_sym->StorageClass), nampnt);
549 break;
550 default:
551 printf("%05d | %s\n", i, storage_class(coff_sym->StorageClass));
554 * For now, skip past the aux entries.
556 i += naux;
560 void dump_coff(unsigned long coffbase, unsigned long len, const IMAGE_SECTION_HEADER* sectHead)
562 const IMAGE_COFF_SYMBOLS_HEADER *coff = PRD(coffbase, len);
563 const IMAGE_SYMBOL *coff_symbols =
564 (const IMAGE_SYMBOL *) ((const char *)coff + coff->LvaToFirstSymbol);
566 dump_coff_symbol_table(coff_symbols, coff->NumberOfSymbols, sectHead);
569 void dump_codeview(unsigned long base, unsigned long len)
571 dump_codeview_headers(base, len);
574 void dump_frame_pointer_omission(unsigned long base, unsigned long len)
576 const FPO_DATA* fpo;
577 const FPO_DATA* last;
578 const char* x;
579 /* FPO is used to describe nonstandard stack frames */
580 printf("Range #loc #pmt Prlg #reg Info\n"
581 "-----------------+----+----+----+----+------------\n");
583 fpo = PRD(base, len);
584 if (!fpo) {printf("Couldn't get FPO blob\n"); return;}
585 last = (const FPO_DATA*)((const char*)fpo + len);
587 while (fpo < last && fpo->ulOffStart)
589 switch (fpo->cbFrame)
591 case FRAME_FPO: x = "FRAME_FPO"; break;
592 case FRAME_NONFPO: x = "FRAME_NONFPO"; break;
593 case FRAME_TRAP: x = "FRAME_TRAP"; break;
594 case FRAME_TSS: x = "case FRAME_TSS"; break;
595 default: x = NULL; break;
597 printf("%08x-%08x %4u %4u %4u %4u %s%s%s\n",
598 (UINT)fpo->ulOffStart, (UINT)(fpo->ulOffStart + fpo->cbProcSize),
599 (UINT)fpo->cdwLocals, fpo->cdwParams, fpo->cbProlog, fpo->cbRegs,
600 x, fpo->fHasSEH ? " SEH" : "", fpo->fUseBP ? " UseBP" : "");
601 fpo++;
605 struct stab_nlist
607 union
609 char* n_name;
610 struct stab_nlist* n_next;
611 int n_strx;
612 } n_un;
613 unsigned char n_type;
614 char n_other;
615 short n_desc;
616 unsigned int n_value;
619 static const char * const stabs_defs[] = {
620 NULL,NULL,NULL,NULL, /* 00 */
621 NULL,NULL,NULL,NULL, /* 08 */
622 NULL,NULL,NULL,NULL, /* 10 */
623 NULL,NULL,NULL,NULL, /* 18 */
624 "GSYM","FNAME","FUN","STSYM", /* 20 */
625 "LCSYM","MAIN","ROSYM","PC", /* 28 */
626 NULL,"NSYMS","NOMAP",NULL, /* 30 */
627 "OBJ",NULL,"OPT",NULL, /* 38 */
628 "RSYM","M2C","SLINE","DSLINE", /* 40 */
629 "BSLINE","DEFD","FLINE",NULL, /* 48 */
630 "EHDECL",NULL,"CATCH",NULL, /* 50 */
631 NULL,NULL,NULL,NULL, /* 58 */
632 "SSYM","ENDM","SO",NULL, /* 60 */
633 NULL,NULL,NULL,NULL, /* 68 */
634 NULL,NULL,NULL,NULL, /* 70 */
635 NULL,NULL,NULL,NULL, /* 78 */
636 "LSYM","BINCL","SOL",NULL, /* 80 */
637 NULL,NULL,NULL,NULL, /* 88 */
638 NULL,NULL,NULL,NULL, /* 90 */
639 NULL,NULL,NULL,NULL, /* 98 */
640 "PSYM","EINCL","ENTRY",NULL, /* a0 */
641 NULL,NULL,NULL,NULL, /* a8 */
642 NULL,NULL,NULL,NULL, /* b0 */
643 NULL,NULL,NULL,NULL, /* b8 */
644 "LBRAC","EXCL","SCOPE",NULL, /* c0 */
645 NULL,NULL,NULL,NULL, /* c8 */
646 NULL,NULL,NULL,NULL, /* d0 */
647 NULL,NULL,NULL,NULL, /* d8 */
648 "RBRAC","BCOMM","ECOMM",NULL, /* e0 */
649 "ECOML","WITH",NULL,NULL, /* e8 */
650 "NBTEXT","NBDATA","NBBSS","NBSTS", /* f0 */
651 "NBLCS",NULL,NULL,NULL /* f8 */
654 void dump_stabs(const void* pv_stabs, unsigned szstabs, const char* stabstr, unsigned szstr)
656 int i;
657 int nstab;
658 const char* ptr;
659 char* stabbuff;
660 unsigned int stabbufflen;
661 const struct stab_nlist* stab_ptr = pv_stabs;
662 const char* strs_end;
663 char n_buffer[16];
665 nstab = szstabs / sizeof(struct stab_nlist);
666 strs_end = stabstr + szstr;
669 * Allocate a buffer into which we can build stab strings for cases
670 * where the stab is continued over multiple lines.
672 stabbufflen = 65536;
673 stabbuff = xmalloc(stabbufflen);
675 stabbuff[0] = '\0';
677 printf("#Sym n_type n_othr n_desc n_value n_strx String\n");
679 for (i = 0; i < nstab; i++, stab_ptr++)
681 ptr = stabstr + stab_ptr->n_un.n_strx;
682 if ((ptr > strs_end) || (ptr + strlen(ptr) > strs_end))
684 ptr = "[[*** bad string ***]]";
686 else if (ptr[strlen(ptr) - 1] == '\\')
689 * Indicates continuation. Append this to the buffer, and go onto the
690 * next record. Repeat the process until we find a stab without the
691 * '/' character, as this indicates we have the whole thing.
693 unsigned len = strlen(ptr);
694 if (strlen(stabbuff) + len > stabbufflen)
696 stabbufflen += 65536;
697 stabbuff = xrealloc(stabbuff, stabbufflen);
699 strcat(stabbuff, ptr);
700 continue;
702 else if (stabbuff[0] != '\0')
704 strcat(stabbuff, ptr);
705 ptr = stabbuff;
707 if ((stab_ptr->n_type & 1) || !stabs_defs[stab_ptr->n_type / 2])
708 sprintf(n_buffer, "<0x%02x>", stab_ptr->n_type);
709 else
710 sprintf(n_buffer, "%-6s", stabs_defs[stab_ptr->n_type / 2]);
711 printf("%4d %s %-8x % 6d %-8x %-6x %s\n",
712 i, n_buffer, stab_ptr->n_other, stab_ptr->n_desc, stab_ptr->n_value,
713 stab_ptr->n_un.n_strx, ptr);
715 free(stabbuff);