widl: Output sizing information for arrays in the generated marshaling code.
[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  * 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.
12  *
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.
17  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
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>
43
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winedump.h"
47 #include "pe.h"
48 #include "cvinclude.h"
49
50 /*
51  * .DBG File Layout:
52  *
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[]
63  */
64
65 /*
66  * Descriptions:
67  *
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
86  */
87
88 /*
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
91  *
92  * IMAGE_SECTION_HEADER - number of entries determined by:
93  *    (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
94  *
95  * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
96  *    (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
97  *
98  * OMFDirEntry - number of entries determined by:
99  *    (OMFDirHeader.cDir)
100  */
101
102 extern IMAGE_NT_HEADERS*        PE_nt_headers;
103
104 static  void*           cv_base /* = 0 */;
105
106 static int dump_cv_sst_module(OMFDirEntry* omfde)
107 {
108     OMFModule*  module;
109     OMFSegDesc* segDesc;
110     int         i;
111
112     module = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFModule));
113     if (!module) {printf("Can't get the OMF-Module, aborting\n"); return FALSE;}
114
115     printf("    olvNumber:          %u\n", module->ovlNumber);
116     printf("    iLib:               %u\n", module->iLib);
117     printf("    cSeg:               %u\n", module->cSeg);
118     printf("    Style:              %c%c\n", module->Style[0], module->Style[1]);
119     printf("    Name:               %.*s\n",
120            *(BYTE*)((char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg),
121            (char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg + 1);
122
123     segDesc = PRD(Offset(module + 1), sizeof(OMFSegDesc) * module->cSeg);
124     if (!segDesc) {printf("Can't get the OMF-SegDesc, aborting\n"); return FALSE;}
125
126     for (i = 0; i < module->cSeg; i++)
127     {
128         printf ("      segment #%2d: offset = [0x%8lx], size = [0x%8lx]\n",
129                 segDesc->Seg, segDesc->Off, segDesc->cbSeg);
130         segDesc++;
131     }
132     return TRUE;
133 }
134
135 static int dump_cv_sst_global_pub(OMFDirEntry* omfde)
136 {
137     long        fileoffset;
138     OMFSymHash* header;
139     BYTE*       symbols;
140     BYTE*       curpos;
141     PUBSYM32*   sym;
142     unsigned    symlen;
143     int         recordlen;
144     char        nametmp[256];
145
146     fileoffset = Offset(cv_base) + omfde->lfo;
147     printf ("    GlobalPub section starts at file offset 0x%lx\n", fileoffset);
148     printf ("    Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash));
149
150     printf ("\n                           ----- Begin Symbol Table -----\n");
151     printf ("      (type)      (symbol name)                 (offset)      (len) (seg) (ind)\n");
152
153     header = PRD(fileoffset, sizeof(OMFSymHash));
154     if (!header) {printf("Can't get OMF-SymHash, aborting\n");return FALSE;}
155
156     symbols = PRD(fileoffset + sizeof(OMFSymHash), header->cbSymbol);
157     if (!symbols) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;}
158
159     /* We don't know how many symbols are in this block of memory...only what
160      * the total size of the block is.  Because the symbol's name is tacked
161      * on to the end of the PUBSYM32 struct, each symbol may take up a different
162      * # of bytes.  This makes it harder to parse through the symbol table,
163      * since we won't know the exact location of the following symbol until we've
164      * already parsed the current one.
165      */
166     for (curpos = symbols; curpos < symbols + header->cbSymbol; curpos += recordlen)
167     {
168         /* Point to the next PUBSYM32 in the table.
169          */
170         sym = (PUBSYM32*)curpos;
171
172         if (sym->reclen < sizeof(PUBSYM32)) break;
173
174         symlen = sym->reclen - sizeof(PUBSYM32) + 1;
175         if (symlen > sizeof(nametmp)) {printf("\nsqueeze%d\n", symlen);symlen = sizeof(nametmp) - 1;}
176
177         memcpy(nametmp, curpos + sizeof (PUBSYM32) + 1, symlen);
178         nametmp[symlen] = '\0';
179
180         printf ("      0x%04x  %-30.30s  [0x%8lx]  [0x%4x]  %d     %ld\n",
181                 sym->rectyp, nametmp, sym->off, sym->reclen, sym->seg, sym->typind);
182
183         /* The entire record is null-padded to the nearest 4-byte
184          * boundary, so we must do a little extra math to keep things straight.
185          */
186         recordlen = (sym->reclen + 3) & ~3;
187     }
188
189     return TRUE;
190 }
191
192 static int dump_cv_sst_global_sym(OMFDirEntry* omfde)
193 {
194     /*** NOT YET IMPLEMENTED ***/
195     return TRUE;
196 }
197
198 static int dump_cv_sst_static_sym(OMFDirEntry* omfde)
199 {
200     /*** NOT YET IMPLEMENTED ***/
201     return TRUE;
202 }
203
204 static int dump_cv_sst_libraries(OMFDirEntry* omfde)
205 {
206     /*** NOT YET IMPLEMENTED ***/
207     return TRUE;
208 }
209
210 static int dump_cv_sst_global_types(OMFDirEntry* omfde)
211 {
212     /*** NOT YET IMPLEMENTED ***/
213     return TRUE;
214 }
215
216 static int dump_cv_sst_seg_map(OMFDirEntry* omfde)
217 {
218     OMFSegMap*          segMap;
219     OMFSegMapDesc*      segMapDesc;
220     int         i;
221
222     segMap = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFSegMap));
223     if (!segMap) {printf("Can't get SegMap, aborting\n");return FALSE;}
224
225     printf("    cSeg:          %u\n", segMap->cSeg);
226     printf("    cSegLog:       %u\n", segMap->cSegLog);
227
228     segMapDesc = PRD(Offset(segMap + 1), segMap->cSeg * sizeof(OMFSegDesc));
229     if (!segMapDesc) {printf("Can't get SegDescr array, aborting\n");return FALSE;}
230
231     for (i = 0; i < segMap->cSeg; i++)
232     {
233         printf("    SegDescr #%2d\n", i + 1);
234         printf("      flags:         %04X\n", segMapDesc[i].flags);
235         printf("      ovl:           %u\n", segMapDesc[i].ovl);
236         printf("      group:         %u\n", segMapDesc[i].group);
237         printf("      frame:         %u\n", segMapDesc[i].frame);
238         printf("      iSegName:      %u\n", segMapDesc[i].iSegName);
239         printf("      iClassName:    %u\n", segMapDesc[i].iClassName);
240         printf("      offset:        %lu\n", segMapDesc[i].offset);
241         printf("      cbSeg:         %lu\n", segMapDesc[i].cbSeg);
242     }
243
244     return TRUE;
245 }
246
247 static int dump_cv_sst_file_index(OMFDirEntry* omfde)
248 {
249     /*** NOT YET IMPLEMENTED ***/
250     return TRUE;
251 }
252
253 static int dump_cv_sst_src_module(OMFDirEntry* omfde)
254 {
255     int                 i, j;
256     BYTE*               rawdata;
257     unsigned long*      seg_info_dw;
258     unsigned short*     seg_info_w;
259     unsigned            ofs;
260     OMFSourceModule*    sourceModule;
261     OMFSourceFile*      sourceFile;
262     OMFSourceLine*      sourceLine;
263
264     rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb);
265     if (!rawdata) {printf("Can't get srcModule subsection details, aborting\n");return FALSE;}
266
267     /* FIXME: check ptr validity */
268     sourceModule = (void*)rawdata;
269     printf ("    Module table: Found %d file(s) and %d segment(s)\n",
270             sourceModule->cFile, sourceModule->cSeg);
271     for (i = 0; i < sourceModule->cFile; i++)
272     {
273         printf ("      File #%2d begins at an offset of 0x%lx in this section\n",
274                 i + 1, sourceModule->baseSrcFile[i]);
275     }
276
277     /* FIXME: check ptr validity */
278     seg_info_dw = (void*)((char*)(sourceModule + 1) +
279                           sizeof(unsigned long) * (sourceModule->cFile - 1));
280     seg_info_w = (unsigned short*)(&seg_info_dw[sourceModule->cSeg * 2]);
281     for (i = 0; i <  sourceModule->cSeg; i++)
282     {
283         printf ("      Segment #%2d start = 0x%lx, end = 0x%lx, seg index = %u\n",
284                 i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1],
285                 seg_info_w[i]);
286     }
287     ofs = sizeof(OMFSourceModule) + sizeof(unsigned long) * (sourceModule->cFile - 1) +
288         sourceModule->cSeg * (2 * sizeof(unsigned long) + sizeof(unsigned short));
289     ofs = (ofs + 3) & ~3;
290
291     /* the OMFSourceFile is quite unpleasant to use:
292      * we have first:
293      *  unsigned short  number of segments
294      *  unsigned short  reservered
295      *  unsigned long   baseSrcLn[# segments]
296      *  unsigned long   offset[2 * #segments]
297      *                          odd indices are start offsets
298      *                          even indices are end offsets
299      *  unsigned char   string length for file name
300      *  char            file name (length is previous field)
301      */
302     /* FIXME: check ptr validity */
303     sourceFile = (void*)(rawdata + ofs);
304     seg_info_dw = (void*)((char*)sourceFile + 2 * sizeof(unsigned short) +
305                           sourceFile->cSeg * sizeof(unsigned long));
306
307     ofs += 2 * sizeof(unsigned short) + 3 * sourceFile->cSeg * sizeof(unsigned long);
308
309     printf("    File table: %.*s\n",
310            *(BYTE*)((char*)sourceModule + ofs), (char*)sourceModule + ofs + 1);
311
312     for (i = 0; i < sourceFile->cSeg; i++)
313     {
314         printf ("      Segment #%2d start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
315                 i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], sourceFile->baseSrcLn[i]);
316     }
317     /* add file name length */
318     ofs += *(BYTE*)((char*)sourceModule + ofs) + 1;
319     ofs = (ofs + 3) & ~3;
320
321     for (i = 0; i < sourceModule->cSeg; i++)
322     {
323         sourceLine = (void*)(rawdata + ofs);
324         seg_info_dw = (void*)((char*)sourceLine + 2 * sizeof(unsigned short));
325         seg_info_w = (void*)(&seg_info_dw[sourceLine->cLnOff]);
326
327         printf ("    Line table #%2d: Found %d line numbers for segment index %d\n",
328                 i, sourceLine->cLnOff, sourceLine->Seg);
329
330         for (j = 0; j < sourceLine->cLnOff; j++)
331         {
332             printf ("      Pair #%2d: offset = [0x%8lx], linenumber = %d\n",
333                     j + 1, seg_info_dw[j], seg_info_w[j]);
334         }
335         ofs += 2 * sizeof(unsigned short) +
336             sourceLine->cLnOff * (sizeof(unsigned long) + sizeof(unsigned short));
337         ofs = (ofs + 3) & ~3;
338     }
339
340     return TRUE;
341 }
342
343 static int dump_cv_sst_align_sym(OMFDirEntry* omfde)
344 {
345     /*** NOT YET IMPLEMENTED ***/
346
347     return TRUE;
348 }
349
350 static void dump_codeview_all_modules(OMFDirHeader *omfdh)
351 {
352     unsigned            i;
353     OMFDirEntry        *dirEntry;
354     const char*         str;
355
356     if (!omfdh || !omfdh->cDir) return;
357
358     dirEntry = PRD(Offset(omfdh + 1), omfdh->cDir * sizeof(OMFDirEntry));
359     if (!dirEntry) {printf("Can't read DirEntry array, aborting\n"); return;}
360
361     for (i = 0; i < omfdh->cDir; i++)
362     {
363         switch (dirEntry[i].SubSection)
364         {
365         case sstModule:         str = "sstModule";      break;
366         case sstAlignSym:       str = "sstAlignSym";    break;
367         case sstSrcModule:      str = "sstSrcModule";   break;
368         case sstLibraries:      str = "sstLibraries";   break;
369         case sstGlobalSym:      str = "sstGlobalSym";   break;
370         case sstGlobalPub:      str = "sstGlobalPub";   break;
371         case sstGlobalTypes:    str = "sstGlobalTypes"; break;
372         case sstSegMap:         str = "sstSegMap";      break;
373         case sstFileIndex:      str = "sstFileIndex";   break;
374         case sstStaticSym:      str = "sstStaticSym";   break;
375         default:                str = "<undefined>";    break;
376         }
377         printf("Module #%2d (%p)\n", i + 1, &dirEntry[i]);
378         printf("  SubSection:            %04X (%s)\n", dirEntry[i].SubSection, str);
379         printf("  iMod:                  %d\n", dirEntry[i].iMod);
380         printf("  lfo:                   %ld\n", dirEntry[i].lfo);
381         printf("  cb:                    %lu\n", dirEntry[i].cb);
382
383         switch (dirEntry[i].SubSection)
384         {
385         case sstModule:         dump_cv_sst_module(&dirEntry[i]);       break;
386         case sstAlignSym:       dump_cv_sst_align_sym(&dirEntry[i]);    break;
387         case sstSrcModule:      dump_cv_sst_src_module(&dirEntry[i]);   break;
388         case sstLibraries:      dump_cv_sst_libraries(&dirEntry[i]);    break;
389         case sstGlobalSym:      dump_cv_sst_global_sym(&dirEntry[i]);   break;
390         case sstGlobalPub:      dump_cv_sst_global_pub(&dirEntry[i]);   break;
391         case sstGlobalTypes:    dump_cv_sst_global_types(&dirEntry[i]); break;
392         case sstSegMap:         dump_cv_sst_seg_map(&dirEntry[i]);      break;
393         case sstFileIndex:      dump_cv_sst_file_index(&dirEntry[i]);   break;
394         case sstStaticSym:      dump_cv_sst_static_sym(&dirEntry[i]);   break;
395         default:                printf("unsupported type %x\n", dirEntry[i].SubSection); break;
396         }
397         printf("\n");
398     }
399
400     return;
401 }
402
403 static void dump_codeview_headers(unsigned long base, unsigned long len)
404 {
405     OMFDirHeader        *dirHeader;
406     OMFSignature        *signature;
407     OMFDirEntry         *dirEntry;
408     unsigned            i;
409     int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0;
410     int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0;
411     int segmapcount = 0, fileindexcount = 0, staticsymcount = 0;
412
413     cv_base = PRD(base, len);
414     if (!cv_base) {printf("Can't get full debug content, aborting\n");return;}
415
416     signature = cv_base;
417
418     printf("    CodeView Data\n");
419
420     printf("      Signature:         %.4s\n", signature->Signature);
421     printf("      Filepos:           0x%08lX\n", signature->filepos);
422
423     if (memcmp(signature->Signature, "NB10", 4) == 0)
424     {
425         struct {DWORD TimeStamp; DWORD  Dunno; char Name[1];}* pdb_data;
426         pdb_data = (void*)(signature + 1);
427
428         printf("        TimeStamp:            %08lX (%s)\n",
429                pdb_data->TimeStamp, get_time_str(pdb_data->TimeStamp));
430         printf("        Dunno:                %08lX\n", pdb_data->Dunno);
431         printf("        Filename:             %s\n", pdb_data->Name);
432         return;
433     }
434
435     if (memcmp(signature->Signature, "NB09", 4) != 0 && memcmp(signature->Signature, "NB11", 4) != 0)
436     {
437         printf("Unsupported signature, aborting\n");
438         return;
439     }
440
441     dirHeader = PRD(Offset(cv_base) + signature->filepos, sizeof(OMFDirHeader));
442     if (!dirHeader) {printf("Can't get debug header, aborting\n"); return;}
443
444     printf("      Size of header:    0x%4X\n", dirHeader->cbDirHeader);
445     printf("      Size per entry:    0x%4X\n", dirHeader->cbDirEntry);
446     printf("      # of entries:      0x%8lX (%ld)\n", dirHeader->cDir, dirHeader->cDir);
447     printf("      Offset to NextDir: 0x%8lX\n", dirHeader->lfoNextDir);
448     printf("      Flags:             0x%8lX\n", dirHeader->flags);
449
450     if (!dirHeader->cDir) return;
451
452     dirEntry = PRD(Offset(dirHeader + 1), sizeof(OMFDirEntry) * dirHeader->cDir);
453     if (!dirEntry) {printf("Can't get DirEntry array, aborting\n");return;}
454
455     for (i = 0; i < dirHeader->cDir; i++)
456     {
457         switch (dirEntry[i].SubSection)
458         {
459         case sstModule:         modulecount++;          break;
460         case sstAlignSym:       alignsymcount++;        break;
461         case sstSrcModule:      srcmodulecount++;       break;
462         case sstLibraries:      librariescount++;       break;
463         case sstGlobalSym:      globalsymcount++;       break;
464         case sstGlobalPub:      globalpubcount++;       break;
465         case sstGlobalTypes:    globaltypescount++;     break;
466         case sstSegMap:         segmapcount++;          break;
467         case sstFileIndex:      fileindexcount++;       break;
468         case sstStaticSym:      staticsymcount++;       break;
469         }
470     }
471
472     /* This one has to be > 0
473      */
474     printf ("\nFound: %d sstModule subsections\n", modulecount);
475
476     if (alignsymcount > 0)    printf ("       %d sstAlignSym subsections\n", alignsymcount);
477     if (srcmodulecount > 0)   printf ("       %d sstSrcModule subsections\n", srcmodulecount);
478     if (librariescount > 0)   printf ("       %d sstLibraries subsections\n", librariescount);
479     if (globalsymcount > 0)   printf ("       %d sstGlobalSym subsections\n", globalsymcount);
480     if (globalpubcount > 0)   printf ("       %d sstGlobalPub subsections\n", globalpubcount);
481     if (globaltypescount > 0) printf ("       %d sstGlobalTypes subsections\n", globaltypescount);
482     if (segmapcount > 0)      printf ("       %d sstSegMap subsections\n", segmapcount);
483     if (fileindexcount > 0)   printf ("       %d sstFileIndex subsections\n", fileindexcount);
484     if (staticsymcount > 0)   printf ("       %d sstStaticSym subsections\n", staticsymcount);
485
486     dump_codeview_all_modules(dirHeader);
487 }
488
489 static const char*   get_coff_name( PIMAGE_SYMBOL coff_sym, const char* coff_strtab )
490 {
491    static       char    namebuff[9];
492    const char*          nampnt;
493
494    if( coff_sym->N.Name.Short )
495       {
496          memcpy(namebuff, coff_sym->N.ShortName, 8);
497          namebuff[8] = '\0';
498          nampnt = &namebuff[0];
499       }
500    else
501       {
502          nampnt = coff_strtab + coff_sym->N.Name.Long;
503       }
504
505    if( nampnt[0] == '_' )
506       nampnt++;
507    return nampnt;
508 }
509
510 void    dump_coff(unsigned long coffbase, unsigned long len, void* pmt)
511 {
512     PIMAGE_COFF_SYMBOLS_HEADER coff;
513     PIMAGE_SYMBOL                 coff_sym;
514     PIMAGE_SYMBOL                 coff_symbols;
515     PIMAGE_LINENUMBER             coff_linetab;
516     char                        * coff_strtab;
517     IMAGE_SECTION_HEADER        * sectHead = pmt;
518     unsigned int i;
519     const char                  * nampnt;
520     int naux;
521
522     coff = (PIMAGE_COFF_SYMBOLS_HEADER)PRD(coffbase, len);
523
524     coff_symbols = (PIMAGE_SYMBOL) ((char *)coff + coff->LvaToFirstSymbol);
525     coff_linetab = (PIMAGE_LINENUMBER) ((char *)coff + coff->LvaToFirstLinenumber);
526     coff_strtab = (char *) (coff_symbols + coff->NumberOfSymbols);
527
528     printf("\nDebug table: COFF format. modbase %p, coffbase %p\n", PRD(0, 0), coff);
529     printf("  ID  | seg:offs    [  abs   ] | symbol/function name\n");
530     for(i=0; i < coff->NumberOfSymbols; i++ )
531     {
532       coff_sym = coff_symbols + i;
533       naux = coff_sym->NumberOfAuxSymbols;
534
535       if( coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE )
536         {
537           printf("file %s\n", (char *) (coff_sym + 1));
538           i += naux;
539           continue;
540         }
541
542       if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC)
543           && (naux == 0)
544           && (coff_sym->SectionNumber == 1) )
545         {
546           DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress;
547           /*
548            * This is a normal static function when naux == 0.
549            * Just register it.  The current file is the correct
550            * one in this instance.
551            */
552           nampnt = get_coff_name( coff_sym, coff_strtab );
553
554           printf("%05d | %02d:%08lx [%08lx] | %s\n", i, coff_sym->SectionNumber - 1, coff_sym->Value - base, coff_sym->Value, nampnt);
555           i += naux;
556           continue;
557         }
558
559       if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
560           && ISFCN(coff_sym->Type)
561           && (coff_sym->SectionNumber > 0) )
562         {
563           DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress;
564
565           nampnt = get_coff_name( coff_sym, coff_strtab );
566
567           /* FIXME: add code to find out the file this symbol belongs to,
568            * see winedbg */
569           printf("%05d | %02d:%08lx [%08lx] | %s\n", i, coff_sym->SectionNumber - 1, coff_sym->Value - base, coff_sym->Value, nampnt);
570           i += naux;
571           continue;
572         }
573
574       /*
575        * For now, skip past the aux entries.
576        */
577       i += naux;
578
579     }
580 }
581
582 void    dump_codeview(unsigned long base, unsigned long len)
583 {
584     dump_codeview_headers(base, len);
585 }
586
587 void    dump_frame_pointer_omission(unsigned long base, unsigned long len)
588 {
589         /* FPO is used to describe nonstandard stack frames */
590         printf("FIXME: FPO (frame pointer omission) debug symbol dumping not implemented yet.\n");
591 }