winedump patch: add COFF dumping

Andreas Mohr andi at rhlx01.fht-esslingen.de
Tue Sep 10 05:53:52 CDT 2002


Hi all,

I needed COFF debug symbol dumping, so I implemented it :)
(well, "implemented" meaning: shamelessly stolen from winedbg)

- implement dumping of COFF debug symbol table
- FIX WINEDUMP SYNTAX DESCRIPTION

  Grrrrr, who the h*ll changed syntax without documenting the changes
  again !?!?!?!?!?
  Not even the bloody invocation *example* worked !!!
  (not to mention that it failed with such a bloody error message as
  "Unrecognized option")
  This is p*** p***.
  And who said that OSS development method was superiour to commercial
  software development again ? Get a life ! :-\
  (just joking, but sometimes I'm really drowning in doubts)

- spelling fixes

Sounds like winedump is slowly starting to become better than any of the
other PE dumping tools, given the dumping functionality we now have,
though :)

Oh, and yes, this patch is inline. I just hope vim did the right thing when
reading in the patch file...

Greetings,

the cosmetics police ;-)

Index: tools/winedump/README
===================================================================
RCS file: /home/wine/wine/tools/winedump/README,v
retrieving revision 1.2
diff -u -r1.2 README
--- tools/winedump/README	29 May 2002 19:09:54 -0000	1.2
+++ tools/winedump/README	10 Sep 2002 10:44:08 -0000
@@ -59,7 +59,7 @@
 - demangling MSVC C++ symbol names
 - dumping the 'PE' files contents
 
-Usage: winedump [-h sym <sym> spec <dll> dump <dll>] [mode options]
+Usage: winedump [-h | sym <sym> | spec <dll> | dump <dll>] [mode options]
 When used in -h mode
    -h           Display this help message
 When used in sym mode
@@ -472,7 +472,7 @@
 The output should be piped through 'sort' and 'uniq' to remove multiple
 declarations, e.g:
 
-winedump -d foo -c -I "inc/*.h" -v | grep FIXME | sort | uniq > fixup.h
+winedump foo -c -I "inc/*.h" -v | grep FIXME | sort | uniq > fixup.h
 
 By adding '#include "fixup.h"' to foobar_dll.h your compile errors will be
 greatly reduced.
@@ -582,10 +582,13 @@
 Dumping
 -------
 
-Another tool might be helpful digging into a 32bit DLL (and any PE image file):
+Another tool might be helpful for digging into a 32bit DLL (and any PE image file):
 pedump.
 
 Usage:
+winedump [-h | sym <sym> | spec <dll> | dump <dll> ] [switches]
+
+winedump switches:
    -h           Display this help message
    -d <dll>     Use dll for input file and generate implementation code
    -C           Turns on symbol demangling
@@ -593,13 +596,13 @@
    -j dir_name  Dumps only the content of directory dir_name (import, export, debug)
    -x           Dumps everything
 
-The basic usage, to look everything in a file is:
-winedump dump -d mydll.dll -x
+The basic usage, to look at everything in a file is:
+winedump dump mydll.dll -x
 
 It'll print any available information on the file. This information can be splitted
 into sub-categories:
-- file hedaers (request by -f or -x) are made of the standard PE header structures, 
+- file headers (request by -f or -x) are made of the standard PE header structures, 
   plus the COFF sections
-- directories: you can print them one after the other using the -j switch. Currently, 
-  only the import, export and debug directories are implemented.
+- directories: you can print them one after the other using the -j switch.
+  Currently, only the import, export and debug directories are implemented.
 - -x displays the file headers and any available directory.
Index: tools/winedump/debug.c
===================================================================
RCS file: /home/wine/wine/tools/winedump/debug.c,v
retrieving revision 1.6
diff -u -r1.6 debug.c
--- tools/winedump/debug.c	17 Aug 2002 18:28:43 -0000	1.6
+++ tools/winedump/debug.c	10 Sep 2002 10:44:08 -0000
@@ -97,6 +97,10 @@
  *    (OMFDirHeader.cDir)
  */
 
+extern void			*PE_base;
+
+extern IMAGE_NT_HEADERS*        PE_nt_headers;
+
 static	void*		cv_base /* = 0 */;
 
 static int dump_cv_sst_module(OMFDirEntry* omfde)
@@ -482,7 +486,106 @@
     dump_codeview_all_modules(dirHeader);
 }
 
