Fixed scrolling of listview with a mouse wheel.
[wine.git] / tools / cvdump / cvload.c
blob912b0a2c128ed5cf9616b25b2f02682f32396c4f
1 /*
2 * Functions to read parts of a .DBG file into their respective struct's
4 * Copyright 2000 John R. Sheets
5 */
7 /*
8 * .DBG File Layout:
10 * IMAGE_SEPARATE_DEBUG_HEADER
11 * IMAGE_SECTION_HEADER[]
12 * IMAGE_DEBUG_DIRECTORY[]
13 * OMFSignature
14 * debug data (typical example)
15 * - IMAGE_DEBUG_TYPE_MISC
16 * - IMAGE_DEBUG_TYPE_FPO
17 * - IMAGE_DEBUG_TYPE_CODEVIEW
18 * OMFDirHeader
19 * OMFDirEntry[]
23 * Descriptions:
25 * (hdr) IMAGE_SEPARATE_DEBUG_HEADER - .DBG-specific file header; holds info that
26 * applies to the file as a whole, including # of COFF sections, file offsets, etc.
27 * (hdr) IMAGE_SECTION_HEADER - list of COFF sections copied verbatim from .EXE;
28 * although this directory contains file offsets, these offsets are meaningless
29 * in the context of the .DBG file, because only the section headers are copied
30 * to the .DBG file...not the binary data it points to.
31 * (hdr) IMAGE_DEBUG_DIRECTORY - list of different formats of debug info contained in file
32 * (see IMAGE_DEBUG_TYPE_* descriptions below); tells where each section starts
33 * (hdr) OMFSignature (CV) - Contains "NBxx" signature, plus file offset telling how far
34 * into the IMAGE_DEBUG_TYPE_CODEVIEW section the OMFDirHeader and OMFDirEntry's sit
35 * (data) IMAGE_DEBUG_TYPE_MISC - usually holds name of original .EXE file
36 * (data) IMAGE_DEBUG_TYPE_FPO - Frame Pointer Optimization data; used for dealing with
37 * optimized stack frames (optional)
38 * (data) IMAGE_DEBUG_TYPE_CODEVIEW - *** THE GOOD STUFF ***
39 * This block of data contains all the symbol tables, line number info, etc.,
40 * that the Visual C++ debugger needs.
41 * (hdr) OMFDirHeader (CV) -
42 * (hdr) OMFDirEntry (CV) - list of subsections within CodeView debug data section
46 * The .DBG file typically has three arrays of directory entries, which tell
47 * the OS or debugger where in the file to look for the actual data
49 * IMAGE_SECTION_HEADER - number of entries determined by:
50 * (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
52 * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
53 * (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
55 * OMFDirEntry - number of entries determined by:
56 * (OMFDirHeader.cDir)
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <windows.h>
64 #include "cvdump.h"
66 extern DWORD g_dwStartOfCodeView;
69 * Extract a generic block of data from debugfile (pass in fileoffset == -1
70 * to avoid the fseek()).
72 int ReadChunk (FILE *debugfile, void *dest, int length, int fileoffset)
74 size_t bytes_read;
76 if (fileoffset >= 0)
77 fseek (debugfile, fileoffset, SEEK_SET);
79 bytes_read = fread (dest, 1, length, debugfile);
80 if (bytes_read < length)
82 printf ("ERROR: Only able to read %d bytes of %d-byte chunk!\n",
83 bytes_read, length);
84 return FALSE;
87 return TRUE;
91 * Scan the next two bytes of a file, and see if they correspond to a file
92 * header signature. Don't forget to put the file pointer back where we
93 * found it...
95 CVHeaderType GetHeaderType (FILE *debugfile)
97 WORD hdrtype;
98 CVHeaderType ret = CV_NONE;
100 int oldpos = ftell (debugfile);
102 #ifdef VERBOSE
103 printf (" *** Current file position = %lx\n", ftell (debugfile));
104 #endif
106 if (!ReadChunk (debugfile, &hdrtype, sizeof (WORD), -1))
108 fseek (debugfile, oldpos, SEEK_SET);
109 return CV_NONE;
112 if (hdrtype == 0x5A4D) /* "MZ" */
113 ret = CV_DOS;
114 else if (hdrtype == 0x4550) /* "PE" */
115 ret = CV_NT;
116 else if (hdrtype == 0x4944) /* "DI" */
117 ret = CV_DBG;
119 fseek (debugfile, oldpos, SEEK_SET);
121 #ifdef VERBOSE
122 printf ("Returning header type = %d [0x%x]\n", ret, hdrtype);
123 printf (" *** Current file position = %lx\n", ftell (debugfile));
124 #endif
126 return ret;
130 * Extract the DOS file headers from an executable
132 int ReadDOSFileHeader (FILE *debugfile, IMAGE_DOS_HEADER *doshdr)
134 size_t bytes_read;
136 bytes_read = fread (doshdr, 1, sizeof (IMAGE_DOS_HEADER), debugfile);
137 if (bytes_read < sizeof (IMAGE_DOS_HEADER))
139 printf ("ERROR: Only able to read %d bytes of %d-byte DOS file header!\n",
140 bytes_read, sizeof (IMAGE_DOS_HEADER));
141 return FALSE;
144 /* Skip over stub data, if present
146 if (doshdr->e_lfanew)
147 fseek (debugfile, doshdr->e_lfanew, SEEK_SET);
149 return TRUE;
153 * Extract the DOS and NT file headers from an executable
155 int ReadPEFileHeader (FILE *debugfile, IMAGE_NT_HEADERS *nthdr)
157 size_t bytes_read;
159 bytes_read = fread (nthdr, 1, sizeof (IMAGE_NT_HEADERS), debugfile);
160 if (bytes_read < sizeof (IMAGE_NT_HEADERS))
162 printf ("ERROR: Only able to read %d bytes of %d-byte NT file header!\n",
163 bytes_read, sizeof (IMAGE_NT_HEADERS));
164 return FALSE;
167 return TRUE;
171 * Extract the DBG file header from debugfile
173 int ReadDBGFileHeader (FILE *debugfile, IMAGE_SEPARATE_DEBUG_HEADER *dbghdr)
175 size_t bytes_read;
177 bytes_read = fread (dbghdr, 1, sizeof (IMAGE_SEPARATE_DEBUG_HEADER), debugfile);
178 if (bytes_read < sizeof (IMAGE_SEPARATE_DEBUG_HEADER))
180 printf ("ERROR: Only able to read %d bytes of %d-byte DBG file header!\n",
181 bytes_read, sizeof (IMAGE_SEPARATE_DEBUG_HEADER));
182 return FALSE;
185 return TRUE;
189 * Extract all of the file's COFF section headers into an array of
190 * IMAGE_SECTION_HEADER's. These COFF sections don't really apply to
191 * the .DBG file directly (they contain file offsets into the .EXE file
192 * which don't correspond to anything in the .DBG file). They are
193 * copied verbatim into this .DBG file to help make the debugging process
194 * more robust. By referencing these COFF section headers, the debugger
195 * can still function in the absence of the original .EXE file!
197 * NOTE: Do not bother pre-allocating memory. This function will
198 * allocate it for you. Don't forget to free() it when you're done,
199 * though.
201 int ReadSectionHeaders (FILE *debugfile, int numsects, IMAGE_SECTION_HEADER **secthdrs)
203 size_t bytes_read;
205 /* Need a double-pointer so we can change the destination of the pointer
206 * and return the new allocation back to the caller.
208 *secthdrs = calloc (numsects, sizeof (IMAGE_SECTION_HEADER));
209 bytes_read = fread (*secthdrs, sizeof (IMAGE_SECTION_HEADER), numsects, debugfile);
210 if (bytes_read < numsects)
212 printf ("ERROR while reading COFF headers: Only able to "
213 "read %d headers out of %d desired!\n",
214 bytes_read, sizeof (IMAGE_SECTION_HEADER));
215 return FALSE;
218 return TRUE;
222 * Load in the debug directory table. This directory describes the various
223 * blocks of debug data that reside at the end of the file (after the COFF
224 * sections), including FPO data, COFF-style debug info, and the CodeView
225 * we are *really* after.
227 int ReadDebugDir (FILE *debugfile, int numdirs, IMAGE_DEBUG_DIRECTORY **debugdirs)
229 size_t bytes_read;
231 /* Need a double-pointer so we can change the destination of the pointer
232 * and return the new allocation back to the caller.
234 *debugdirs = calloc (numdirs, sizeof (IMAGE_DEBUG_DIRECTORY));
235 bytes_read = fread (*debugdirs, sizeof (IMAGE_DEBUG_DIRECTORY), numdirs, debugfile);
236 if (bytes_read < numdirs)
238 printf ("ERROR while reading Debug Directory: Only able to "
239 "read %d headers out of %d desired!\n",
240 bytes_read, numdirs);
241 return FALSE;
244 return TRUE;
248 * Load in the CodeView-style headers inside the CodeView debug section.
249 * The 'sig' and 'dirhdr' parameters must point to already-allocated
250 * data structures.
252 int ReadCodeViewHeader (FILE *debugfile, OMFSignature *sig, OMFDirHeader *dirhdr)
254 size_t bytes_read;
256 bytes_read = fread (sig, 1, sizeof (OMFSignature), debugfile);
257 if (bytes_read < sizeof (OMFSignature))
259 printf ("ERROR while reading CodeView Header Signature: Only "
260 "able to read %d bytes out of %d desired!\n",
261 bytes_read, sizeof (OMFSignature));
262 return FALSE;
265 /* Must perform a massive jump, almost to the end of the file, to find the
266 * CodeView Directory Header (OMFDirHeader), which is immediately followed
267 * by the array of entries (OMFDirEntry). We calculate the jump based on
268 * the beginning of the CodeView debug section (from the CodeView entry in
269 * the IMAGE_DEBUG_DIRECTORY array), with the added offset from OMGSignature.
271 fseek (debugfile, sig->filepos + g_dwStartOfCodeView, SEEK_SET);
272 bytes_read = fread (dirhdr, 1, sizeof (OMFDirHeader), debugfile);
273 if (bytes_read < sizeof (OMFDirHeader))
275 printf ("ERROR while reading CodeView Directory Header: Only "
276 "able to read %d bytes out of %d desired!\n",
277 bytes_read, sizeof (OMFDirHeader));
278 return FALSE;
281 /* File pointer is now at first OMGDirEntry, so we can begin reading those now,
282 * with an immediate call to ReadCodeViewDirectory ().
285 return TRUE;
289 * Load in the CodeView directory entries, which each point to a CodeView
290 * subsection (e.g. sstModules, sstGlobalPub). The number of entries in
291 * this table is determined by OMFDirEntry.cDir.
293 * Strangely enough, this particular section comes immediately *after*
294 * the debug data (as opposed to immediately *before* the data as is the
295 * standard with the COFF headers).
297 int ReadCodeViewDirectory (FILE *debugfile, int entrynum, OMFDirEntry **entries)
299 size_t bytes_read;
301 /* Need a double-pointer so we can change the destination of the pointer
302 * and return the new allocation back to the caller.
304 /* printf ("Allocating space for %d entries\n", entrynum); */
305 *entries = calloc (entrynum, sizeof (OMFDirEntry));
306 /* printf ("Allocated memory at %p (%p)\n", *entries, entries); */
307 bytes_read = fread (*entries, sizeof (OMFDirEntry), entrynum, debugfile);
308 if (bytes_read < entrynum)
310 printf ("ERROR while reading CodeView Debug Directories: Only "
311 "able to read %d entries out of %d desired!\n",
312 bytes_read, entrynum);
313 return FALSE;
316 return TRUE;
320 * Load in the data contents of all CodeView sstModule sub-sections in the file (likely a
321 * large array, as there is one sub-section for every code module... > 100 modules is normal).
322 * 'entrynum' should hold the total number of CV sub-sections, not the number of sstModule
323 * subsections. The function will ignore anything that isn't a sstModule.
325 * NOTE: 'debugfile' must already be pointing to the correct location.
327 int ReadModuleData (FILE *debugfile, int entrynum, OMFDirEntry *entries,
328 int *module_count, OMFModuleFull **modules)
330 int i;
331 int segnum;
332 size_t bytes_read;
333 OMFSegDesc *segarray;
334 char namelen;
335 OMFModuleFull *module;
336 int pad;
338 /* How much of the OMFModuleFull struct can we pull directly from the file?
339 * (Kind of a hack, but not much else we can do...the 'SegInfo' and 'Name'
340 * fields will hold memory pointers, not the actual data from the file.)
342 int module_bytes = (sizeof (unsigned short) * 3) + (sizeof (char) * 2);
344 if (entries == NULL)
345 return FALSE;
347 /* Find out how many sstModule sub-sections we have in 'entries'
349 *module_count = 0;
350 for (i = 0; i < entrynum; i++)
352 if (entries[i].SubSection == sstModule)
353 (*module_count)++;
356 /* Need a double-pointer so we can change the destination of the pointer
357 * and return the new allocation back to the caller.
359 *modules = calloc (*module_count, sizeof (OMFModuleFull));
360 for (i = 0; i < *module_count; i++)
362 /* Convenience pointer to current module
364 module = &(*modules)[i];
366 /* Must extract each OMFModuleFull separately from file, because the 'SegInfo'
367 * and 'Name' fields also require separate allocations; the data for these
368 * fields is interspersed in the file, between OMFModuleFull blocks.
370 bytes_read = fread (module, sizeof (char), module_bytes, debugfile);
371 if (bytes_read < module_bytes)
373 printf ("ERROR while reading CodeView Module Sub-section Data: "
374 "Only able to read %d bytes from entry %d!\n",
375 bytes_read, i);
376 return FALSE;
379 /* Allocate space for, and grab the entire 'SegInfo' array.
381 segnum = module->cSeg;
382 segarray = calloc (segnum, sizeof (OMFSegDesc));
384 bytes_read = fread (segarray, sizeof (OMFSegDesc), segnum, debugfile);
385 if (bytes_read < segnum)
387 printf ("ERROR while reading CodeView Module SegInfo Data: "
388 "Only able to read %d segments from module %d!\n",
389 bytes_read, i);
390 return FALSE;
392 module->SegInfo = segarray;
394 /* Allocate space for the (length-prefixed) 'Name' field.
396 bytes_read = fread (&namelen, sizeof (char), 1, debugfile);
397 if (bytes_read < 1)
399 printf ("ERROR while reading CodeView Module Name length!\n");
400 return FALSE;
403 /* Read 'Name' field from file. 'Name' must be aligned on a 4-byte
404 * boundary, so we must do a little extra math on the string length.
405 * (NOTE: Must include namelen byte in total padding length, too.)
407 pad = ((namelen + 1) % 4);
408 if (pad)
409 namelen += (4 - pad);
411 module->Name = calloc (namelen + 1, sizeof (char));
412 bytes_read = fread (module->Name, sizeof (char), namelen, debugfile);
413 if (bytes_read < namelen)
415 printf ("ERROR while reading CodeView Module Name: "
416 "Only able to read %d chars from module %d!\n",
417 bytes_read, i);
418 return FALSE;
420 /* printf ("%s\n", module->Name); */
423 #ifdef VERBOSE
424 printf ("Done reading %d modules\n", *module_count);
425 #endif
427 return TRUE;