RBBS_FIXEDSIZE should not affect _AdjustBands (found by Mike McCormack
[wine] / tools / cvdump / cvload.c
1 /*
2  * Functions to read parts of a .DBG file into their respective struct's
3  *
4  * Copyright 2000 John R. Sheets
5  */
6
7 /*
8  * .DBG File Layout:
9  *
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[]
20  */
21
22 /*
23  * Descriptions:
24  *
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
43  */
44
45 /*
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
48  *
49  * IMAGE_SECTION_HEADER - number of entries determined by:
50  *    (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
51  *
52  * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
53  *    (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
54  *
55  * OMFDirEntry - number of entries determined by:
56  *    (OMFDirHeader.cDir)
57  */
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <windows.h>
63
64 #include "cvdump.h"
65
66 extern DWORD g_dwStartOfCodeView;
67
68 /*
69  * Extract a generic block of data from debugfile (pass in fileoffset == -1
70  * to avoid the fseek()).
71  */
72 int ReadChunk (FILE *debugfile, void *dest, int length, int fileoffset)
73 {
74     size_t bytes_read;
75
76     if (fileoffset >= 0)
77         fseek (debugfile, fileoffset, SEEK_SET);
78
79     bytes_read = fread (dest, 1, length, debugfile);
80     if (bytes_read < length)
81     {
82         printf ("ERROR: Only able to read %d bytes of %d-byte chunk!\n",
83                 bytes_read, length);
84         return FALSE;
85     }
86
87     return TRUE;
88 }
89
90 /*
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...
94  */
95 CVHeaderType GetHeaderType (FILE *debugfile)
96 {
97     WORD hdrtype;
98     CVHeaderType ret = CV_NONE;
99
100     int oldpos = ftell (debugfile);
101
102 #ifdef VERBOSE
103     printf (" *** Current file position = %lx\n", ftell (debugfile));
104 #endif
105
106     if (!ReadChunk (debugfile, &hdrtype, sizeof (WORD), -1))
107     {
108         fseek (debugfile, oldpos, SEEK_SET);
109         return CV_NONE;
110     }
111
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;
118
119     fseek (debugfile, oldpos, SEEK_SET);
120
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
125
126     return ret;
127 }
128
129 /*
130  * Extract the DOS file headers from an executable
131  */
132 int ReadDOSFileHeader (FILE *debugfile, IMAGE_DOS_HEADER *doshdr)
133 {
134     size_t bytes_read;
135
136     bytes_read = fread (doshdr, 1, sizeof (IMAGE_DOS_HEADER), debugfile);
137     if (bytes_read < sizeof (IMAGE_DOS_HEADER))
138     {
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;
142     }
143
144     /* Skip over stub data, if present
145      */
146     if (doshdr->e_lfanew)
147         fseek (debugfile, doshdr->e_lfanew, SEEK_SET);
148
149     return TRUE;
150 }
151
152 /*
153  * Extract the DOS and NT file headers from an executable
154  */
155 int ReadPEFileHeader (FILE *debugfile, IMAGE_NT_HEADERS *nthdr)
156 {
157     size_t bytes_read;
158
159     bytes_read = fread (nthdr, 1, sizeof (IMAGE_NT_HEADERS), debugfile);
160     if (bytes_read < sizeof (IMAGE_NT_HEADERS))
161     {
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;
165     }
166
167     return TRUE;
168 }
169
170 /*
171  * Extract the DBG file header from debugfile
172  */
173 int ReadDBGFileHeader (FILE *debugfile, IMAGE_SEPARATE_DEBUG_HEADER *dbghdr)
174 {
175     size_t bytes_read;
176
177     bytes_read = fread (dbghdr, 1, sizeof (IMAGE_SEPARATE_DEBUG_HEADER), debugfile);
178     if (bytes_read < sizeof (IMAGE_SEPARATE_DEBUG_HEADER))
179     {
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;
183     }
184
185     return TRUE;
186 }
187
188 /*
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!
196  *
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.
200  */
201 int ReadSectionHeaders (FILE *debugfile, int numsects, IMAGE_SECTION_HEADER **secthdrs)
202 {
203     size_t bytes_read;
204
205     /* Need a double-pointer so we can change the destination of the pointer
206      * and return the new allocation back to the caller.
207      */
208     *secthdrs = calloc (numsects, sizeof (IMAGE_SECTION_HEADER));
209     bytes_read = fread (*secthdrs, sizeof (IMAGE_SECTION_HEADER), numsects, debugfile);
210     if (bytes_read < numsects)
211     {
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;
216     }
217
218     return TRUE;
219 }
220
221 /*
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.
226  */
227 int ReadDebugDir (FILE *debugfile, int numdirs, IMAGE_DEBUG_DIRECTORY **debugdirs)
228 {
229     size_t bytes_read;
230
231     /* Need a double-pointer so we can change the destination of the pointer
232      * and return the new allocation back to the caller.
233      */
234     *debugdirs = calloc (numdirs, sizeof (IMAGE_DEBUG_DIRECTORY));
235     bytes_read = fread (*debugdirs, sizeof (IMAGE_DEBUG_DIRECTORY), numdirs, debugfile);
236     if (bytes_read < numdirs)
237     {
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;
242     }
243
244     return TRUE;
245 }
246
247 /*
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.
251  */
252 int ReadCodeViewHeader (FILE *debugfile, OMFSignature *sig, OMFDirHeader *dirhdr)
253 {
254     size_t bytes_read;
255
256     bytes_read = fread (sig, 1, sizeof (OMFSignature), debugfile);
257     if (bytes_read < sizeof (OMFSignature))
258     {
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;
263     }
264
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.
270      */
271     fseek (debugfile, sig->filepos + g_dwStartOfCodeView, SEEK_SET);
272     bytes_read = fread (dirhdr, 1, sizeof (OMFDirHeader), debugfile);
273     if (bytes_read < sizeof (OMFDirHeader))
274     {
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;
279     }
280
281     /* File pointer is now at first OMGDirEntry, so we can begin reading those now,
282      * with an immediate call to ReadCodeViewDirectory ().
283      */
284
285     return TRUE;
286 }
287
288 /*
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.
292  *
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).
296  */
297 int ReadCodeViewDirectory (FILE *debugfile, int entrynum, OMFDirEntry **entries)
298 {
299     size_t bytes_read;
300
301     /* Need a double-pointer so we can change the destination of the pointer
302      * and return the new allocation back to the caller.
303      */
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)
309     {
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;
314     }
315
316     return TRUE;
317 }
318
319 /*
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.
324  *
325  * NOTE: 'debugfile' must already be pointing to the correct location.
326  */
327 int ReadModuleData (FILE *debugfile, int entrynum, OMFDirEntry *entries,
328                     int *module_count, OMFModuleFull **modules)
329 {
330     int i;
331     int segnum;
332     size_t bytes_read;
333     OMFSegDesc *segarray;
334     char namelen;
335     OMFModuleFull *module;
336     int pad;
337
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.)
341      */
342     int module_bytes = (sizeof (unsigned short) * 3) + (sizeof (char) * 2);
343
344     if (entries == NULL)
345         return FALSE;
346
347     /* Find out how many sstModule sub-sections we have in 'entries'
348      */
349     *module_count = 0;
350     for (i = 0; i < entrynum; i++)
351     {
352         if (entries[i].SubSection == sstModule)
353             (*module_count)++;
354     }
355
356     /* Need a double-pointer so we can change the destination of the pointer
357      * and return the new allocation back to the caller.
358      */
359     *modules = calloc (*module_count, sizeof (OMFModuleFull));
360     for (i = 0; i < *module_count; i++)
361     {
362         /* Convenience pointer to current module
363          */
364         module = &(*modules)[i];
365
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.
369          */
370         bytes_read = fread (module, sizeof (char), module_bytes, debugfile);
371         if (bytes_read < module_bytes)
372         {
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;
377         }
378         
379         /* Allocate space for, and grab the entire 'SegInfo' array.
380          */
381         segnum = module->cSeg;
382         segarray = calloc (segnum, sizeof (OMFSegDesc));
383
384         bytes_read = fread (segarray, sizeof (OMFSegDesc), segnum, debugfile);
385         if (bytes_read < segnum)
386         {
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;
391         }
392         module->SegInfo = segarray;
393
394         /* Allocate space for the (length-prefixed) 'Name' field.
395          */
396         bytes_read = fread (&namelen, sizeof (char), 1, debugfile);
397         if (bytes_read < 1)
398         {
399             printf ("ERROR while reading CodeView Module Name length!\n");
400             return FALSE;
401         }
402
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.)
406          */
407         pad = ((namelen + 1) % 4);
408         if (pad)
409             namelen += (4 - pad);
410
411         module->Name = calloc (namelen + 1, sizeof (char));
412         bytes_read = fread (module->Name, sizeof (char), namelen, debugfile);
413         if (bytes_read < namelen)
414         {
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;
419         }
420         /*  printf ("%s\n", module->Name); */
421     }
422
423 #ifdef VERBOSE
424     printf ("Done reading %d modules\n", *module_count);
425 #endif
426
427     return TRUE;
428 }
429
430