+static const char*   get_coff_name( PIMAGE_SYMBOL coff_sym, const char* coff_strtab )
+{
+   static       char    namebuff[9];
+   const char*          nampnt;
+
+   if( coff_sym->N.Name.Short )
+      {
+         memcpy(namebuff, coff_sym->N.ShortName, 8);
+         namebuff[8] = '\0';
+         nampnt = &namebuff[0];
+      }
+   else
+      {
+         nampnt = coff_strtab + coff_sym->N.Name.Long;
+      }
+
+   if( nampnt[0] == '_' )
+      nampnt++;
+   return nampnt;
+}
+
+void	dump_coff(unsigned long coffbase, unsigned long len)
+{
+    PIMAGE_COFF_SYMBOLS_HEADER coff;
+    PIMAGE_SYMBOL                 coff_sym;
+    PIMAGE_SYMBOL                 coff_symbols;
+    PIMAGE_LINENUMBER             coff_linetab;
+    char                        * coff_strtab;
+    IMAGE_SECTION_HEADER *sectHead = (IMAGE_SECTION_HEADER*)((char*)PE_nt_headers + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader);
+    unsigned int i;
+    const char                  * nampnt;
+    int naux;
+
+    coff = (PIMAGE_COFF_SYMBOLS_HEADER)PRD(coffbase, len);
+
+    coff_symbols = (PIMAGE_SYMBOL) ((unsigned int) coff + coff->LvaToFirstSymbol);
+    coff_linetab = (PIMAGE_LINENUMBER) ((unsigned int) coff + coff->LvaToFirstLinenumber);
+    coff_strtab = (char *) (coff_symbols + coff->NumberOfSymbols);
+
+    printf("\nDebug table: COFF format. modbase %p, coffbase %p\n", PE_base, coff);
+    printf("  ID  | seg:offs    [  abs   ] | symbol/function name\n");
+  for(i=0; i < coff->NumberOfSymbols; i++ )
+    {
+      coff_sym = coff_symbols + i;
+      naux = coff_sym->NumberOfAuxSymbols;
+
+      if( coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE )
+        {
+	  printf("file %s\n", (char *) (coff_sym + 1));
+          i += naux;
+          continue;
+        }
+
+      if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC)
+          && (naux == 0)
+          && (coff_sym->SectionNumber == 1) )
+        {
+          DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress;
+          /*
+           * This is a normal static function when naux == 0.
+           * Just register it.  The current file is the correct
+           * one in this instance.
+           */
+          nampnt = get_coff_name( coff_sym, coff_strtab );
+
+	  printf("%05d | %02d:%08lx [%08lx] | %s\n", i, coff_sym->SectionNumber - 1, coff_sym->Value - base, coff_sym->Value, nampnt);
+	  i += naux;
+	  continue;
+	}
+
+      if(    (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
+          && ISFCN(coff_sym->Type)
+          && (coff_sym->SectionNumber > 0) )
+        {
+          DWORD base = sectHead[coff_sym->SectionNumber - 1].VirtualAddress;
+
+          nampnt = get_coff_name( coff_sym, coff_strtab );
+
+	  /* FIXME: add code to find out the file this symbol belongs to,
+	   * see winedbg */
+	  printf("%05d | %02d:%08lx [%08lx] | %s\n", i, coff_sym->SectionNumber - 1, coff_sym->Value - base, coff_sym->Value, nampnt);
+          i += naux;
+          continue;
+	}
+
+      /*
+       * For now, skip past the aux entries.
+       */
+      i += naux;
+
+    }
+}
+
 void	dump_codeview(unsigned long base, unsigned long len)
 {
     dump_codeview_headers(base, len);
+}
+
+void	dump_frame_pointer_omission(unsigned long base, unsigned long len)
+{
+	/* FPO is used to describe nonstandard stack frames */
+	printf("FIXME: FPO (frame pointer omission) debug symbol dumping not implemented yet.\n");
 }
Index: tools/winedump/pe.c
===================================================================
RCS file: /home/wine/wine/tools/winedump/pe.c,v
retrieving revision 1.16
diff -u -r1.16 pe.c
--- tools/winedump/pe.c	26 Aug 2002 21:47:41 -0000	1.16
+++ tools/winedump/pe.c	10 Sep 2002 10:44:09 -0000
@@ -46,9 +46,9 @@
 # define O_BINARY 0
 #endif
 
