2 * Read VC++ debug information from COFF and eventually
5 * Copyright (C) 1996, Eric Youngdale.
6 * Copyright (C) 1999-2000, Ulrich Weigand.
7 * Copyright (C) 2004, Eric Pouech.
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.
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.
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
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.
31 * Get 16 bit CV stuff working.
32 * Add symbol size to internal symbol table.
36 #include "wine/port.h"
46 #define PATH_MAX MAX_PATH
53 #include "wine/exception.h"
54 #include "wine/debug.h"
55 #include "dbghelp_private.h"
56 #include "wine/mscvpdb.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff
);
60 /*========================================================================
61 * Process COFF debug information.
66 unsigned int startaddr
;
68 struct symt_compiland
* compiland
;
71 struct symt
** entries
;
78 struct CoffFile
* files
;
83 static const char* coff_get_name(const IMAGE_SYMBOL
* coff_sym
,
84 const char* coff_strtab
)
86 static char namebuff
[9];
89 if (coff_sym
->N
.Name
.Short
)
91 memcpy(namebuff
, coff_sym
->N
.ShortName
, 8);
93 nampnt
= &namebuff
[0];
97 nampnt
= coff_strtab
+ coff_sym
->N
.Name
.Long
;
100 if (nampnt
[0] == '_') nampnt
++;
104 static int coff_add_file(struct CoffFileSet
* coff_files
, struct module
* module
,
105 const char* filename
)
107 struct CoffFile
* file
;
109 if (coff_files
->nfiles
+ 1 >= coff_files
->nfiles_alloc
)
111 if (coff_files
->files
)
113 coff_files
->nfiles_alloc
*= 2;
114 coff_files
->files
= HeapReAlloc(GetProcessHeap(), 0, coff_files
->files
,
115 coff_files
->nfiles_alloc
* sizeof(struct CoffFile
));
119 coff_files
->nfiles_alloc
= 16;
120 coff_files
->files
= HeapAlloc(GetProcessHeap(), 0,
121 coff_files
->nfiles_alloc
* sizeof(struct CoffFile
));
124 file
= coff_files
->files
+ coff_files
->nfiles
;
125 file
->startaddr
= 0xffffffff;
127 file
->compiland
= symt_new_compiland(module
, 0,
128 source_new(module
, NULL
, filename
));
129 file
->linetab_offset
= -1;
131 file
->entries
= NULL
;
132 file
->neps
= file
->neps_alloc
= 0;
134 return coff_files
->nfiles
++;
137 static void coff_add_symbol(struct CoffFile
* coff_file
, struct symt
* sym
)
139 if (coff_file
->neps
+ 1 >= coff_file
->neps_alloc
)
141 coff_file
->neps_alloc
*= 2;
142 coff_file
->entries
= (coff_file
->entries
) ?
143 HeapReAlloc(GetProcessHeap(), 0, coff_file
->entries
,
144 coff_file
->neps_alloc
* sizeof(struct symt
*)) :
145 HeapAlloc(GetProcessHeap(), 0,
146 coff_file
->neps_alloc
* sizeof(struct symt
*));
148 coff_file
->entries
[coff_file
->neps
++] = sym
;
151 BOOL
coff_process_info(const struct msc_debug_info
* msc_dbg
)
153 const IMAGE_AUX_SYMBOL
* aux
;
154 const IMAGE_COFF_SYMBOLS_HEADER
* coff
;
155 const IMAGE_LINENUMBER
* coff_linetab
;
156 const IMAGE_LINENUMBER
* linepnt
;
157 const char* coff_strtab
;
158 const IMAGE_SYMBOL
* coff_sym
;
159 const IMAGE_SYMBOL
* coff_symbols
;
160 struct CoffFileSet coff_files
;
161 int curr_file_idx
= -1;
172 TRACE("Processing COFF symbols...\n");
174 assert(sizeof(IMAGE_SYMBOL
) == IMAGE_SIZEOF_SYMBOL
);
175 assert(sizeof(IMAGE_LINENUMBER
) == IMAGE_SIZEOF_LINENUMBER
);
177 coff_files
.files
= NULL
;
178 coff_files
.nfiles
= coff_files
.nfiles_alloc
= 0;
180 coff
= (const IMAGE_COFF_SYMBOLS_HEADER
*)msc_dbg
->root
;
182 coff_symbols
= (const IMAGE_SYMBOL
*)((const char *)coff
+ coff
->LvaToFirstSymbol
);
183 coff_linetab
= (const IMAGE_LINENUMBER
*)((const char *)coff
+ coff
->LvaToFirstLinenumber
);
184 coff_strtab
= (const char*)(coff_symbols
+ coff
->NumberOfSymbols
);
188 for (i
= 0; i
< coff
->NumberOfSymbols
; i
++)
190 coff_sym
= coff_symbols
+ i
;
191 naux
= coff_sym
->NumberOfAuxSymbols
;
193 if (coff_sym
->StorageClass
== IMAGE_SYM_CLASS_FILE
)
195 curr_file_idx
= coff_add_file(&coff_files
, msc_dbg
->module
,
196 (const char*)(coff_sym
+ 1));
197 TRACE("New file %s\n", (const char*)(coff_sym
+ 1));
202 if (curr_file_idx
< 0)
204 assert(coff_files
.nfiles
== 0 && coff_files
.nfiles_alloc
== 0);
205 curr_file_idx
= coff_add_file(&coff_files
, msc_dbg
->module
, "<none>");
206 TRACE("New file <none>\n");
210 * This guy marks the size and location of the text section
211 * for the current file. We need to keep track of this so
212 * we can figure out what file the different global functions
215 if (coff_sym
->StorageClass
== IMAGE_SYM_CLASS_STATIC
&&
216 naux
!= 0 && coff_sym
->Type
== 0 && coff_sym
->SectionNumber
== 1)
218 aux
= (const IMAGE_AUX_SYMBOL
*) (coff_sym
+ 1);
220 if (coff_files
.files
[curr_file_idx
].linetab_offset
!= -1)
223 * Save this so we can still get the old name.
227 fn
= source_get(msc_dbg
->module
,
228 coff_files
.files
[curr_file_idx
].compiland
->source
);
230 TRACE("Duplicating sect from %s: %x %x %x %d %d\n",
231 fn
, aux
->Section
.Length
,
232 aux
->Section
.NumberOfRelocations
,
233 aux
->Section
.NumberOfLinenumbers
,
234 aux
->Section
.Number
, aux
->Section
.Selection
);
235 TRACE("More sect %d %s %08x %d %d %d\n",
236 coff_sym
->SectionNumber
,
237 coff_get_name(coff_sym
, coff_strtab
),
238 coff_sym
->Value
, coff_sym
->Type
,
239 coff_sym
->StorageClass
, coff_sym
->NumberOfAuxSymbols
);
242 * Duplicate the file entry. We have no way to describe
243 * multiple text sections in our current way of handling things.
245 coff_add_file(&coff_files
, msc_dbg
->module
, fn
);
249 TRACE("New text sect from %s: %x %x %x %d %d\n",
250 source_get(msc_dbg
->module
, coff_files
.files
[curr_file_idx
].compiland
->source
),
252 aux
->Section
.NumberOfRelocations
,
253 aux
->Section
.NumberOfLinenumbers
,
254 aux
->Section
.Number
, aux
->Section
.Selection
);
257 if (coff_files
.files
[curr_file_idx
].startaddr
> coff_sym
->Value
)
259 coff_files
.files
[curr_file_idx
].startaddr
= coff_sym
->Value
;
262 if (coff_files
.files
[curr_file_idx
].endaddr
< coff_sym
->Value
+ aux
->Section
.Length
)
264 coff_files
.files
[curr_file_idx
].endaddr
= coff_sym
->Value
+ aux
->Section
.Length
;
267 coff_files
.files
[curr_file_idx
].linetab_offset
= linetab_indx
;
268 coff_files
.files
[curr_file_idx
].linecnt
= aux
->Section
.NumberOfLinenumbers
;
269 linetab_indx
+= aux
->Section
.NumberOfLinenumbers
;
274 if (coff_sym
->StorageClass
== IMAGE_SYM_CLASS_STATIC
&& naux
== 0 &&
275 coff_sym
->SectionNumber
== 1)
277 DWORD base
= msc_dbg
->sectp
[coff_sym
->SectionNumber
- 1].VirtualAddress
;
279 * This is a normal static function when naux == 0.
280 * Just register it. The current file is the correct
281 * one in this instance.
283 nampnt
= coff_get_name(coff_sym
, coff_strtab
);
285 TRACE("\tAdding static symbol %s\n", nampnt
);
287 /* FIXME: was adding symbol to this_file ??? */
288 coff_add_symbol(&coff_files
.files
[curr_file_idx
],
289 &symt_new_function(msc_dbg
->module
,
290 coff_files
.files
[curr_file_idx
].compiland
,
292 msc_dbg
->module
->module
.BaseOfImage
+ base
+ coff_sym
->Value
,
294 NULL
/* FIXME */)->symt
);
299 if (coff_sym
->StorageClass
== IMAGE_SYM_CLASS_EXTERNAL
&&
300 ISFCN(coff_sym
->Type
) && coff_sym
->SectionNumber
> 0)
302 struct symt_compiland
* compiland
= NULL
;
303 DWORD base
= msc_dbg
->sectp
[coff_sym
->SectionNumber
- 1].VirtualAddress
;
304 nampnt
= coff_get_name(coff_sym
, coff_strtab
);
307 i
, wine_dbgstr_longlong(msc_dbg
->module
->module
.BaseOfImage
+ base
+ coff_sym
->Value
),
309 TRACE("\tAdding global symbol %s (sect=%s)\n",
310 nampnt
, msc_dbg
->sectp
[coff_sym
->SectionNumber
- 1].Name
);
313 * Now we need to figure out which file this guy belongs to.
315 for (j
= 0; j
< coff_files
.nfiles
; j
++)
317 if (coff_files
.files
[j
].startaddr
<= base
+ coff_sym
->Value
318 && coff_files
.files
[j
].endaddr
> base
+ coff_sym
->Value
)
320 compiland
= coff_files
.files
[j
].compiland
;
324 if (j
< coff_files
.nfiles
)
326 coff_add_symbol(&coff_files
.files
[j
],
327 &symt_new_function(msc_dbg
->module
, compiland
, nampnt
,
328 msc_dbg
->module
->module
.BaseOfImage
+ base
+ coff_sym
->Value
,
329 0 /* FIXME */, NULL
/* FIXME */)->symt
);
333 symt_new_function(msc_dbg
->module
, NULL
, nampnt
,
334 msc_dbg
->module
->module
.BaseOfImage
+ base
+ coff_sym
->Value
,
335 0 /* FIXME */, NULL
/* FIXME */);
341 if (coff_sym
->StorageClass
== IMAGE_SYM_CLASS_EXTERNAL
&&
342 coff_sym
->SectionNumber
> 0)
344 DWORD base
= msc_dbg
->sectp
[coff_sym
->SectionNumber
- 1].VirtualAddress
;
346 * Similar to above, but for the case of data symbols.
347 * These aren't treated as entrypoints.
349 nampnt
= coff_get_name(coff_sym
, coff_strtab
);
352 i
, wine_dbgstr_longlong(msc_dbg
->module
->module
.BaseOfImage
+ base
+ coff_sym
->Value
),
354 TRACE("\tAdding global data symbol %s\n", nampnt
);
357 * Now we need to figure out which file this guy belongs to.
359 symt_new_global_variable(msc_dbg
->module
, NULL
, nampnt
, TRUE
/* FIXME */,
360 msc_dbg
->module
->module
.BaseOfImage
+ base
+ coff_sym
->Value
,
361 0 /* FIXME */, NULL
/* FIXME */);
366 if (coff_sym
->StorageClass
== IMAGE_SYM_CLASS_STATIC
&& naux
== 0)
369 * Ignore these. They don't have anything to do with
376 TRACE("Skipping unknown entry '%s' %d %d %d\n",
377 coff_get_name(coff_sym
, coff_strtab
),
378 coff_sym
->StorageClass
, coff_sym
->SectionNumber
, naux
);
381 * For now, skip past the aux entries.
386 if (coff_files
.files
!= NULL
)
389 * OK, we now should have a list of files, and we should have a list
390 * of entrypoints. We need to sort the entrypoints so that we are
391 * able to tie the line numbers with the given functions within the
394 for (j
= 0; j
< coff_files
.nfiles
; j
++)
396 if (coff_files
.files
[j
].entries
!= NULL
)
398 symt_cmp_addr_module
= msc_dbg
->module
;
399 qsort(coff_files
.files
[j
].entries
, coff_files
.files
[j
].neps
,
400 sizeof(struct symt
*), symt_cmp_addr
);
405 * Now pick apart the line number tables, and attach the entries
406 * to the given functions.
408 for (j
= 0; j
< coff_files
.nfiles
; j
++)
411 if (coff_files
.files
[j
].neps
!= 0)
413 for (k
= 0; k
< coff_files
.files
[j
].linecnt
; k
++)
415 linepnt
= coff_linetab
+ coff_files
.files
[j
].linetab_offset
+ k
;
417 * If we have spilled onto the next entrypoint, then
422 if (l
+1 >= coff_files
.files
[j
].neps
) break;
423 symt_get_info(msc_dbg
->module
, coff_files
.files
[j
].entries
[l
+1], TI_GET_ADDRESS
, &addr
);
424 if (((msc_dbg
->module
->module
.BaseOfImage
+ linepnt
->Type
.VirtualAddress
) < addr
))
429 if (coff_files
.files
[j
].entries
[l
+1]->tag
== SymTagFunction
)
432 * Add the line number. This is always relative to the
433 * start of the function, so we need to subtract that offset
436 symt_get_info(msc_dbg
->module
, coff_files
.files
[j
].entries
[l
+1], TI_GET_ADDRESS
, &addr
);
437 symt_add_func_line(msc_dbg
->module
, (struct symt_function
*)coff_files
.files
[j
].entries
[l
+1],
438 coff_files
.files
[j
].compiland
->source
, linepnt
->Linenumber
,
439 msc_dbg
->module
->module
.BaseOfImage
+ linepnt
->Type
.VirtualAddress
- addr
);
445 for (j
= 0; j
< coff_files
.nfiles
; j
++)
447 HeapFree(GetProcessHeap(), 0, coff_files
.files
[j
].entries
);
449 HeapFree(GetProcessHeap(), 0, coff_files
.files
);
450 msc_dbg
->module
->module
.SymType
= SymCoff
;
451 /* FIXME: we could have a finer grain here */
452 msc_dbg
->module
->module
.LineNumbers
= TRUE
;
453 msc_dbg
->module
->module
.GlobalSymbols
= TRUE
;
454 msc_dbg
->module
->module
.TypeInfo
= FALSE
;
455 msc_dbg
->module
->module
.SourceIndexed
= TRUE
;
456 msc_dbg
->module
->module
.Publics
= TRUE
;