ddraw: Separate IDirectDrawSurface4 vtable.
[wine] / dlls / dbghelp / coff.c
1 /*
2  * Read VC++ debug information from COFF and eventually
3  * from PDB files.
4  *
5  * Copyright (C) 1996,      Eric Youngdale.
6  * Copyright (C) 1999-2000, Ulrich Weigand.
7  * Copyright (C) 2004,      Eric Pouech.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 /*
25  * Note - this handles reading debug information for 32 bit applications
26  * that run under Windows-NT for example.  I doubt that this would work well
27  * for 16 bit applications, but I don't think it really matters since the
28  * file format is different, and we should never get in here in such cases.
29  *
30  * TODO:
31  *      Get 16 bit CV stuff working.
32  *      Add symbol size to internal symbol table.
33  */
34
35 #include "config.h"
36 #include "wine/port.h"
37
38 #include <assert.h>
39 #include <stdlib.h>
40
41 #include <string.h>
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #ifndef PATH_MAX
46 #define PATH_MAX MAX_PATH
47 #endif
48 #include <stdarg.h>
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winternl.h"
52
53 #include "wine/exception.h"
54 #include "wine/debug.h"
55 #include "dbghelp_private.h"
56 #include "wine/mscvpdb.h"
57
58 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff);
59
60 /*========================================================================
61  * Process COFF debug information.
62  */
63
64 struct CoffFile
65 {
66     unsigned int                startaddr;
67     unsigned int                endaddr;
68     struct symt_compiland*      compiland;
69     int                         linetab_offset;
70     int                         linecnt;
71     struct symt**               entries;
72     int                         neps;
73     int                         neps_alloc;
74 };
75
76 struct CoffFileSet
77 {
78     struct CoffFile*    files;
79     int                 nfiles;
80     int                 nfiles_alloc;
81 };
82
83 static const char*      coff_get_name(const IMAGE_SYMBOL* coff_sym, 
84                                       const char* coff_strtab)
85 {
86     static      char    namebuff[9];
87     const char*         nampnt;
88
89     if (coff_sym->N.Name.Short)
90     {
91         memcpy(namebuff, coff_sym->N.ShortName, 8);
92         namebuff[8] = '\0';
93         nampnt = &namebuff[0];
94     }
95     else
96     {
97         nampnt = coff_strtab + coff_sym->N.Name.Long;
98     }
99
100     if (nampnt[0] == '_') nampnt++;
101     return nampnt;
102 }
103
104 static int coff_add_file(struct CoffFileSet* coff_files, struct module* module,
105                          const char* filename)
106 {
107     struct CoffFile* file;
108
109     if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc)
110     {
111         if (coff_files->files)
112         {
113             coff_files->nfiles_alloc *= 2;
114             coff_files->files = HeapReAlloc(GetProcessHeap(), 0, coff_files->files,
115                                             coff_files->nfiles_alloc * sizeof(struct CoffFile));
116         }
117         else
118         {
119             coff_files->nfiles_alloc = 16;
120             coff_files->files = HeapAlloc(GetProcessHeap(), 0,
121                                           coff_files->nfiles_alloc * sizeof(struct CoffFile));
122         }
123     }
124     file = coff_files->files + coff_files->nfiles;
125     file->startaddr = 0xffffffff;
126     file->endaddr   = 0;
127     file->compiland = symt_new_compiland(module, 0,
128                                          source_new(module, NULL, filename));
129     file->linetab_offset = -1;
130     file->linecnt = 0;
131     file->entries = NULL;
132     file->neps = file->neps_alloc = 0;
133
134     return coff_files->nfiles++;
135 }
136
137 static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym)
138 {
139     if (coff_file->neps + 1 >= coff_file->neps_alloc)
140     {
141         if (coff_file->entries)
142         {
143             coff_file->neps_alloc *= 2;
144             coff_file->entries = HeapReAlloc(GetProcessHeap(), 0, coff_file->entries,
145                                              coff_file->neps_alloc * sizeof(struct symt*));
146         }
147         else
148         {
149             coff_file->neps_alloc = 32;
150             coff_file->entries = HeapAlloc(GetProcessHeap(), 0,
151                                            coff_file->neps_alloc * sizeof(struct symt*));
152         }
153     }
154     coff_file->entries[coff_file->neps++] = sym;
155 }
156
157 DECLSPEC_HIDDEN BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
158 {
159     const IMAGE_AUX_SYMBOL*             aux;
160     const IMAGE_COFF_SYMBOLS_HEADER*    coff;
161     const IMAGE_LINENUMBER*             coff_linetab;
162     const IMAGE_LINENUMBER*             linepnt;
163     const char*                         coff_strtab;
164     const IMAGE_SYMBOL*                 coff_sym;
165     const IMAGE_SYMBOL*                 coff_symbols;
166     struct CoffFileSet                  coff_files;
167     int                                 curr_file_idx = -1;
168     unsigned int                        i;
169     int                                 j;
170     int                                 k;
171     int                                 l;
172     int                                 linetab_indx;
173     const char*                         nampnt;
174     int                                 naux;
175     BOOL                                ret = FALSE;
176     ULONG64                             addr;
177
178     TRACE("Processing COFF symbols...\n");
179
180     assert(sizeof(IMAGE_SYMBOL) == IMAGE_SIZEOF_SYMBOL);
181     assert(sizeof(IMAGE_LINENUMBER) == IMAGE_SIZEOF_LINENUMBER);
182
183     coff_files.files = NULL;
184     coff_files.nfiles = coff_files.nfiles_alloc = 0;
185
186     coff = (const IMAGE_COFF_SYMBOLS_HEADER*)msc_dbg->root;
187
188     coff_symbols = (const IMAGE_SYMBOL*)((const char *)coff + coff->LvaToFirstSymbol);
189     coff_linetab = (const IMAGE_LINENUMBER*)((const char *)coff + coff->LvaToFirstLinenumber);
190     coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols);
191
192     linetab_indx = 0;
193
194     for (i = 0; i < coff->NumberOfSymbols; i++)
195     {
196         coff_sym = coff_symbols + i;
197         naux = coff_sym->NumberOfAuxSymbols;
198
199         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE)
200         {
201             curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, 
202                                           (const char*)(coff_sym + 1));
203             TRACE("New file %s\n", (const char*)(coff_sym + 1));
204             i += naux;
205             continue;
206         }
207
208         if (curr_file_idx < 0)
209         {
210             assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0);
211             curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, "<none>");
212             TRACE("New file <none>\n");
213         }
214
215         /*
216          * This guy marks the size and location of the text section
217          * for the current file.  We need to keep track of this so
218          * we can figure out what file the different global functions
219          * go with.
220          */
221         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC &&
222             naux != 0 && coff_sym->Type == 0 && coff_sym->SectionNumber == 1)
223         {
224             aux = (const IMAGE_AUX_SYMBOL*) (coff_sym + 1);
225
226             if (coff_files.files[curr_file_idx].linetab_offset != -1)
227             {
228                 /*
229                  * Save this so we can still get the old name.
230                  */
231                 const char* fn;
232
233                 fn = source_get(msc_dbg->module,
234                                 coff_files.files[curr_file_idx].compiland->source);
235
236                 TRACE("Duplicating sect from %s: %x %x %x %d %d\n",
237                       fn, aux->Section.Length,
238                       aux->Section.NumberOfRelocations,
239                       aux->Section.NumberOfLinenumbers,
240                       aux->Section.Number, aux->Section.Selection);
241                 TRACE("More sect %d %s %08x %d %d %d\n",
242                       coff_sym->SectionNumber,
243                       coff_get_name(coff_sym, coff_strtab),
244                       coff_sym->Value, coff_sym->Type,
245                       coff_sym->StorageClass, coff_sym->NumberOfAuxSymbols);
246
247                 /*
248                  * Duplicate the file entry.  We have no way to describe
249                  * multiple text sections in our current way of handling things.
250                  */
251                 coff_add_file(&coff_files, msc_dbg->module, fn);
252             }
253             else
254             {
255                 TRACE("New text sect from %s: %x %x %x %d %d\n",
256                       source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source),
257                       aux->Section.Length,
258                       aux->Section.NumberOfRelocations,
259                       aux->Section.NumberOfLinenumbers,
260                       aux->Section.Number, aux->Section.Selection);
261             }
262
263             if (coff_files.files[curr_file_idx].startaddr > coff_sym->Value)
264             {
265                 coff_files.files[curr_file_idx].startaddr = coff_sym->Value;
266             }
267
268             if (coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length)
269             {
270                 coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length;
271             }
272
273             coff_files.files[curr_file_idx].linetab_offset = linetab_indx;
274             coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers;
275             linetab_indx += aux->Section.NumberOfLinenumbers;
276             i += naux;
277             continue;
278         }
279
280         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 && 
281             coff_sym->SectionNumber == 1)
282         {
283             DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
284             /*
285              * This is a normal static function when naux == 0.
286              * Just register it.  The current file is the correct
287              * one in this instance.
288              */
289             nampnt = coff_get_name(coff_sym, coff_strtab);
290
291             TRACE("\tAdding static symbol %s\n", nampnt);
292
293             /* FIXME: was adding symbol to this_file ??? */
294             coff_add_symbol(&coff_files.files[curr_file_idx],
295                             &symt_new_function(msc_dbg->module, 
296                                                coff_files.files[curr_file_idx].compiland, 
297                                                nampnt,
298                                                msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
299                                                0 /* FIXME */,
300                                                NULL /* FIXME */)->symt);
301             i += naux;
302             continue;
303         }
304
305         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
306             ISFCN(coff_sym->Type) && coff_sym->SectionNumber > 0)
307         {
308             struct symt_compiland* compiland = NULL;
309             DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
310             nampnt = coff_get_name(coff_sym, coff_strtab);
311
312             TRACE("%d: %s %s\n",
313                   i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value),
314                   nampnt);
315             TRACE("\tAdding global symbol %s (sect=%s)\n",
316                   nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name);
317
318             /*
319              * Now we need to figure out which file this guy belongs to.
320              */
321             for (j = 0; j < coff_files.nfiles; j++)
322             {
323                 if (coff_files.files[j].startaddr <= base + coff_sym->Value
324                      && coff_files.files[j].endaddr > base + coff_sym->Value)
325                 {
326                     compiland = coff_files.files[j].compiland;
327                     break;
328                 }
329             }
330             if (j < coff_files.nfiles)
331             {
332                 coff_add_symbol(&coff_files.files[j],
333                                 &symt_new_function(msc_dbg->module, compiland, nampnt, 
334                                                    msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
335                                                    0 /* FIXME */, NULL /* FIXME */)->symt);
336             } 
337             else 
338             {
339                 symt_new_function(msc_dbg->module, NULL, nampnt, 
340                                   msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
341                                   0 /* FIXME */, NULL /* FIXME */);
342             }
343             i += naux;
344             continue;
345         }
346
347         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
348             coff_sym->SectionNumber > 0)
349         {
350             DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
351             struct location loc;
352
353             /*
354              * Similar to above, but for the case of data symbols.
355              * These aren't treated as entrypoints.
356              */
357             nampnt = coff_get_name(coff_sym, coff_strtab);
358
359             TRACE("%d: %s %s\n",
360                   i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value),
361                   nampnt);
362             TRACE("\tAdding global data symbol %s\n", nampnt);
363
364             /*
365              * Now we need to figure out which file this guy belongs to.
366              */
367             loc.kind = loc_absolute;
368             loc.reg = 0;
369             loc.offset = msc_dbg->module->module.BaseOfImage + base + coff_sym->Value;
370             symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */,
371                                      loc, 0 /* FIXME */, NULL /* FIXME */);
372             i += naux;
373             continue;
374         }
375
376         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0)
377         {
378             /*
379              * Ignore these.  They don't have anything to do with
380              * reality.
381              */
382             i += naux;
383             continue;
384         }
385
386         TRACE("Skipping unknown entry '%s' %d %d %d\n",
387               coff_get_name(coff_sym, coff_strtab),
388               coff_sym->StorageClass, coff_sym->SectionNumber, naux);
389         
390         /*
391          * For now, skip past the aux entries.
392          */
393         i += naux;
394     }
395
396     if (coff_files.files != NULL)
397     {
398         /*
399          * OK, we now should have a list of files, and we should have a list
400          * of entrypoints.  We need to sort the entrypoints so that we are
401          * able to tie the line numbers with the given functions within the
402          * file.
403          */
404         for (j = 0; j < coff_files.nfiles; j++)
405         {
406             if (coff_files.files[j].entries != NULL)
407             {
408                 qsort(coff_files.files[j].entries, coff_files.files[j].neps,
409                       sizeof(struct symt*), symt_cmp_addr);
410             }
411         }
412
413         /*
414          * Now pick apart the line number tables, and attach the entries
415          * to the given functions.
416          */
417         for (j = 0; j < coff_files.nfiles; j++)
418         {
419             l = 0;
420             if (coff_files.files[j].neps != 0)
421             {
422                 for (k = 0; k < coff_files.files[j].linecnt; k++)
423                 {
424                     linepnt = coff_linetab + coff_files.files[j].linetab_offset + k;
425                     /*
426                      * If we have spilled onto the next entrypoint, then
427                      * bump the counter..
428                      */
429                     for (;;)
430                     {
431                         if (l+1 >= coff_files.files[j].neps) break;
432                         symt_get_address(coff_files.files[j].entries[l+1], &addr);
433                         if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr))
434                             break;
435                         l++;
436                     }
437
438                     if (coff_files.files[j].entries[l+1]->tag == SymTagFunction)
439                     {
440                         /*
441                          * Add the line number.  This is always relative to the
442                          * start of the function, so we need to subtract that offset
443                          * first.
444                          */
445                         symt_get_address(coff_files.files[j].entries[l+1], &addr);
446                         symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], 
447                                            coff_files.files[j].compiland->source, linepnt->Linenumber,
448                                            msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr);
449                     }
450                 }
451             }
452         }
453
454         for (j = 0; j < coff_files.nfiles; j++)
455         {
456             HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries);
457         }
458         HeapFree(GetProcessHeap(), 0, coff_files.files);
459         msc_dbg->module->module.SymType = SymCoff;
460         /* FIXME: we could have a finer grain here */
461         msc_dbg->module->module.LineNumbers = TRUE;
462         msc_dbg->module->module.GlobalSymbols = TRUE;
463         msc_dbg->module->module.TypeInfo = FALSE;
464         msc_dbg->module->module.SourceIndexed = TRUE;
465         msc_dbg->module->module.Publics = TRUE;
466         ret = TRUE;
467     }
468
469     return ret;
470 }