-static void*			base;
-static unsigned long		total_len;
-static IMAGE_NT_HEADERS*	nt_headers;
+void*			PE_base;
+unsigned long		PE_total_len;
+IMAGE_NT_HEADERS*	PE_nt_headers;
 
 enum FileSig {SIG_UNKNOWN, SIG_DOS, SIG_PE, SIG_DBG};
 
@@ -85,14 +85,14 @@
 
 void*	PRD(unsigned long prd, unsigned long len)
 {
-    return (prd + len > total_len) ? NULL : (char*)base + prd;
+    return (prd + len > PE_total_len) ? NULL : (char*)PE_base + prd;
 }
 
 unsigned long Offset(void* ptr)
 {
-    if (ptr < base) {printf("<<<<<ptr below\n");return 0;}
-    if ((char *)ptr >= (char*)base + total_len) {printf("<<<<<ptr above\n");return 0;}
-    return (char*)ptr - (char*)base;
+    if (ptr < PE_base) {printf("<<<<<ptr below\n");return 0;}
+    if ((char *)ptr >= (char*)PE_base + PE_total_len) {printf("<<<<<ptr above\n");return 0;}
+    return (char*)ptr - (char*)PE_base;
 }
 
 void*	RVA(unsigned long rva, unsigned long len)
@@ -100,13 +100,13 @@
     IMAGE_SECTION_HEADER*	sectHead;
     int				i;
 
-    sectHead = (IMAGE_SECTION_HEADER*)((char*)nt_headers + sizeof(DWORD) +
+    sectHead = (IMAGE_SECTION_HEADER*)((char*)PE_nt_headers + sizeof(DWORD) +
 				       sizeof(IMAGE_FILE_HEADER) +
-				       nt_headers->FileHeader.SizeOfOptionalHeader);
+				       PE_nt_headers->FileHeader.SizeOfOptionalHeader);
 
     if (rva == 0) return NULL;
 
