cmd: DIR command outputs free space for the path.
[wine.git] / dlls / dbghelp / coff.c
blob57d0175c5c28949becdd22b9a8b5f7330f03f86f
1 /*
2 * Read VC++ debug information from COFF and eventually
3 * from PDB files.
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.
30 * TODO:
31 * Get 16 bit CV stuff working.
32 * Add symbol size to internal symbol table.
35 #include <assert.h>
36 #include <stdlib.h>
37 #include <string.h>
39 #include <stdarg.h>
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winternl.h"
44 #include "wine/debug.h"
45 #include "dbghelp_private.h"
46 #include "wine/mscvpdb.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff);
50 /*========================================================================
51 * Process COFF debug information.
54 struct CoffFile
56 unsigned int startaddr;
57 unsigned int endaddr;
58 struct symt_compiland* compiland;
59 int linetab_offset;
60 int linecnt;
61 struct symt** entries;
62 int neps;
63 int neps_alloc;
66 struct CoffFileSet
68 struct CoffFile* files;
69 int nfiles;
70 int nfiles_alloc;
73 static const char* coff_get_name(const IMAGE_SYMBOL* coff_sym,
74 const char* coff_strtab)
76 static char namebuff[9];
77 const char* nampnt;
79 if (coff_sym->N.Name.Short)
81 memcpy(namebuff, coff_sym->N.ShortName, 8);
82 namebuff[8] = '\0';
83 nampnt = &namebuff[0];
85 else
87 nampnt = coff_strtab + coff_sym->N.Name.Long;
90 if (nampnt[0] == '_') nampnt++;
91 return nampnt;
94 static int coff_add_file(struct CoffFileSet* coff_files, struct module* module,
95 const char* filename)
97 struct CoffFile* file;
99 if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc)
101 if (coff_files->files)
103 coff_files->nfiles_alloc *= 2;
104 coff_files->files = HeapReAlloc(GetProcessHeap(), 0, coff_files->files,
105 coff_files->nfiles_alloc * sizeof(struct CoffFile));
107 else
109 coff_files->nfiles_alloc = 16;
110 coff_files->files = HeapAlloc(GetProcessHeap(), 0,
111 coff_files->nfiles_alloc * sizeof(struct CoffFile));
114 file = coff_files->files + coff_files->nfiles;
115 file->startaddr = 0xffffffff;
116 file->endaddr = 0;
117 file->compiland = symt_new_compiland(module, source_new(module, NULL, filename));
118 file->linetab_offset = -1;
119 file->linecnt = 0;
120 file->entries = NULL;
121 file->neps = file->neps_alloc = 0;
123 return coff_files->nfiles++;
126 static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym)
128 if (coff_file->neps + 1 >= coff_file->neps_alloc)
130 if (coff_file->entries)
132 coff_file->neps_alloc *= 2;
133 coff_file->entries = HeapReAlloc(GetProcessHeap(), 0, coff_file->entries,
134 coff_file->neps_alloc * sizeof(struct symt*));
136 else
138 coff_file->neps_alloc = 32;
139 coff_file->entries = HeapAlloc(GetProcessHeap(), 0,
140 coff_file->neps_alloc * sizeof(struct symt*));
143 coff_file->entries[coff_file->neps++] = sym;
146 DECLSPEC_HIDDEN 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;
157 unsigned int i;
158 int j;
159 int k;
160 int l;
161 int linetab_indx;
162 const char* nampnt;
163 int naux;
164 BOOL ret = FALSE;
165 ULONG64 addr;
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*)((const char *)coff + coff->LvaToFirstSymbol);
178 coff_linetab = (const IMAGE_LINENUMBER*)((const char *)coff + coff->LvaToFirstLinenumber);
179 coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols);
181 linetab_indx = 0;
183 for (i = 0; i < coff->NumberOfSymbols; i++)
185 coff_sym = coff_symbols + i;
186 naux = coff_sym->NumberOfAuxSymbols;
188 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE)
190 curr_file_idx = coff_add_file(&coff_files, msc_dbg->module,
191 (const char*)(coff_sym + 1));
192 TRACE("New file %s\n", (const char*)(coff_sym + 1));
193 i += naux;
194 continue;
197 if (curr_file_idx < 0)
199 assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0);
200 curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, "<none>");
201 TRACE("New file <none>\n");
205 * This guy marks the size and location of the text section
206 * for the current file. We need to keep track of this so
207 * we can figure out what file the different global functions
208 * go with.
210 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC &&
211 naux != 0 && coff_sym->Type == 0 && coff_sym->SectionNumber == 1)
213 aux = (const IMAGE_AUX_SYMBOL*) (coff_sym + 1);
215 if (coff_files.files[curr_file_idx].linetab_offset != -1)
218 * Save this so we can still get the old name.
220 const char* fn;
222 fn = source_get(msc_dbg->module,
223 coff_files.files[curr_file_idx].compiland->source);
225 TRACE("Duplicating sect from %s: %lx %x %x %d %d\n",
226 fn, aux->Section.Length,
227 aux->Section.NumberOfRelocations,
228 aux->Section.NumberOfLinenumbers,
229 aux->Section.Number, aux->Section.Selection);
230 TRACE("More sect %d %s %08lx %d %d %d\n",
231 coff_sym->SectionNumber,
232 coff_get_name(coff_sym, coff_strtab),
233 coff_sym->Value, coff_sym->Type,
234 coff_sym->StorageClass, coff_sym->NumberOfAuxSymbols);
237 * Duplicate the file entry. We have no way to describe
238 * multiple text sections in our current way of handling things.
240 coff_add_file(&coff_files, msc_dbg->module, fn);
242 else
244 TRACE("New text sect from %s: %lx %x %x %d %d\n",
245 source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source),
246 aux->Section.Length,
247 aux->Section.NumberOfRelocations,
248 aux->Section.NumberOfLinenumbers,
249 aux->Section.Number, aux->Section.Selection);
252 if (coff_files.files[curr_file_idx].startaddr > coff_sym->Value)
254 coff_files.files[curr_file_idx].startaddr = coff_sym->Value;
257 if (coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length)
259 coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length;
262 coff_files.files[curr_file_idx].linetab_offset = linetab_indx;
263 coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers;
264 linetab_indx += aux->Section.NumberOfLinenumbers;
265 i += naux;
266 continue;
269 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 &&
270 coff_sym->SectionNumber == 1)
272 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
274 * This is a normal static function when naux == 0.
275 * Just register it. The current file is the correct
276 * one in this instance.
278 nampnt = coff_get_name(coff_sym, coff_strtab);
280 TRACE("\tAdding static symbol %s\n", nampnt);
282 /* FIXME: was adding symbol to this_file ??? */
283 coff_add_symbol(&coff_files.files[curr_file_idx],
284 &symt_new_function(msc_dbg->module,
285 coff_files.files[curr_file_idx].compiland,
286 nampnt,
287 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
288 0 /* FIXME */,
289 NULL /* FIXME */)->symt);
290 continue;
293 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
294 ISFCN(coff_sym->Type) && coff_sym->SectionNumber > 0)
296 struct symt_compiland* compiland = NULL;
297 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
298 nampnt = coff_get_name(coff_sym, coff_strtab);
300 TRACE("%d: %I64x %s\n",
301 i, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, nampnt);
302 TRACE("\tAdding global symbol %s (sect=%s)\n",
303 nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name);
306 * Now we need to figure out which file this guy belongs to.
308 for (j = 0; j < coff_files.nfiles; j++)
310 if (coff_files.files[j].startaddr <= base + coff_sym->Value
311 && coff_files.files[j].endaddr > base + coff_sym->Value)
313 compiland = coff_files.files[j].compiland;
314 break;
317 if (j < coff_files.nfiles)
319 coff_add_symbol(&coff_files.files[j],
320 &symt_new_function(msc_dbg->module, compiland, nampnt,
321 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
322 0 /* FIXME */, NULL /* FIXME */)->symt);
324 else
326 symt_new_function(msc_dbg->module, NULL, nampnt,
327 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
328 0 /* FIXME */, NULL /* FIXME */);
330 i += naux;
331 continue;
334 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
335 coff_sym->SectionNumber > 0)
337 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
338 struct location loc;
341 * Similar to above, but for the case of data symbols.
342 * These aren't treated as entrypoints.
344 nampnt = coff_get_name(coff_sym, coff_strtab);
346 TRACE("%d: %I64x %s\n",
347 i, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, nampnt);
348 TRACE("\tAdding global data symbol %s\n", nampnt);
351 * Now we need to figure out which file this guy belongs to.
353 loc.kind = loc_absolute;
354 loc.reg = 0;
355 loc.offset = msc_dbg->module->module.BaseOfImage + base + coff_sym->Value;
356 symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */,
357 loc, 0 /* FIXME */, NULL /* FIXME */);
358 i += naux;
359 continue;
362 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0)
365 * Ignore these. They don't have anything to do with
366 * reality.
368 continue;
371 TRACE("Skipping unknown entry '%s' %d %d %d\n",
372 coff_get_name(coff_sym, coff_strtab),
373 coff_sym->StorageClass, coff_sym->SectionNumber, naux);
376 * For now, skip past the aux entries.
378 i += naux;
381 if (coff_files.files != NULL)
384 * OK, we now should have a list of files, and we should have a list
385 * of entrypoints. We need to sort the entrypoints so that we are
386 * able to tie the line numbers with the given functions within the
387 * file.
389 for (j = 0; j < coff_files.nfiles; j++)
391 if (coff_files.files[j].entries != NULL)
393 qsort(coff_files.files[j].entries, coff_files.files[j].neps,
394 sizeof(struct symt*), symt_cmp_addr);
399 * Now pick apart the line number tables, and attach the entries
400 * to the given functions.
402 for (j = 0; j < coff_files.nfiles; j++)
404 l = 0;
405 if (coff_files.files[j].neps != 0)
407 for (k = 0; k < coff_files.files[j].linecnt; k++)
409 linepnt = coff_linetab + coff_files.files[j].linetab_offset + k;
411 * If we have spilled onto the next entrypoint, then
412 * bump the counter..
414 for (; l+1 < coff_files.files[j].neps; l++)
416 if (symt_get_address(coff_files.files[j].entries[l+1], &addr) &&
417 msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress < addr)
419 if (coff_files.files[j].entries[l+1]->tag == SymTagFunction)
421 symt_add_func_line(msc_dbg->module,
422 (struct symt_function*)coff_files.files[j].entries[l+1],
423 coff_files.files[j].compiland->source,
424 linepnt->Linenumber,
425 msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress);
427 break;
434 for (j = 0; j < coff_files.nfiles; j++)
436 HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries);
438 HeapFree(GetProcessHeap(), 0, coff_files.files);
439 msc_dbg->module->module.SymType = SymCoff;
440 /* FIXME: we could have a finer grain here */
441 msc_dbg->module->module.LineNumbers = TRUE;
442 msc_dbg->module->module.GlobalSymbols = TRUE;
443 msc_dbg->module->module.TypeInfo = FALSE;
444 msc_dbg->module->module.SourceIndexed = TRUE;
445 msc_dbg->module->module.Publics = TRUE;
446 ret = TRUE;
449 return ret;