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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
54 #include "wine/exception.h"
55 #include "wine/debug.h"
57 #include "dbghelp_private.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff);
62 /*========================================================================
63 * Process COFF debug information.
68 unsigned int startaddr;
70 struct symt_compiland* compiland;
73 struct symt** entries;
80 struct CoffFile* files;
85 static const char* coff_get_name(const IMAGE_SYMBOL* coff_sym,
86 const char* coff_strtab)
88 static char namebuff[9];
91 if (coff_sym->N.Name.Short)
93 memcpy(namebuff, coff_sym->N.ShortName, 8);
95 nampnt = &namebuff[0];
99 nampnt = coff_strtab + coff_sym->N.Name.Long;
102 if (nampnt[0] == '_') nampnt++;
106 static int coff_add_file(struct CoffFileSet* coff_files, struct module* module,
107 const char* filename)
109 struct CoffFile* file;
111 if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc)
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));
120 file = coff_files->files + coff_files->nfiles;
121 file->startaddr = 0xffffffff;
123 file->compiland = symt_new_compiland(module, filename);
124 file->linetab_offset = -1;
126 file->entries = NULL;
127 file->neps = file->neps_alloc = 0;
129 return coff_files->nfiles++;
132 static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym)
134 if (coff_file->neps + 1 >= coff_file->neps_alloc)
136 coff_file->neps_alloc += 10;
137 coff_file->entries = (coff_file->entries) ?
138 HeapReAlloc(GetProcessHeap(), 0, coff_file->entries,
139 coff_file->neps_alloc * sizeof(struct symt*)) :
140 HeapAlloc(GetProcessHeap(), 0,
141 coff_file->neps_alloc * sizeof(struct symt*));
143 coff_file->entries[coff_file->neps++] = sym;
146 BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
148 const IMAGE_AUX_SYMBOL* aux;
149 const IMAGE_COFF_SYMBOLS_HEADER* coff;
150 const IMAGE_LINENUMBER* coff_linetab;
151 const IMAGE_LINENUMBER* linepnt;
152 const char* coff_strtab;
153 const IMAGE_SYMBOL* coff_sym;
154 const IMAGE_SYMBOL* coff_symbols;
155 struct CoffFileSet coff_files;
156 int curr_file_idx = -1;
167 TRACE("Processing COFF symbols...\n");
169 assert(sizeof(IMAGE_SYMBOL) == IMAGE_SIZEOF_SYMBOL);
170 assert(sizeof(IMAGE_LINENUMBER) == IMAGE_SIZEOF_LINENUMBER);
172 coff_files.files = NULL;
173 coff_files.nfiles = coff_files.nfiles_alloc = 0;
175 coff = (const IMAGE_COFF_SYMBOLS_HEADER*)msc_dbg->root;
177 coff_symbols = (const IMAGE_SYMBOL*)((unsigned int)coff +
178 coff->LvaToFirstSymbol);
179 coff_linetab = (const IMAGE_LINENUMBER*)((unsigned int)coff +
180 coff->LvaToFirstLinenumber);
181 coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols);
185 for (i = 0; i < coff->NumberOfSymbols; i++)
187 coff_sym = coff_symbols + i;
188 naux = coff_sym->NumberOfAuxSymbols;
190 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE)
192 curr_file_idx = coff_add_file(&coff_files, msc_dbg->module,
193 (const char*)(coff_sym + 1));
194 TRACE("New file %s\n", (const char*)(coff_sym + 1));
199 if (curr_file_idx < 0)
201 assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0);
202 curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, "<none>");
203 TRACE("New file <none>\n");
207 * This guy marks the size and location of the text section
208 * for the current file. We need to keep track of this so
209 * we can figure out what file the different global functions
212 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC &&
213 naux != 0 && coff_sym->Type == 0 && coff_sym->SectionNumber == 1)
215 aux = (const IMAGE_AUX_SYMBOL*) (coff_sym + 1);
217 if (coff_files.files[curr_file_idx].linetab_offset != -1)
220 * Save this so we can still get the old name.
224 fn = source_get(msc_dbg->module,
225 coff_files.files[curr_file_idx].compiland->source);
227 TRACE("Duplicating sect from %s: %lx %x %x %d %d\n",
228 fn, aux->Section.Length,
229 aux->Section.NumberOfRelocations,
230 aux->Section.NumberOfLinenumbers,
231 aux->Section.Number, aux->Section.Selection);
232 TRACE("More sect %d %s %08lx %d %d %d\n",
233 coff_sym->SectionNumber,
234 coff_get_name(coff_sym, coff_strtab),
235 coff_sym->Value, coff_sym->Type,
236 coff_sym->StorageClass, coff_sym->NumberOfAuxSymbols);
239 * Duplicate the file entry. We have no way to describe
240 * multiple text sections in our current way of handling things.
242 coff_add_file(&coff_files, msc_dbg->module, fn);
246 TRACE("New text sect from %s: %lx %x %x %d %d\n",
247 source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source),
249 aux->Section.NumberOfRelocations,
250 aux->Section.NumberOfLinenumbers,
251 aux->Section.Number, aux->Section.Selection);
254 if (coff_files.files[curr_file_idx].startaddr > coff_sym->Value)
256 coff_files.files[curr_file_idx].startaddr = coff_sym->Value;
259 if (coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length)
261 coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length;
264 coff_files.files[curr_file_idx].linetab_offset = linetab_indx;
265 coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers;
266 linetab_indx += aux->Section.NumberOfLinenumbers;
271 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 &&
272 coff_sym->SectionNumber == 1)
274 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
276 * This is a normal static function when naux == 0.
277 * Just register it. The current file is the correct
278 * one in this instance.
280 nampnt = coff_get_name(coff_sym, coff_strtab);
282 TRACE("\tAdding static symbol %s\n", nampnt);
284 /* FIXME: was adding symbol to this_file ??? */
285 coff_add_symbol(&coff_files.files[curr_file_idx],
286 &symt_new_function(msc_dbg->module,
287 coff_files.files[curr_file_idx].compiland,
289 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
291 NULL /* FIXME */)->symt);
296 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
297 ISFCN(coff_sym->Type) && coff_sym->SectionNumber > 0)
299 struct symt_compiland* compiland = NULL;
300 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
301 nampnt = coff_get_name(coff_sym, coff_strtab);
303 TRACE("%d: %lx %s\n",
304 i, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
306 TRACE("\tAdding global symbol %s (sect=%s)\n",
307 nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name);
310 * Now we need to figure out which file this guy belongs to.
312 for (j = 0; j < coff_files.nfiles; j++)
314 if (coff_files.files[j].startaddr <= base + coff_sym->Value
315 && coff_files.files[j].endaddr > base + coff_sym->Value)
317 compiland = coff_files.files[j].compiland;
321 if (j < coff_files.nfiles)
323 coff_add_symbol(&coff_files.files[j],
324 &symt_new_function(msc_dbg->module, compiland, nampnt,
325 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
326 0 /* FIXME */, NULL /* FIXME */)->symt);
330 symt_new_function(msc_dbg->module, NULL, nampnt,
331 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
332 0 /* FIXME */, NULL /* FIXME */);
338 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
339 coff_sym->SectionNumber > 0)
341 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
343 * Similar to above, but for the case of data symbols.
344 * These aren't treated as entrypoints.
346 nampnt = coff_get_name(coff_sym, coff_strtab);
348 TRACE("%d: %lx %s\n",
349 i, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
351 TRACE("\tAdding global data symbol %s\n", nampnt);
354 * Now we need to figure out which file this guy belongs to.
356 symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */,
357 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
358 0 /* FIXME */, NULL /* FIXME */);
363 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0)
366 * Ignore these. They don't have anything to do with
373 TRACE("Skipping unknown entry '%s' %d %d %d\n",
374 coff_get_name(coff_sym, coff_strtab),
375 coff_sym->StorageClass, coff_sym->SectionNumber, naux);
378 * For now, skip past the aux entries.
383 if (coff_files.files != NULL)
386 * OK, we now should have a list of files, and we should have a list
387 * of entrypoints. We need to sort the entrypoints so that we are
388 * able to tie the line numbers with the given functions within the
391 for (j = 0; j < coff_files.nfiles; j++)
393 if (coff_files.files[j].entries != NULL)
395 qsort(coff_files.files[j].entries, coff_files.files[j].neps,
396 sizeof(struct symt*), symt_cmp_addr);
401 * Now pick apart the line number tables, and attach the entries
402 * to the given functions.
404 for (j = 0; j < coff_files.nfiles; j++)
407 if (coff_files.files[j].neps != 0)
409 for (k = 0; k < coff_files.files[j].linecnt; k++)
411 linepnt = coff_linetab + coff_files.files[j].linetab_offset + k;
413 * If we have spilled onto the next entrypoint, then
418 if (l+1 >= coff_files.files[j].neps) break;
419 symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
420 if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr))
425 if (coff_files.files[j].entries[l+1]->tag == SymTagFunction)
428 * Add the line number. This is always relative to the
429 * start of the function, so we need to subtract that offset
432 symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
433 symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1],
434 coff_files.files[j].compiland->source, linepnt->Linenumber,
435 msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr);
441 for (j = 0; j < coff_files.nfiles; j++)
443 HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries);
445 HeapFree(GetProcessHeap(), 0, coff_files.files);
446 msc_dbg->module->module.SymType = SymCoff;