-    for (i = nt_headers->FileHeader.NumberOfSections - 1; i >= 0; i--)
+    for (i = PE_nt_headers->FileHeader.NumberOfSections - 1; i >= 0; i--)
     {
         if (sectHead[i].VirtualAddress <= rva &&
             rva + len <= (DWORD)sectHead[i].VirtualAddress + sectHead[i].SizeOfRawData)
@@ -125,10 +125,10 @@
 
 static	void*	get_dir(unsigned idx)
 {
-    if (idx >= nt_headers->OptionalHeader.NumberOfRvaAndSizes)
+    if (idx >= PE_nt_headers->OptionalHeader.NumberOfRvaAndSizes)
 	return NULL;
-    return RVA(nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress,
-	       nt_headers->OptionalHeader.DataDirectory[idx].Size);
+    return RVA(PE_nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress,
+	       PE_nt_headers->OptionalHeader.DataDirectory[idx].Size);
 }
 
 static const char*	DirectoryNames[16] = {
@@ -146,7 +146,7 @@
     unsigned			i;
 
     printf("File Header\n");
-    fileHeader = &nt_headers->FileHeader;
+    fileHeader = &PE_nt_headers->FileHeader;
 
     printf("  Machine:                      %04X (%s)\n",
 	   fileHeader->Machine, get_machine_str(fileHeader->Machine));
@@ -175,7 +175,7 @@
 
     /* hope we have the right size */
     printf("Optional Header\n");
-    optionalHeader = &nt_headers->OptionalHeader;
+    optionalHeader = &PE_nt_headers->OptionalHeader;
     printf("  Magic                              0x%-4X         %u\n",
 	   optionalHeader->Magic, optionalHeader->Magic);
     printf("  linker version                     %u.%02u\n",
@@ -401,12 +401,12 @@
     unsigned			nb_imp, i;
 
     if (!importDesc)	return;
-    nb_imp = nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size /
+    nb_imp = PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size /
 	sizeof(*importDesc);
     if (!nb_imp) return;
 
     printf("Import Table size: %lu\n",
-	   nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size);/* FIXME */
+	   PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size);/* FIXME */
 
     for (i = 0; i < nb_imp - 1; i++) /* the last descr is set as 0 as a sentinel */
     {
@@ -495,11 +495,13 @@
     case IMAGE_DEBUG_TYPE_UNKNOWN:
 	break;
     case IMAGE_DEBUG_TYPE_COFF:
+	dump_coff(idd->PointerToRawData, idd->SizeOfData);
 	break;
     case IMAGE_DEBUG_TYPE_CODEVIEW:
 	dump_codeview(idd->PointerToRawData, idd->SizeOfData);
 	break;
     case IMAGE_DEBUG_TYPE_FPO:
+	dump_frame_pointer_omission(idd->PointerToRawData, idd->SizeOfData);
 	break;
     case IMAGE_DEBUG_TYPE_MISC:
     {
@@ -535,7 +537,7 @@
     unsigned			nb_dbg, i;
 
     if (!debugDir) return;
-    nb_dbg = nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size /
+    nb_dbg = PE_nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size /
 	sizeof(*debugDir);
     if (!nb_dbg) return;
 
@@ -740,10 +742,10 @@
     if (globals.do_dumpheader)
     {
 	dump_pe_header();
-	/* FIX%E: should check ptr */
-	dump_sections((char*)nt_headers + sizeof(DWORD) +
-		      sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader,
-		      nt_headers->FileHeader.NumberOfSections);
+	/* FIXME: should check ptr */
+	dump_sections((char*)PE_nt_headers + sizeof(DWORD) +
+		      sizeof(IMAGE_FILE_HEADER) + PE_nt_headers->FileHeader.SizeOfOptionalHeader,
+		      PE_nt_headers->FileHeader.NumberOfSections);
     }
     else if (!globals.dumpsect)
     {
@@ -792,7 +794,7 @@
 	    {
 		if (*pdw == IMAGE_NT_SIGNATURE)
 		{
-		    nt_headers = PRD(dh->e_lfanew, sizeof(DWORD));
+		    PE_nt_headers = PRD(dh->e_lfanew, sizeof(DWORD));
 		    sig = SIG_PE;
 		}
 		else
@@ -830,14 +832,14 @@
     if (fd == -1) fatal("Can't open file");
 
     if (fstat(fd, &s) < 0) fatal("Can't get size");
-    total_len = s.st_size;
+    PE_total_len = s.st_size;
 
 #ifdef HAVE_MMAP
-    if ((base = mmap(NULL, total_len, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1)
+    if ((PE_base = mmap(NULL, PE_total_len, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1)
 #endif
     {
-        if (!(base = malloc( total_len ))) fatal( "Out of memory" );
-        if (read( fd, base, total_len ) != total_len) fatal( "Cannot read file" );
+        if (!(PE_base = malloc( PE_total_len ))) fatal( "Out of memory" );
+        if (read( fd, PE_base, PE_total_len ) != PE_total_len) fatal( "Cannot read file" );
     }
 
     effective_sig = check_headers();
@@ -854,7 +856,7 @@
 	case SIG_UNKNOWN: /* shouldn't happen... */
 	    ret = 0; break;
 	case SIG_PE:
-	    printf("Contents of \"%s\": %ld bytes\n\n", name, total_len);
+	    printf("Contents of \"%s\": %ld bytes\n\n", name, PE_total_len);
 	    (*fn)();
 	    break;
 	case SIG_DBG:
@@ -872,10 +874,10 @@
 
     if (ret) printf("Done dumping %s\n", name);
 #ifdef HAVE_MMAP
-    if (munmap(base, total_len) == -1)
+    if (munmap(PE_base, PE_total_len) == -1)
 #endif
     {
-        free( base );
+        free( PE_base );
     }
     close(fd);
 
Index: tools/winedump/pe.h
===================================================================
RCS file: /home/wine/wine/tools/winedump/pe.h,v
retrieving revision 1.2
diff -u -r1.2 pe.h
--- tools/winedump/pe.h	10 Mar 2002 00:24:24 -0000	1.2
+++ tools/winedump/pe.h	10 Sep 2002 10:44:09 -0000
@@ -19,6 +19,8 @@
  */
 
 extern void		dump_codeview(unsigned long ptr, unsigned long len);
+extern void		dump_coff(unsigned long coffbase, unsigned long len);
+extern void		dump_frame_pointer_omission(unsigned long base, unsigned long len);
 extern void*		PRD(unsigned long prd, unsigned long len);
 extern unsigned long	Offset(void* ptr);
 extern char*		get_time_str(DWORD _t);

-- 
Andreas Mohr                        Stauferstr. 6, D-71272 Renningen, Germany



More information about the wine-patches mailing list