- moved into new mscvpdb.h (out of msc.c) all types and defines needed
to parse debug files generated by MS tools - moved into coff.c (and out of msc.c) the COFF handling - cleaned lots of types (add consistency across structs) - versioning of some defines and types (to follow MS tools evolution) - enhanced V2 of symbols parsing (some more types recognized, support of imported .pdb files) - added support for newest .pdb format
This commit is contained in:
parent
970a877995
commit
9995c7d368
|
@ -6,6 +6,7 @@ MODULE = dbghelp.dll
|
|||
IMPORTS = psapi kernel32 ntdll
|
||||
|
||||
C_SRCS = \
|
||||
coff.c \
|
||||
dbghelp.c \
|
||||
elf_module.c \
|
||||
image.c \
|
||||
|
|
|
@ -0,0 +1,454 @@
|
|||
/*
|
||||
* Read VC++ debug information from COFF and eventually
|
||||
* from PDB files.
|
||||
*
|
||||
* Copyright (C) 1996, Eric Youngdale.
|
||||
* Copyright (C) 1999-2000, Ulrich Weigand.
|
||||
* Copyright (C) 2004, Eric Pouech.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note - this handles reading debug information for 32 bit applications
|
||||
* that run under Windows-NT for example. I doubt that this would work well
|
||||
* for 16 bit applications, but I don't think it really matters since the
|
||||
* file format is different, and we should never get in here in such cases.
|
||||
*
|
||||
* TODO:
|
||||
* Get 16 bit CV stuff working.
|
||||
* Add symbol size to internal symbol table.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX MAX_PATH
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "winternl.h"
|
||||
|
||||
#include "wine/exception.h"
|
||||
#include "wine/debug.h"
|
||||
#include "excpt.h"
|
||||
#include "dbghelp_private.h"
|
||||
#include "mscvpdb.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff);
|
||||
|
||||
/*========================================================================
|
||||
* Process COFF debug information.
|
||||
*/
|
||||
|
||||
struct CoffFile
|
||||
{
|
||||
unsigned int startaddr;
|
||||
unsigned int endaddr;
|
||||
struct symt_compiland* compiland;
|
||||
int linetab_offset;
|
||||
int linecnt;
|
||||
struct symt** entries;
|
||||
int neps;
|
||||
int neps_alloc;
|
||||
};
|
||||
|
||||
struct CoffFileSet
|
||||
{
|
||||
struct CoffFile* files;
|
||||
int nfiles;
|
||||
int nfiles_alloc;
|
||||
};
|
||||
|
||||
static const char* coff_get_name(const IMAGE_SYMBOL* coff_sym,
|
||||
const char* coff_strtab)
|
||||
{
|
||||
static char namebuff[9];
|
||||
const char* nampnt;
|
||||
|
||||
if (coff_sym->N.Name.Short)
|
||||
{
|
||||
memcpy(namebuff, coff_sym->N.ShortName, 8);
|
||||
namebuff[8] = '\0';
|
||||
nampnt = &namebuff[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
nampnt = coff_strtab + coff_sym->N.Name.Long;
|
||||
}
|
||||
|
||||
if (nampnt[0] == '_') nampnt++;
|
||||
return nampnt;
|
||||
}
|
||||
|
||||
static int coff_add_file(struct CoffFileSet* coff_files, struct module* module,
|
||||
const char* filename)
|
||||
{
|
||||
struct CoffFile* file;
|
||||
|
||||
if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc)
|
||||
{
|
||||
coff_files->nfiles_alloc += 10;
|
||||
coff_files->files = (coff_files->files) ?
|
||||
HeapReAlloc(GetProcessHeap(), 0, coff_files->files,
|
||||
coff_files->nfiles_alloc * sizeof(struct CoffFile)) :
|
||||
HeapAlloc(GetProcessHeap(), 0,
|
||||
coff_files->nfiles_alloc * sizeof(struct CoffFile));
|
||||
}
|
||||
file = coff_files->files + coff_files->nfiles;
|
||||
file->startaddr = 0xffffffff;
|
||||
file->endaddr = 0;
|
||||
file->compiland = symt_new_compiland(module, filename);
|
||||
file->linetab_offset = -1;
|
||||
file->linecnt = 0;
|
||||
file->entries = NULL;
|
||||
file->neps = file->neps_alloc = 0;
|
||||
|
||||
return coff_files->nfiles++;
|
||||
}
|
||||
|
||||
static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym)
|
||||
{
|
||||
if (coff_file->neps + 1 >= coff_file->neps_alloc)
|
||||
{
|
||||
coff_file->neps_alloc += 10;
|
||||
coff_file->entries = (coff_file->entries) ?
|
||||
HeapReAlloc(GetProcessHeap(), 0, coff_file->entries,
|
||||
coff_file->neps_alloc * sizeof(struct symt*)) :
|
||||
HeapAlloc(GetProcessHeap(), 0,
|
||||
coff_file->neps_alloc * sizeof(struct symt*));
|
||||
}
|
||||
coff_file->entries[coff_file->neps++] = sym;
|
||||
}
|
||||
|
||||
BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
|
||||
{
|
||||
const IMAGE_AUX_SYMBOL* aux;
|
||||
const IMAGE_COFF_SYMBOLS_HEADER* coff;
|
||||
const IMAGE_LINENUMBER* coff_linetab;
|
||||
const IMAGE_LINENUMBER* linepnt;
|
||||
const char* coff_strtab;
|
||||
const IMAGE_SYMBOL* coff_sym;
|
||||
const IMAGE_SYMBOL* coff_symbols;
|
||||
struct CoffFileSet coff_files;
|
||||
int curr_file_idx = -1;
|
||||
unsigned int i;
|
||||
int j;
|
||||
int k;
|
||||
int l;
|
||||
int linetab_indx;
|
||||
const char* nampnt;
|
||||
int naux;
|
||||
BOOL ret = FALSE;
|
||||
DWORD addr;
|
||||
|
||||
TRACE("Processing COFF symbols...\n");
|
||||
|
||||
assert(sizeof(IMAGE_SYMBOL) == IMAGE_SIZEOF_SYMBOL);
|
||||
assert(sizeof(IMAGE_LINENUMBER) == IMAGE_SIZEOF_LINENUMBER);
|
||||
|
||||
coff_files.files = NULL;
|
||||
coff_files.nfiles = coff_files.nfiles_alloc = 0;
|
||||
|
||||
coff = (const IMAGE_COFF_SYMBOLS_HEADER*)msc_dbg->root;
|
||||
|
||||
coff_symbols = (const IMAGE_SYMBOL*)((unsigned int)coff +
|
||||
coff->LvaToFirstSymbol);
|
||||
coff_linetab = (const IMAGE_LINENUMBER*)((unsigned int)coff +
|
||||
coff->LvaToFirstLinenumber);
|
||||
coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols);
|
||||
|
||||
linetab_indx = 0;
|
||||
|
||||
for (i = 0; i < coff->NumberOfSymbols; i++)
|
||||
{
|
||||
coff_sym = coff_symbols + i;
|
||||
naux = coff_sym->NumberOfAuxSymbols;
|
||||
|
||||
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE)
|
||||
{
|
||||
curr_file_idx = coff_add_file(&coff_files, msc_dbg->module,
|
||||
(const char*)(coff_sym + 1));
|
||||
TRACE("New file %s\n", (const char*)(coff_sym + 1));
|
||||
i += naux;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr_file_idx < 0)
|
||||
{
|
||||
assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0);
|
||||
curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, "<none>");
|
||||
TRACE("New file <none>\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* This guy marks the size and location of the text section
|
||||
* for the current file. We need to keep track of this so
|
||||
* we can figure out what file the different global functions
|
||||
* go with.
|
||||
*/
|
||||
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC &&
|
||||
naux != 0 && coff_sym->Type == 0 && coff_sym->SectionNumber == 1)
|
||||
{
|
||||
aux = (const IMAGE_AUX_SYMBOL*) (coff_sym + 1);
|
||||
|
||||
if (coff_files.files[curr_file_idx].linetab_offset != -1)
|
||||
{
|
||||
/*
|
||||
* Save this so we can still get the old name.
|
||||
*/
|
||||
const char* fn;
|
||||
|
||||
fn = source_get(msc_dbg->module,
|
||||
coff_files.files[curr_file_idx].compiland->source);
|
||||
|
||||
TRACE("Duplicating sect from %s: %lx %x %x %d %d\n",
|
||||
fn, aux->Section.Length,
|
||||
aux->Section.NumberOfRelocations,
|
||||
aux->Section.NumberOfLinenumbers,
|
||||
aux->Section.Number, aux->Section.Selection);
|
||||
TRACE("More sect %d %s %08lx %d %d %d\n",
|
||||
coff_sym->SectionNumber,
|
||||
coff_get_name(coff_sym, coff_strtab),
|
||||
coff_sym->Value, coff_sym->Type,
|
||||
coff_sym->StorageClass, coff_sym->NumberOfAuxSymbols);
|
||||
|
||||
/*
|
||||
* Duplicate the file entry. We have no way to describe
|
||||
* multiple text sections in our current way of handling things.
|
||||
*/
|
||||
coff_add_file(&coff_files, msc_dbg->module, fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("New text sect from %s: %lx %x %x %d %d\n",
|
||||
source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source),
|
||||
aux->Section.Length,
|
||||
aux->Section.NumberOfRelocations,
|
||||
aux->Section.NumberOfLinenumbers,
|
||||
aux->Section.Number, aux->Section.Selection);
|
||||
}
|
||||
|
||||
if (coff_files.files[curr_file_idx].startaddr > coff_sym->Value)
|
||||
{
|
||||
coff_files.files[curr_file_idx].startaddr = coff_sym->Value;
|
||||
}
|
||||
|
||||
if (coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length)
|
||||
{
|
||||
coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length;
|
||||
}
|
||||
|
||||
coff_files.files[curr_file_idx].linetab_offset = linetab_indx;
|
||||
coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers;
|
||||
linetab_indx += aux->Section.NumberOfLinenumbers;
|
||||
i += naux;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 &&
|
||||
coff_sym->SectionNumber == 1)
|
||||
{
|
||||
DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
/*
|
||||
* This is a normal static function when naux == 0.
|
||||
* Just register it. The current file is the correct
|
||||
* one in this instance.
|
||||
*/
|
||||
nampnt = coff_get_name(coff_sym, coff_strtab);
|
||||
|
||||
TRACE("\tAdding static symbol %s\n", nampnt);
|
||||
|
||||
/* FIXME: was adding symbol to this_file ??? */
|
||||
coff_add_symbol(&coff_files.files[curr_file_idx],
|
||||
&symt_new_function(msc_dbg->module,
|
||||
coff_files.files[curr_file_idx].compiland,
|
||||
nampnt,
|
||||
msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
|
||||
0 /* FIXME */,
|
||||
NULL /* FIXME */)->symt);
|
||||
i += naux;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
|
||||
ISFCN(coff_sym->Type) && coff_sym->SectionNumber > 0)
|
||||
{
|
||||
struct symt_compiland* compiland = NULL;
|
||||
DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
nampnt = coff_get_name(coff_sym, coff_strtab);
|
||||
|
||||
TRACE("%d: %lx %s\n",
|
||||
i, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
|
||||
nampnt);
|
||||
TRACE("\tAdding global symbol %s (sect=%s)\n",
|
||||
nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name);
|
||||
|
||||
/*
|
||||
* Now we need to figure out which file this guy belongs to.
|
||||
*/
|
||||
for (j = 0; j < coff_files.nfiles; j++)
|
||||
{
|
||||
if (coff_files.files[j].startaddr <= base + coff_sym->Value
|
||||
&& coff_files.files[j].endaddr > base + coff_sym->Value)
|
||||
{
|
||||
compiland = coff_files.files[j].compiland;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < coff_files.nfiles)
|
||||
{
|
||||
coff_add_symbol(&coff_files.files[j],
|
||||
&symt_new_function(msc_dbg->module, compiland, nampnt,
|
||||
msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
|
||||
0 /* FIXME */, NULL /* FIXME */)->symt);
|
||||
}
|
||||
else
|
||||
{
|
||||
symt_new_function(msc_dbg->module, NULL, nampnt,
|
||||
msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
|
||||
0 /* FIXME */, NULL /* FIXME */);
|
||||
}
|
||||
i += naux;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
|
||||
coff_sym->SectionNumber > 0)
|
||||
{
|
||||
DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
/*
|
||||
* Similar to above, but for the case of data symbols.
|
||||
* These aren't treated as entrypoints.
|
||||
*/
|
||||
nampnt = coff_get_name(coff_sym, coff_strtab);
|
||||
|
||||
TRACE("%d: %lx %s\n",
|
||||
i, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
|
||||
nampnt);
|
||||
TRACE("\tAdding global data symbol %s\n", nampnt);
|
||||
|
||||
/*
|
||||
* Now we need to figure out which file this guy belongs to.
|
||||
*/
|
||||
symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */,
|
||||
msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
|
||||
0 /* FIXME */, NULL /* FIXME */);
|
||||
i += naux;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0)
|
||||
{
|
||||
/*
|
||||
* Ignore these. They don't have anything to do with
|
||||
* reality.
|
||||
*/
|
||||
i += naux;
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE("Skipping unknown entry '%s' %d %d %d\n",
|
||||
coff_get_name(coff_sym, coff_strtab),
|
||||
coff_sym->StorageClass, coff_sym->SectionNumber, naux);
|
||||
|
||||
/*
|
||||
* For now, skip past the aux entries.
|
||||
*/
|
||||
i += naux;
|
||||
}
|
||||
|
||||
if (coff_files.files != NULL)
|
||||
{
|
||||
/*
|
||||
* OK, we now should have a list of files, and we should have a list
|
||||
* of entrypoints. We need to sort the entrypoints so that we are
|
||||
* able to tie the line numbers with the given functions within the
|
||||
* file.
|
||||
*/
|
||||
for (j = 0; j < coff_files.nfiles; j++)
|
||||
{
|
||||
if (coff_files.files[j].entries != NULL)
|
||||
{
|
||||
qsort(coff_files.files[j].entries, coff_files.files[j].neps,
|
||||
sizeof(struct symt*), symt_cmp_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now pick apart the line number tables, and attach the entries
|
||||
* to the given functions.
|
||||
*/
|
||||
for (j = 0; j < coff_files.nfiles; j++)
|
||||
{
|
||||
l = 0;
|
||||
if (coff_files.files[j].neps != 0)
|
||||
{
|
||||
for (k = 0; k < coff_files.files[j].linecnt; k++)
|
||||
{
|
||||
linepnt = coff_linetab + coff_files.files[j].linetab_offset + k;
|
||||
/*
|
||||
* If we have spilled onto the next entrypoint, then
|
||||
* bump the counter..
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
if (l+1 >= coff_files.files[j].neps) break;
|
||||
symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
|
||||
if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr))
|
||||
break;
|
||||
l++;
|
||||
}
|
||||
|
||||
if (coff_files.files[j].entries[l+1]->tag == SymTagFunction)
|
||||
{
|
||||
/*
|
||||
* Add the line number. This is always relative to the
|
||||
* start of the function, so we need to subtract that offset
|
||||
* first.
|
||||
*/
|
||||
symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
|
||||
symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1],
|
||||
coff_files.files[j].compiland->source, linepnt->Linenumber,
|
||||
msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < coff_files.nfiles; j++)
|
||||
{
|
||||
if (coff_files.files[j].entries != NULL)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries);
|
||||
}
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, coff_files.files);
|
||||
msc_dbg->module->module.SymType = SymCoff;
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
3201
dlls/dbghelp/msc.c
3201
dlls/dbghelp/msc.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue