wined3d: D3DTRANSFORMSTATETYPE: Consistently use in the WINED3D namespace.
[wine/multimedia.git] / tools / winedump / debug.c
blobeb3963b0c787d816acdda56ab03e76d158da8478
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"
24 #include "wine/port.h"
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 #include <time.h>
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36 #ifdef HAVE_SYS_STAT_H
37 # include <sys/stat.h>
38 #endif
39 #ifdef HAVE_SYS_MMAN_H
40 #include <sys/mman.h>
41 #endif
42 #include <fcntl.h>
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winedump.h"
47 #include "pe.h"
48 #include "cvinclude.h"
51 * .DBG File Layout:
53 * IMAGE_SEPARATE_DEBUG_HEADER
54 * IMAGE_SECTION_HEADER[]
55 * IMAGE_DEBUG_DIRECTORY[]
56 * OMFSignature
57 * debug data (typical example)
58 * - IMAGE_DEBUG_TYPE_MISC
59 * - IMAGE_DEBUG_TYPE_FPO
60 * - IMAGE_DEBUG_TYPE_CODEVIEW
61 * OMFDirHeader
62 * OMFDirEntry[]
66 * Descriptions:
68 * (hdr) IMAGE_SEPARATE_DEBUG_HEADER - .DBG-specific file header; holds info that
69 * applies to the file as a whole, including # of COFF sections, file offsets, etc.
70 * (hdr) IMAGE_SECTION_HEADER - list of COFF sections copied verbatim from .EXE;
71 * although this directory contains file offsets, these offsets are meaningless
72 * in the context of the .DBG file, because only the section headers are copied
73 * to the .DBG file...not the binary data it points to.
74 * (hdr) IMAGE_DEBUG_DIRECTORY - list of different formats of debug info contained in file
75 * (see IMAGE_DEBUG_TYPE_* descriptions below); tells where each section starts
76 * (hdr) OMFSignature (CV) - Contains "NBxx" signature, plus file offset telling how far
77 * into the IMAGE_DEBUG_TYPE_CODEVIEW section the OMFDirHeader and OMFDirEntry's sit
78 * (data) IMAGE_DEBUG_TYPE_MISC - usually holds name of original .EXE file
79 * (data) IMAGE_DEBUG_TYPE_FPO - Frame Pointer Optimization data; used for dealing with
80 * optimized stack frames (optional)
81 * (data) IMAGE_DEBUG_TYPE_CODEVIEW - *** THE GOOD STUFF ***
82 * This block of data contains all the symbol tables, line number info, etc.,
83 * that the Visual C++ debugger needs.
84 * (hdr) OMFDirHeader (CV) -
85 * (hdr) OMFDirEntry (CV) - list of subsections within CodeView debug data section
89 * The .DBG file typically has three arrays of directory entries, which tell
90 * the OS or debugger where in the file to look for the actual data
92 * IMAGE_SECTION_HEADER - number of entries determined by:
93 * (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
95 * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
96 * (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
98 * OMFDirEntry - number of entries determined by:
99 * (OMFDirHeader.cDir)
102 extern const IMAGE_NT_HEADERS* PE_nt_headers;
103 static const void* cv_base /* = 0 */;
105 static int dump_cv_sst_module(const OMFDirEntry* omfde)
107 const OMFModule* module;
108 const OMFSegDesc* segDesc;
109 int i;
111 module = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFModule));
112 if (!module) {printf("Can't get the OMF-Module, aborting\n"); return FALSE;}
114 printf(" olvNumber: %u\n", module->ovlNumber);
115 printf(" iLib: %u\n", module->iLib);
116 printf(" cSeg: %u\n", module->cSeg);
117 printf(" Style: %c%c\n", module->Style[0], module->Style[1]);
118 printf(" Name: %.*s\n",
119 *(const BYTE*)((const char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg),
120 (const char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg + 1);
122 segDesc = PRD(Offset(module + 1), sizeof(OMFSegDesc) * module->cSeg);
123 if (!segDesc) {printf("Can't get the OMF-SegDesc, aborting\n"); return FALSE;}
125 for (i = 0; i < module->cSeg; i++)
127 printf (" segment #%2d: offset = [0x%8lx], size = [0x%8lx]\n",
128 segDesc->Seg, segDesc->Off, segDesc->cbSeg);
129 segDesc++;
131 return TRUE;
134 static int dump_cv_sst_global_pub(const OMFDirEntry* omfde)
136 long fileoffset;
137 const OMFSymHash* header;
138 const BYTE* symbols;
139 const BYTE* curpos;
140 const PUBSYM32* sym;
141 unsigned symlen;
142 int recordlen;
143 char nametmp[256];
145 fileoffset = Offset(cv_base) + omfde->lfo;
146 printf (" GlobalPub section starts at file offset 0x%lx\n", fileoffset);
147 printf (" Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash));
149 printf ("\n ----- Begin Symbol Table -----\n");
150 printf (" (type) (symbol name) (offset) (len) (seg) (ind)\n");
152 header = PRD(fileoffset, sizeof(OMFSymHash));
153 if (!header) {printf("Can't get OMF-SymHash, aborting\n");return FALSE;}
155 symbols = PRD(fileoffset + sizeof(OMFSymHash), header->cbSymbol);
156 if (!symbols) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;}
158 /* We don't know how many symbols are in this block of memory...only what
159 * the total size of the block is. Because the symbol's name is tacked
160 * on to the end of the PUBSYM32 struct, each symbol may take up a different
161 * # of bytes. This makes it harder to parse through the symbol table,
162 * since we won't know the exact location of the following symbol until we've
163 * already parsed the current one.
165 for (curpos = symbols; curpos < symbols + header->cbSymbol; curpos += recordlen)
167 /* Point to the next PUBSYM32 in the table.
169 sym = (const PUBSYM32*)curpos;
171 if (sym->reclen < sizeof(PUBSYM32)) break;
173 symlen = sym->reclen - sizeof(PUBSYM32) + 1;
174 if (symlen > sizeof(nametmp)) {printf("\nsqueeze%d\n", symlen);symlen = sizeof(nametmp) - 1;}
176 memcpy(nametmp, curpos + sizeof (PUBSYM32) + 1, symlen);
177 nametmp[symlen] = '\0';
179 printf (" 0x%04x %-30.30s [0x%8lx] [0x%4x] %d %ld\n",
180 sym->rectyp, nametmp, sym->off, sym->reclen, sym->seg, sym->typind);
182 /* The entire record is null-padded to the nearest 4-byte
183 * boundary, so we must do a little extra math to keep things straight.
185 recordlen = (sym->reclen + 3) & ~3;
188 return TRUE;
191 static int dump_cv_sst_global_sym(const OMFDirEntry* omfde)
193 /*** NOT YET IMPLEMENTED ***/
194 return TRUE;
197 static int dump_cv_sst_static_sym(const OMFDirEntry* omfde)
199 /*** NOT YET IMPLEMENTED ***/
200 return TRUE;
203 static int dump_cv_sst_libraries(const OMFDirEntry* omfde)
205 /*** NOT YET IMPLEMENTED ***/
206 return TRUE;
209 static int dump_cv_sst_global_types(const OMFDirEntry* omfde)
211 /*** NOT YET IMPLEMENTED ***/
212 return TRUE;
215 static int dump_cv_sst_seg_map(const OMFDirEntry* omfde)
217 const OMFSegMap* segMap;
218 const OMFSegMapDesc* segMapDesc;
219 int i;
221 segMap = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFSegMap));
222 if (!segMap) {printf("Can't get SegMap, aborting\n");return FALSE;}
224 printf(" cSeg: %u\n", segMap->cSeg);
225 printf(" cSegLog: %u\n", segMap->cSegLog);
227 segMapDesc = PRD(Offset(segMap + 1), segMap->cSeg * sizeof(OMFSegDesc));
228 if (!segMapDesc) {printf("Can't get SegDescr array, aborting\n");return FALSE;}
230 for (i = 0; i < segMap->cSeg; i++)
232 printf(" SegDescr #%2d\n", i + 1);
233 printf(" flags: %04X\n", segMapDesc[i].flags);
234 printf(" ovl: %u\n", segMapDesc[i].ovl);
235 printf(" group: %u\n", segMapDesc[i].group);
236 printf(" frame: %u\n", segMapDesc[i].frame);
237 printf(" iSegName: %u\n", segMapDesc[i].iSegName);
238 printf(" iClassName: %u\n", segMapDesc[i].iClassName);
239 printf(" offset: %lu\n", segMapDesc[i].offset);
240 printf(" cbSeg: %lu\n", segMapDesc[i].cbSeg);
243 return TRUE;
246 static int dump_cv_sst_file_index(const OMFDirEntry* omfde)
248 /*** NOT YET IMPLEMENTED ***/
249 return TRUE;
252 static int dump_cv_sst_src_module(const OMFDirEntry* omfde)
254 int i, j;
255 const BYTE* rawdata;
256 const unsigned long* seg_info_dw;
257 const unsigned short* seg_info_w;
258 unsigned ofs;
259 const OMFSourceModule* sourceModule;
260 const OMFSourceFile* sourceFile;
261 const OMFSourceLine* sourceLine;
263 rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb);
264 if (!rawdata) {printf("Can't get srcModule subsection details, aborting\n");return FALSE;}
266 /* FIXME: check ptr validity */
267 sourceModule = (const void*)rawdata;
268 printf (" Module table: Found %d file(s) and %d segment(s)\n",
269 sourceModule->cFile, sourceModule->cSeg);
270 for (i = 0; i < sourceModule->cFile; i++)
272 printf (" File #%2d begins at an offset of 0x%lx in this section\n",
273 i + 1, sourceModule->baseSrcFile[i]);
276 /* FIXME: check ptr validity */
277 seg_info_dw = (const void*)((const char*)(sourceModule + 1) +
278 sizeof(unsigned long) * (sourceModule->cFile - 1));
279 seg_info_w = (const unsigned short*)(&seg_info_dw[sourceModule->cSeg * 2]);
280 for (i = 0; i < sourceModule->cSeg; i++)
282 printf (" Segment #%2d start = 0x%lx, end = 0x%lx, seg index = %u\n",
283 i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1],
284 seg_info_w[i]);
286 ofs = sizeof(OMFSourceModule) + sizeof(unsigned long) * (sourceModule->cFile - 1) +
287 sourceModule->cSeg * (2 * sizeof(unsigned long) + sizeof(unsigned short));
288 ofs = (ofs + 3) & ~3;
290 /* the OMFSourceFile is quite unpleasant to use:
291 * we have first:
292 * unsigned short number of segments
293 * unsigned short reservered
294 * unsigned long baseSrcLn[# segments]
295 * unsigned long offset[2 * #segments]
296 * odd indices are start offsets
297 * even indices are end offsets
298 * unsigned char string length for file name
299 * char file name (length is previous field)
301 /* FIXME: check ptr validity */
302 sourceFile = (const void*)(rawdata + ofs);
303 seg_info_dw = (const void*)((const char*)sourceFile + 2 * sizeof(unsigned short) +
304 sourceFile->cSeg * sizeof(unsigned long));
306 ofs += 2 * sizeof(unsigned short) + 3 * sourceFile->cSeg * sizeof(unsigned long);
308 printf(" File table: %.*s\n",
309 *(const BYTE*)((const char*)sourceModule + ofs), (const char*)sourceModule + ofs + 1);
311 for (i = 0; i < sourceFile->cSeg; i++)
313 printf (" Segment #%2d start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
314 i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], sourceFile->baseSrcLn[i]);
316 /* add file name length */
317 ofs += *(const BYTE*)((const char*)sourceModule + ofs) + 1;
318 ofs = (ofs + 3) & ~3;
320 for (i = 0; i < sourceModule->cSeg; i++)
322 sourceLine = (const void*)(rawdata + ofs);
323 seg_info_dw = (const void*)((const char*)sourceLine + 2 * sizeof(unsigned short));
324 seg_info_w = (const void*)(&seg_info_dw[sourceLine->cLnOff]);
326 printf (" Line table #%2d: Found %d line numbers for segment index %d\n",
327 i, sourceLine->cLnOff, sourceLine->Seg);
329 for (j = 0; j < sourceLine->cLnOff; j++)
331 printf (" Pair #%2d: offset = [0x%8lx], linenumber = %d\n",
332 j + 1, seg_info_dw[j], seg_info_w[j]);
334 ofs += 2 * sizeof(unsigned short) +
335 sourceLine->cLnOff * (sizeof(unsigned long) + sizeof(unsigned short));
336 ofs = (ofs + 3) & ~3;
339 return TRUE;
342 static int dump_cv_sst_align_sym(const OMFDirEntry* omfde)
344 /*** NOT YET IMPLEMENTED ***/
346 return TRUE;
349 static void dump_codeview_all_modules(const OMFDirHeader *omfdh)
351 unsigned i;
352 const OMFDirEntry* dirEntry;
353 const char* str;
355 if (!omfdh || !omfdh->cDir) return;
357 dirEntry = PRD(Offset(omfdh + 1), omfdh->cDir * sizeof(OMFDirEntry));
358 if (!dirEntry) {printf("Can't read DirEntry array, aborting\n"); return;}
360 for (i = 0; i < omfdh->cDir; i++)
362 switch (dirEntry[i].SubSection)
364 case sstModule: str = "sstModule"; break;
365 case sstAlignSym: str = "sstAlignSym"; break;
366 case sstSrcModule: str = "sstSrcModule"; break;
367 case sstLibraries: str = "sstLibraries"; break;
368 case sstGlobalSym: str = "sstGlobalSym"; break;
369 case sstGlobalPub: str = "sstGlobalPub"; break;
370 case sstGlobalTypes: str = "sstGlobalTypes"; break;
371 case sstSegMap: str = "sstSegMap"; break;
372 case sstFileIndex: str = "sstFileIndex"; break;
373 case sstStaticSym: str = "sstStaticSym"; break;
374 default: str = "<undefined>"; break;
376 printf("Module #%2d (%p)\n", i + 1, &dirEntry[i]);
377 printf(" SubSection: %04X (%s)\n", dirEntry[i].SubSection, str);
378 printf(" iMod: %d\n", dirEntry[i].iMod);
379 printf(" lfo: %ld\n", dirEntry[i].lfo);
380 printf(" cb: %lu\n", dirEntry[i].cb);
382 switch (dirEntry[i].SubSection)
384 case sstModule: dump_cv_sst_module(&dirEntry[i]); break;
385 case sstAlignSym: dump_cv_sst_align_sym(&dirEntry[i]); break;
386 case sstSrcModule: dump_cv_sst_src_module(&dirEntry[i]); break;
387 case sstLibraries: dump_cv_sst_libraries(&dirEntry[i]); break;
388 case sstGlobalSym: dump_cv_sst_global_sym(&dirEntry[i]); break;
389 case sstGlobalPub: dump_cv_sst_global_pub(&dirEntry[i]); break;
390 case sstGlobalTypes: dump_cv_sst_global_types(&dirEntry[i]); break;
391 case sstSegMap: dump_cv_sst_seg_map(&dirEntry[i]); break;
392 case sstFileIndex: dump_cv_sst_file_index(&dirEntry[i]); break;
393 case sstStaticSym: dump_cv_sst_static_sym(&dirEntry[i]); break;
394 default: printf("unsupported type %x\n", dirEntry[i].SubSection); break;
396 printf("\n");
399 return;
402 static void dump_codeview_headers(unsigned long base, unsigned long len)
404 const OMFDirHeader* dirHeader;
405 const OMFSignature* signature;
406 const OMFDirEntry* dirEntry;
407 unsigned i;
408 int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0;
409 int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0;
410 int segmapcount = 0, fileindexcount = 0, staticsymcount = 0;
412 cv_base = PRD(base, len);
413 if (!cv_base) {printf("Can't get full debug content, aborting\n");return;}
415 signature = cv_base;
417 printf(" CodeView Data\n");
419 printf(" Signature: %.4s\n", signature->Signature);
420 printf(" Filepos: 0x%08lX\n", signature->filepos);
422 if (memcmp(signature->Signature, "NB10", 4) == 0)
424 const struct {DWORD TimeStamp; DWORD Dunno; char Name[1];} *pdb_data;
425 pdb_data = (const void *)(signature + 1);
427 printf(" TimeStamp: %08X (%s)\n",
428 pdb_data->TimeStamp, get_time_str(pdb_data->TimeStamp));
429 printf(" Dunno: %08X\n", pdb_data->Dunno);
430 printf(" Filename: %s\n", pdb_data->Name);
431 return;
434 if (memcmp(signature->Signature, "NB09", 4) != 0 && memcmp(signature->Signature, "NB11", 4) != 0)
436 printf("Unsupported signature, aborting\n");
437 return;
440 dirHeader = PRD(Offset(cv_base) + signature->filepos, sizeof(OMFDirHeader));
441 if (!dirHeader) {printf("Can't get debug header, aborting\n"); return;}
443 printf(" Size of header: 0x%4X\n", dirHeader->cbDirHeader);
444 printf(" Size per entry: 0x%4X\n", dirHeader->cbDirEntry);
445 printf(" # of entries: 0x%8lX (%ld)\n", dirHeader->cDir, dirHeader->cDir);
446 printf(" Offset to NextDir: 0x%8lX\n", dirHeader->lfoNextDir);
447 printf(" Flags: 0x%8lX\n", dirHeader->flags);
449 if (!dirHeader->cDir) return;
451 dirEntry = PRD(Offset(dirHeader + 1), sizeof(OMFDirEntry) * dirHeader->cDir);
452 if (!dirEntry) {printf("Can't get DirEntry array, aborting\n");return;}
454 for (i = 0; i < dirHeader->cDir; i++)
456 switch (dirEntry[i].SubSection)
458 case sstModule: modulecount++; break;
459 case sstAlignSym: alignsymcount++; break;
460 case sstSrcModule: srcmodulecount++; break;
461 case sstLibraries: librariescount++; break;
462 case sstGlobalSym: globalsymcount++; break;
463 case sstGlobalPub: globalpubcount++; break;
464 case sstGlobalTypes: globaltypescount++; break;
465 case sstSegMap: segmapcount++; break;
466 case sstFileIndex: fileindexcount++; break;
467 case sstStaticSym: staticsymcount++; break;
471 /* This one has to be > 0
473 printf ("\nFound: %d sstModule subsections\n", modulecount);
475 if (alignsymcount > 0) printf (" %d sstAlignSym subsections\n", alignsymcount);
476 if (srcmodulecount > 0) printf (" %d sstSrcModule subsections\n", srcmodulecount);
477 if (librariescount > 0) printf (" %d sstLibraries subsections\n", librariescount);
478 if (globalsymcount > 0) printf (" %d sstGlobalSym subsections\n", globalsymcount);
479 if (globalpubcount > 0) printf (" %d sstGlobalPub subsections\n", globalpubcount);
480 if (globaltypescount > 0) printf (" %d sstGlobalTypes subsections\n", globaltypescount);
481 if (segmapcount > 0) printf (" %d sstSegMap subsections\n", segmapcount);
482 if (fileindexcount > 0) printf (" %d sstFileIndex subsections\n", fileindexcount);
483 if (staticsymcount > 0) printf (" %d sstStaticSym subsections\n", staticsymcount);
485 dump_codeview_all_modules(dirHeader);
488 static const char *get_coff_name( const IMAGE_SYMBOL *coff_sym, const char *coff_strtab )
490 static char namebuff[9];
491 const char* nampnt;
493 if( coff_sym->N.Name.Short )
495 memcpy(namebuff, coff_sym->N.ShortName, 8);
496 namebuff[8] = '\0';
497 nampnt = &namebuff[0];
499 else
501 nampnt = coff_strtab + coff_sym->N.Name.Long;
504 if( nampnt[0] == '_' )
505 nampnt++;
506 return nampnt;
509 void dump_coff(unsigned long coffbase, unsigned long len, const void* pmt)
511 const IMAGE_COFF_SYMBOLS_HEADER *coff = (const IMAGE_COFF_SYMBOLS_HEADER *)PRD(coffbase, len);
512 const IMAGE_SYMBOL *coff_sym;
513 const IMAGE_SYMBOL *coff_symbols =
514 (const IMAGE_SYMBOL *) ((const char *)coff + coff->LvaToFirstSymbol);
515 const char *coff_strtab = (const char *) (coff_symbols + coff->NumberOfSymbols);
516 const IMAGE_SECTION_HEADER *sectHead = pmt;
517 unsigned int i;
518 const char *nampnt;
519 int naux;
521 printf("\nDebug table: COFF format. modbase %p, coffbase %p\n", PRD(0, 0), coff);
522 printf(" ID | seg:offs [ abs ] | symbol/function name\n");
523 for(i=0; i < coff->NumberOfSymbols; i++ )
525 coff_sym = coff_symbols + i;
526 naux = coff_sym->NumberOfAuxSymbols;
528 if( coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE )
530 printf("file %s\n", (const char *) (coff_sym + 1));
531 i += naux;
532 continue;
535 if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC)
536 && (naux == 0)
537 && (coff_sym->SectionNumber == 1) )
539 DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress;
541 * This is a normal static function when naux == 0.
542 * Just register it. The current file is the correct
543 * one in this instance.
545 nampnt = get_coff_name( coff_sym, coff_strtab );
547 printf("%05d | %02d:%08x [%08x] | %s\n", i, coff_sym->SectionNumber - 1, coff_sym->Value - base, coff_sym->Value, nampnt);
548 i += naux;
549 continue;
552 if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
553 && ISFCN(coff_sym->Type)
554 && (coff_sym->SectionNumber > 0) )
556 DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress;
558 nampnt = get_coff_name( coff_sym, coff_strtab );
560 /* FIXME: add code to find out the file this symbol belongs to,
561 * see winedbg */
562 printf("%05d | %02d:%08x [%08x] | %s\n", i, coff_sym->SectionNumber - 1, coff_sym->Value - base, coff_sym->Value, nampnt);
563 i += naux;
564 continue;
568 * For now, skip past the aux entries.
570 i += naux;
575 void dump_codeview(unsigned long base, unsigned long len)
577 dump_codeview_headers(base, len);
580 void dump_frame_pointer_omission(unsigned long base, unsigned long len)
582 /* FPO is used to describe nonstandard stack frames */
583 printf("FIXME: FPO (frame pointer omission) debug symbol dumping not implemented yet.\n");
586 struct stab_nlist
588 union
590 char* n_name;
591 struct stab_nlist* n_next;
592 long n_strx;
593 } n_un;
594 unsigned char n_type;
595 char n_other;
596 short n_desc;
597 unsigned long n_value;
600 static const char* stabs_defs[] = {
601 NULL,NULL,NULL,NULL, /* 00 */
602 NULL,NULL,NULL,NULL, /* 08 */
603 NULL,NULL,NULL,NULL, /* 10 */
604 NULL,NULL,NULL,NULL, /* 18 */
605 "GSYM","FNAME","FUN","STSYM", /* 20 */
606 "LCSYM","MAIN","ROSYM","PC", /* 28 */
607 NULL,"NSYMS","NOMAP",NULL, /* 30 */
608 "OBJ",NULL,"OPT",NULL, /* 38 */
609 "RSYM","M2C","SLINE","DSLINE", /* 40 */
610 "BSLINE","DEFD","FLINE",NULL, /* 48 */
611 "EHDECL",NULL,"CATCH",NULL, /* 50 */
612 NULL,NULL,NULL,NULL, /* 58 */
613 "SSYM","ENDM","SO",NULL, /* 60 */
614 NULL,NULL,NULL,NULL, /* 68 */
615 NULL,NULL,NULL,NULL, /* 70 */
616 NULL,NULL,NULL,NULL, /* 78 */
617 "LSYM","BINCL","SOL",NULL, /* 80 */
618 NULL,NULL,NULL,NULL, /* 88 */
619 NULL,NULL,NULL,NULL, /* 90 */
620 NULL,NULL,NULL,NULL, /* 98 */
621 "PSYM","EINCL","ENTRY",NULL, /* a0 */
622 NULL,NULL,NULL,NULL, /* a8 */
623 NULL,NULL,NULL,NULL, /* b0 */
624 NULL,NULL,NULL,NULL, /* b8 */
625 "LBRAC","EXCL","SCOPE",NULL, /* c0 */
626 NULL,NULL,NULL,NULL, /* c8 */
627 NULL,NULL,NULL,NULL, /* d0 */
628 NULL,NULL,NULL,NULL, /* d8 */
629 "RBRAC","BCOMM","ECOMM",NULL, /* e0 */
630 "ECOML","WITH",NULL,NULL, /* e8 */
631 "NBTEXT","NBDATA","NBBSS","NBSTS", /* f0 */
632 "NBLCS",NULL,NULL,NULL /* f8 */
635 void dump_stabs(const void* pv_stabs, unsigned szstabs, const char* stabstr, unsigned szstr)
637 int i;
638 int nstab;
639 const char* ptr;
640 char* stabbuff;
641 unsigned int stabbufflen;
642 const struct stab_nlist* stab_ptr = pv_stabs;
643 const char* strs_end;
644 char n_buffer[16];
646 nstab = szstabs / sizeof(struct stab_nlist);
647 strs_end = stabstr + szstr;
650 * Allocate a buffer into which we can build stab strings for cases
651 * where the stab is continued over multiple lines.
653 stabbufflen = 65536;
654 stabbuff = malloc(stabbufflen);
656 stabbuff[0] = '\0';
658 printf("#Sym n_type n_othr n_desc n_value n_strx String\n");
660 for (i = 0; i < nstab; i++, stab_ptr++)
662 ptr = stabstr + stab_ptr->n_un.n_strx;
663 if ((ptr > strs_end) || (ptr + strlen(ptr) > strs_end))
665 ptr = "[[*** bad string ***]]";
667 else if (ptr[strlen(ptr) - 1] == '\\')
670 * Indicates continuation. Append this to the buffer, and go onto the
671 * next record. Repeat the process until we find a stab without the
672 * '/' character, as this indicates we have the whole thing.
674 unsigned len = strlen(ptr);
675 if (strlen(stabbuff) + len > stabbufflen)
677 stabbufflen += 65536;
678 stabbuff = realloc(stabbuff, stabbufflen);
680 strncat(stabbuff, ptr, len - 1);
681 continue;
683 else if (stabbuff[0] != '\0')
685 strcat(stabbuff, ptr);
686 ptr = stabbuff;
688 if ((stab_ptr->n_type & 1) || !stabs_defs[stab_ptr->n_type / 2])
689 sprintf(n_buffer, "<0x%02x>", stab_ptr->n_type);
690 else
691 sprintf(n_buffer, "%-6s", stabs_defs[stab_ptr->n_type / 2]);
692 printf("%4d %s %-8x % 6d %-8lx %-6lx %s\n",
693 i, n_buffer, stab_ptr->n_other, stab_ptr->n_desc, stab_ptr->n_value,
694 stab_ptr->n_un.n_strx, ptr);
696 free(stabbuff);