dbghelp: Moved mscvpdb.h file to include/wine to allow sharing of the definitions...
[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 "winreg.h"
52 #include "winternl.h"
53
54 #include "wine/exception.h"
55 #include "wine/debug.h"
56 #include "excpt.h"
57 #include "dbghelp_private.h"
58 #include "wine/mscvpdb.h"
59
60 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff);
61
62 /*========================================================================
63  * Process COFF debug information.
64  */
65
66 struct CoffFile
67 {
68     unsigned int                startaddr;
69     unsigned int                endaddr;
70     struct symt_compiland*      compiland;
71     int                         linetab_offset;
72     int                         linecnt;
73     struct symt**               entries;
74     int                         neps;
75     int                         neps_alloc;
76 };
77
78 struct CoffFileSet
79 {
80     struct CoffFile*    files;
81     int                 nfiles;
82     int                 nfiles_alloc;
83 };
84
85 static const char*      coff_get_name(const IMAGE_SYMBOL* coff_sym, 
86                                       const char* coff_strtab)
87 {
88     static      char    namebuff[9];
89     const char*         nampnt;
90
91     if (coff_sym->N.Name.Short)
92     {
93         memcpy(namebuff, coff_sym->N.ShortName, 8);
94         namebuff[8] = '\0';
95         nampnt = &namebuff[0];
96     }
97     else
98     {
99         nampnt = coff_strtab + coff_sym->N.Name.Long;
100     }
101
102     if (nampnt[0] == '_') nampnt++;
103     return nampnt;
104 }
105
106 static int coff_add_file(struct CoffFileSet* coff_files, struct module* module,
107                          const char* filename)
108 {
109     struct CoffFile* file;
110
111     if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc)
112     {
113         coff_files->nfiles_alloc += 10;
114         coff_files->files = (coff_files->files) ?
115             HeapReAlloc(GetProcessHeap(), 0, coff_files->files,
116                         coff_files->nfiles_alloc * sizeof(struct CoffFile)) :
117             HeapAlloc(GetProcessHeap(), 0,
118                       coff_files->nfiles_alloc * sizeof(struct CoffFile));
119     }
120     file = coff_files->files + coff_files->nfiles;
121     file->startaddr = 0xffffffff;
122     file->endaddr   = 0;
123     file->compiland = symt_new_compiland(module, 0,
124                                          source_new(module, NULL, filename));
125     file->linetab_offset = -1;
126     file->linecnt = 0;
127     file->entries = NULL;
128     file->neps = file->neps_alloc = 0;
129
130     return coff_files->nfiles++;
131 }
132
133 static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym)
134 {
135     if (coff_file->neps + 1 >= coff_file->neps_alloc)
136     {
137         coff_file->neps_alloc += 10;
138         coff_file->entries = (coff_file->entries) ?
139             HeapReAlloc(GetProcessHeap(), 0, coff_file->entries,
140                         coff_file->neps_alloc * sizeof(struct symt*)) :
141             HeapAlloc(GetProcessHeap(), 0, 
142                       coff_file->neps_alloc * sizeof(struct symt*));
143     }
144     coff_file->entries[coff_file->neps++] = sym;
145 }
146
147 BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
148 {
149     const IMAGE_AUX_SYMBOL*             aux;
150     const IMAGE_COFF_SYMBOLS_HEADER*    coff;
151     const IMAGE_LINENUMBER*             coff_linetab;
152     const IMAGE_LINENUMBER*             linepnt;
153     const char*                         coff_strtab;
154     const IMAGE_SYMBOL*                 coff_sym;
155     const IMAGE_SYMBOL*                 coff_symbols;
156     struct CoffFileSet                  coff_files;
157     int                                 curr_file_idx = -1;
158     unsigned int                        i;
159     int                                 j;
160     int                                 k;
161     int                                 l;
162     int                                 linetab_indx;
163     const char*                         nampnt;
164     int                                 naux;
165     BOOL                                ret = FALSE;
166     DWORD                               addr;
167
168     TRACE("Processing COFF symbols...\n");
169
170     assert(sizeof(IMAGE_SYMBOL) == IMAGE_SIZEOF_SYMBOL);
171     assert(sizeof(IMAGE_LINENUMBER) == IMAGE_SIZEOF_LINENUMBER);
172
173     coff_files.files = NULL;
174     coff_files.nfiles = coff_files.nfiles_alloc = 0;
175
176     coff = (const IMAGE_COFF_SYMBOLS_HEADER*)msc_dbg->root;
177
178     coff_symbols = (const IMAGE_SYMBOL*)((const char *)coff + coff->LvaToFirstSymbol);
179     coff_linetab = (const IMAGE_LINENUMBER*)((const char *)coff + coff->LvaToFirstLinenumber);
180     coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols);
181
182     linetab_indx = 0;
183
184     for (i = 0; i < coff->NumberOfSymbols; i++)
185     {
186         coff_sym = coff_symbols + i;
187         naux = coff_sym->NumberOfAuxSymbols;
188
189         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE)
190         {
191             curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, 
192                                           (const char*)(coff_sym + 1));
193             TRACE("New file %s\n", (const char*)(coff_sym + 1));
194             i += naux;
195             continue;
196         }
197
198         if (curr_file_idx < 0)
199         {
200             assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0);
201             curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, "<none>");
202             TRACE("New file <none>\n");
203         }
204
205         /*
206          * This guy marks the size and location of the text section
207          * for the current file.  We need to keep track of this so
208          * we can figure out what file the different global functions
209          * go with.
210          */
211         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC &&
212             naux != 0 && coff_sym->Type == 0 && coff_sym->SectionNumber == 1)
213         {
214             aux = (const IMAGE_AUX_SYMBOL*) (coff_sym + 1);
215
216             if (coff_files.files[curr_file_idx].linetab_offset != -1)
217             {
218                 /*
219                  * Save this so we can still get the old name.
220                  */
221                 const char* fn;
222
223                 fn = source_get(msc_dbg->module, 
224                                 coff_files.files[curr_file_idx].compiland->source);
225
226                 TRACE("Duplicating sect from %s: %lx %x %x %d %d\n",
227                       fn, aux->Section.Length,
228                       aux->Section.NumberOfRelocations,
229                       aux->Section.NumberOfLinenumbers,
230                       aux->Section.Number, aux->Section.Selection);
231                 TRACE("More sect %d %s %08lx %d %d %d\n",
232                       coff_sym->SectionNumber,
233                       coff_get_name(coff_sym, coff_strtab),
234                       coff_sym->Value, coff_sym->Type,
235                       coff_sym->StorageClass, coff_sym->NumberOfAuxSymbols);
236
237                 /*
238                  * Duplicate the file entry.  We have no way to describe
239                  * multiple text sections in our current way of handling things.
240                  */
241                 coff_add_file(&coff_files, msc_dbg->module, fn);
242             }
243             else
244             {
245                 TRACE("New text sect from %s: %lx %x %x %d %d\n",
246                       source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source),
247                       aux->Section.Length,
248                       aux->Section.NumberOfRelocations,
249                       aux->Section.NumberOfLinenumbers,
250                       aux->Section.Number, aux->Section.Selection);
251             }
252
253             if (coff_files.files[curr_file_idx].startaddr > coff_sym->Value)
254             {
255                 coff_files.files[curr_file_idx].startaddr = coff_sym->Value;
256             }
257
258             if (coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length)
259             {
260                 coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length;
261             }
262
263             coff_files.files[curr_file_idx].linetab_offset = linetab_indx;
264             coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers;
265             linetab_indx += aux->Section.NumberOfLinenumbers;
266             i += naux;
267             continue;
268         }
269
270         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 && 
271             coff_sym->SectionNumber == 1)
272         {
273             DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
274             /*
275              * This is a normal static function when naux == 0.
276              * Just register it.  The current file is the correct
277              * one in this instance.
278              */
279             nampnt = coff_get_name(coff_sym, coff_strtab);
280
281             TRACE("\tAdding static symbol %s\n", nampnt);
282
283             /* FIXME: was adding symbol to this_file ??? */
284             coff_add_symbol(&coff_files.files[curr_file_idx],
285                             &symt_new_function(msc_dbg->module, 
286                                                coff_files.files[curr_file_idx].compiland, 
287                                                nampnt,
288                                                msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
289                                                0 /* FIXME */,
290                                                NULL /* FIXME */)->symt);
291             i += naux;
292             continue;
293         }
294
295         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
296             ISFCN(coff_sym->Type) && coff_sym->SectionNumber > 0)
297         {
298             struct symt_compiland* compiland = NULL;
299             DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
300             nampnt = coff_get_name(coff_sym, coff_strtab);
301
302             TRACE("%d: %s %s\n",
303                   i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value),
304                   nampnt);
305             TRACE("\tAdding global symbol %s (sect=%s)\n",
306                   nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name);
307
308             /*
309              * Now we need to figure out which file this guy belongs to.
310              */
311             for (j = 0; j < coff_files.nfiles; j++)
312             {
313                 if (coff_files.files[j].startaddr <= base + coff_sym->Value
314                      && coff_files.files[j].endaddr > base + coff_sym->Value)
315                 {
316                     compiland = coff_files.files[j].compiland;
317                     break;
318                 }
319             }
320             if (j < coff_files.nfiles)
321             {
322                 coff_add_symbol(&coff_files.files[j],
323                                 &symt_new_function(msc_dbg->module, compiland, nampnt, 
324                                                    msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
325                                                    0 /* FIXME */, NULL /* FIXME */)->symt);
326             } 
327             else 
328             {
329                 symt_new_function(msc_dbg->module, NULL, nampnt, 
330                                   msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
331                                   0 /* FIXME */, NULL /* FIXME */);
332             }
333             i += naux;
334             continue;
335         }
336
337         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
338             coff_sym->SectionNumber > 0)
339         {
340             DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
341             /*
342              * Similar to above, but for the case of data symbols.
343              * These aren't treated as entrypoints.
344              */
345             nampnt = coff_get_name(coff_sym, coff_strtab);
346
347             TRACE("%d: %s %s\n",
348                   i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value),
349                   nampnt);
350             TRACE("\tAdding global data symbol %s\n", nampnt);
351
352             /*
353              * Now we need to figure out which file this guy belongs to.
354              */
355             symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */,
356                                      msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
357                                      0 /* FIXME */, NULL /* FIXME */);
358             i += naux;
359             continue;
360         }
361
362         if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0)
363         {
364             /*
365              * Ignore these.  They don't have anything to do with
366              * reality.
367              */
368             i += naux;
369             continue;
370         }
371
372         TRACE("Skipping unknown entry '%s' %d %d %d\n",
373               coff_get_name(coff_sym, coff_strtab),
374               coff_sym->StorageClass, coff_sym->SectionNumber, naux);
375         
376         /*
377          * For now, skip past the aux entries.
378          */
379         i += naux;
380     }
381
382     if (coff_files.files != NULL)
383     {
384         /*
385          * OK, we now should have a list of files, and we should have a list
386          * of entrypoints.  We need to sort the entrypoints so that we are
387          * able to tie the line numbers with the given functions within the
388          * file.
389          */
390         for (j = 0; j < coff_files.nfiles; j++)
391         {
392             if (coff_files.files[j].entries != NULL)
393             {
394                 qsort(coff_files.files[j].entries, coff_files.files[j].neps,
395                       sizeof(struct symt*), symt_cmp_addr);
396             }
397         }
398
399         /*
400          * Now pick apart the line number tables, and attach the entries
401          * to the given functions.
402          */
403         for (j = 0; j < coff_files.nfiles; j++)
404         {
405             l = 0;
406             if (coff_files.files[j].neps != 0)
407             {
408                 for (k = 0; k < coff_files.files[j].linecnt; k++)
409                 {
410                     linepnt = coff_linetab + coff_files.files[j].linetab_offset + k;
411                     /*
412                      * If we have spilled onto the next entrypoint, then
413                      * bump the counter..
414                      */
415                     for (;;)
416                     {
417                         if (l+1 >= coff_files.files[j].neps) break;
418                         symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
419                         if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr))
420                             break;
421                         l++;
422                     }
423
424                     if (coff_files.files[j].entries[l+1]->tag == SymTagFunction)
425                     {
426                         /*
427                          * Add the line number.  This is always relative to the
428                          * start of the function, so we need to subtract that offset
429                          * first.
430                          */
431                         symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
432                         symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], 
433                                            coff_files.files[j].compiland->source, linepnt->Linenumber,
434                                            msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr);
435                     }
436                 }
437             }
438         }
439
440         for (j = 0; j < coff_files.nfiles; j++)
441         {
442             HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries);
443         }
444         HeapFree(GetProcessHeap(), 0, coff_files.files);
445         msc_dbg->module->module.SymType = SymCoff;
446         /* FIXME: we could have a finer grain here */
447         msc_dbg->module->module.LineNumbers = TRUE;
448         msc_dbg->module->module.GlobalSymbols = TRUE;
449         msc_dbg->module->module.TypeInfo = FALSE;
450         msc_dbg->module->module.SourceIndexed = TRUE;
451         msc_dbg->module->module.Publics = TRUE;
452         ret = TRUE;
453     }
454
455     return ret;
456 }