First shot at importing dbghelp. Its broken. Dont enable it

until KJK and Alex have a look.

svn path=/trunk/; revision=12153
This commit is contained in:
Steven Edwards 2004-12-16 17:42:10 +00:00
parent d057566f59
commit 1aea28360c
26 changed files with 12868 additions and 0 deletions

View file

@ -0,0 +1,26 @@
*.coff
*.dll
*.d
*.a
*.o
*.sym
*.map
*.tmp
Makefile.ros
idb_hist_large.bmp
idb_hist_small.bmp
idb_std_small.bmp
idb_std_large.bmp
idb_view_large.bmp
idb_view_small.bmp
idc_copy.cur
idc_divider.cur
idc_divideropen.cur
idc_movebutton.cur
idi_dragarrow.ico
idi_tt_error_sm.ico
idi_tt_info_sm.ico
idi_tt_warn_sm.ico
idt_check.bmp
comctl32.spec.def
comctl32.stubs.c

View file

@ -0,0 +1,409 @@
TOPSRCDIR = ../..
TOPOBJDIR = ../..
SRCDIR = .
MODULE = dbghelp.dll
IMPORTS = psapi kernel32 ntdll
C_SRCS = \
coff.c \
dbghelp.c \
elf_module.c \
image.c \
memory.c \
minidump.c \
module.c \
msc.c \
path.c \
pe_module.c \
source.c \
stabs.c \
stack.c \
storage.c \
symbol.c \
type.c
# Global rules for building dlls -*-Makefile-*-
#
# Each individual makefile should define the following variables:
# MODULE : name of the main module being built
# EXTRALIBS : extra libraries to link in (optional)
# SPEC_SRCS16 : interface definition files for 16-bit dlls (optional)
# SUBSYSTEM : (optional) subsystem (for native dlls)
#
# plus all variables required by the global Make.rules.in
#
DLLDEFS =
DLLFLAGS = -D_REENTRANT -fPIC
DLLEXT = .so
DEFS = -D__WINESRC__ $(DLLDEFS) $(EXTRADEFS)
MAINSPEC = $(MODULE:%.dll=%).spec
SPEC_DEF = $(MAINSPEC).def
WIN16_FILES = $(SPEC_SRCS16:.spec=.spec.o) $(C_SRCS16:.c=.o) $(EXTRA_OBJS16)
ALL_OBJS = $(WIN16_FILES) $(OBJS) $(MODULE).dbg.o
ALL_LIBS = $(LIBWINE) $(EXTRALIBS) $(LIBPORT) $(LDFLAGS) $(LIBS)
IMPORTLIBS = $(DELAYIMPORTS:%=$(DLLDIR)/lib%.$(IMPLIBEXT)) $(IMPORTS:%=$(DLLDIR)/lib%.$(IMPLIBEXT))
all: $(MODULE)$(DLLEXT) $(SUBDIRS)
# Global rules shared by all makefiles -*-Makefile-*-
#
# Each individual makefile must define the following variables:
# TOPSRCDIR : top-level source directory
# TOPOBJDIR : top-level object directory
# SRCDIR : source directory for this module
# MODULE : name of the module being built
#
# Each individual makefile may define the following additional variables:
# C_SRCS : C sources for the module
# C_SRCS16 : 16-bit C sources for the module
# RC_SRCS : resource source files
# EXTRA_SRCS : extra source files for make depend
# EXTRA_OBJS : extra object files
# IMPORTS : dlls to import
# DELAYIMPORTS : dlls to import in delayed mode
# SUBDIRS : subdirectories that contain a Makefile
# EXTRASUBDIRS : subdirectories that do not contain a Makefile
# INSTALLSUBDIRS : subdirectories to run make install/uninstall into
# First some useful definitions
SHELL = /bin/sh
CC = gcc
CFLAGS = -g -O2
CPPFLAGS =
LIBS =
BISON = bison
YACC = $(BISON) -y
LEX = flex
LEXLIB = -lfl
EXEEXT =
OBJEXT = o
LIBEXT = so
DLLEXT = .so
IMPLIBEXT = def
LDSHARED = $(CC) -shared $(SONAME:%=-Wl,-soname,%) $(VERSCRIPT:%=-Wl,--version-script=%)
DLLTOOL = false
DLLWRAP =
AR = ar rc
RANLIB = ranlib
STRIP = strip
WINDRES = false
LN = ln
LN_S = ln -s
TOOLSDIR = $(TOPOBJDIR)
AS = as
LD = ld
LDFLAGS =
RM = rm -f
MV = mv
LINT =
LINTFLAGS =
FONTFORGE = false
INCLUDES = -I$(SRCDIR) -I. -I$(TOPSRCDIR)/include -I$(TOPOBJDIR)/include $(EXTRAINCL)
EXTRACFLAGS = -Wall -pipe -mpreferred-stack-boundary=2 -fno-strict-aliasing -gstabs+ -Wpointer-arith
ALLCFLAGS = $(INCLUDES) $(DEFS) $(DLLFLAGS) $(EXTRACFLAGS) $(CPPFLAGS) $(CFLAGS)
ALLLINTFLAGS = $(INCLUDES) $(DEFS) $(LINTFLAGS)
IDLFLAGS = $(INCLUDES) $(DEFS) $(EXTRAIDLFLAGS)
MKINSTALLDIRS= $(TOPSRCDIR)/tools/mkinstalldirs -m 755
WINAPI_CHECK = $(TOPSRCDIR)/tools/winapi_check/winapi_check
WINEWRAPPER = $(TOPSRCDIR)/tools/winewrapper
C2MAN = $(TOPSRCDIR)/tools/c2man.pl
RUNTEST = $(TOPSRCDIR)/tools/runtest
WINEBUILD = $(TOOLSDIR)/tools/winebuild/winebuild
MAKEDEP = $(TOOLSDIR)/tools/makedep
WRC = $(TOOLSDIR)/tools/wrc/wrc
BIN2RES = $(TOOLSDIR)/tools/bin2res
WMC = $(TOOLSDIR)/tools/wmc/wmc
WIDL = $(TOOLSDIR)/tools/widl/widl
WINEGCC = $(TOOLSDIR)/tools/winegcc/winegcc
SFNT2FNT = $(TOOLSDIR)/tools/sfnt2fnt
FNT2FON = $(TOOLSDIR)/tools/fnt2fon
RC = $(WRC)
RC16 = $(WRC)
RCFLAGS = --nostdinc $(INCLUDES) $(DEFS) $(EXTRARCFLAGS)
RC16FLAGS = -O res16 $(RCFLAGS)
LDPATH = LD_LIBRARY_PATH="$(TOOLSDIR)/libs/unicode:$$LD_LIBRARY_PATH"
DLLDIR = $(TOPOBJDIR)/dlls
LIBDIR = $(TOPOBJDIR)/libs
LIBPORT = -L$(TOPOBJDIR)/libs/port -lwine_port
LIBUNICODE = -L$(TOPOBJDIR)/libs/unicode -lwine_unicode
LIBWINE = -L$(TOPOBJDIR)/libs/wine -lwine
# Installation infos
INSTALL = /usr/bin/ginstall -c $(INSTALL_FLAGS)
INSTALL_PROGRAM = ${INSTALL} $(INSTALL_PROGRAM_FLAGS)
INSTALL_SCRIPT = ${INSTALL} $(INSTALL_SCRIPT_FLAGS)
INSTALL_DATA = ${INSTALL} -m 644 $(INSTALL_DATA_FLAGS)
prefix = /usr/local
exec_prefix = ${prefix}
bindir = ${exec_prefix}/bin
libdir = ${exec_prefix}/lib
datadir = ${prefix}/share
infodir = ${prefix}/info
mandir = ${prefix}/man
sysconfdir = ${prefix}/etc
includedir = ${prefix}/include/wine
dlldir = ${exec_prefix}/lib/wine
prog_manext = 1
api_manext = 3w
conf_manext = 5
CLEAN_FILES = *.o *.a *.so *.ln *.$(LIBEXT) \\\#*\\\# *~ *% .\\\#* *.bak *.orig *.rej \
*.flc *.spec.c *.spec.def *.dbg.c *.tab.c *.tab.h lex.yy.c core
OBJS = $(C_SRCS:.c=.o) $(EXTRA_OBJS)
RCOBJS = $(RC_SRCS:.rc=.res.o)
LINTS = $(C_SRCS:.c=.ln)
# Implicit rules
.SUFFIXES: .mc .rc .mc.rc .res .res.o .spec .spec.c .spec.def .idl .h .ok .sfd .ttf
.c.o:
$(CC) -c $(ALLCFLAGS) -o $@ $<
.s.o:
$(AS) -o $@ $<
.mc.mc.rc:
$(LDPATH) $(WMC) -i -U -H /dev/null -o $@ $<
.rc.res:
$(LDPATH) $(RC) $(RCFLAGS) -fo$@ $<
.res.res.o:
$(WINDRES) -i $< -o $@
.spec.spec.c:
$(WINEBUILD) $(DEFS) -o $@ --main-module $(MODULE) --dll $<
.spec.spec.def:
$(WINEBUILD) -w $(DEFS) -o $@ --def $<
.idl.h:
$(WIDL) $(IDLFLAGS) -h -H $@ $<
.c.ln:
$(LINT) -c $(ALLLINTFLAGS) $< || ( $(RM) $@ && exit 1 )
.c.ok:
$(RUNTEST) $(RUNTESTFLAGS) $< && touch $@
.sfd.ttf:
$(FONTFORGE) -script $(TOPSRCDIR)/fonts/genttf.ff $<
# 'all' target first in case the enclosing Makefile didn't define any target
all: Makefile
filter:
@$(TOPSRCDIR)/tools/winapi/make_filter --make $(MAKE) all
.PHONY: all filter
# Rules for resources
$(RC_BINARIES): $(BIN2RES) $(RC_BINSRC)
$(BIN2RES) -f -o $@ $(SRCDIR)/$(RC_BINSRC)
$(RC_SRCS:.rc=.res) $(RC_SRCS16:.rc=.res): $(WRC) $(RC_BINARIES)
# Rule for main module debug channels
$(MODULE).dbg.c: $(C_SRCS) $(C_SRCS16) $(WINEBUILD)
$(WINEBUILD) $(DEFS) -o $@ --debug -C$(SRCDIR) $(C_SRCS) $(C_SRCS16)
# Rules for makefile
Makefile: Makefile.in $(TOPSRCDIR)/configure
@echo Makefile is older than $?, please rerun $(TOPSRCDIR)/configure
@exit 1
# Rule for linting
$(MODULE).ln : $(LINTS)
if test "$(LINTS)" ; \
then \
$(LINT) $(ALLLINTFLAGS) -o$(MODULE) $(LINTS) ; \
$(MV) llib-l$(MODULE).ln $(MODULE).ln ; \
else \
$(LINT) $(ALLLINTFLAGS) -C$(MODULE) /dev/null ; \
fi
lint:: $(MODULE).ln
# Rules for Windows API checking
winapi_check:: dummy
$(WINAPI_CHECK) $(WINAPI_CHECK_FLAGS) $(WINAPI_CHECK_EXTRA_FLAGS) .
.PHONY: winapi_check
# Rules for dependencies
$(SUBDIRS:%=%/__depend__): dummy
cd `dirname $@` && $(MAKE) depend
depend: $(IDL_SRCS:.idl=.h) $(SUBDIRS:%=%/__depend__)
$(MAKEDEP) $(INCLUDES) -C$(SRCDIR) $(C_SRCS) $(C_SRCS16) $(RC_SRCS) $(RC_SRCS16) $(MC_SRCS) $(IDL_SRCS) $(EXTRA_SRCS)
.PHONY: depend $(SUBDIRS:%=%/__depend__)
# Rules for cleaning
$(SUBDIRS:%=%/__clean__): dummy
cd `dirname $@` && $(MAKE) clean
$(SUBDIRS:%=%/__testclean__): dummy
cd `dirname $@` && $(MAKE) testclean
$(EXTRASUBDIRS:%=%/__clean__): dummy
-cd `dirname $@` && $(RM) $(CLEAN_FILES)
testclean:: $(SUBDIRS:%=%/__testclean__)
clean:: $(SUBDIRS:%=%/__clean__) $(EXTRASUBDIRS:%=%/__clean__)
$(RM) $(CLEAN_FILES) $(RC_SRCS:.rc=.res) $(RC_SRCS16:.rc=.res) $(MC_SRCS:.mc=.mc.rc) $(IDL_SRCS:.idl=.h) $(PROGRAMS) $(RC_BINARIES)
.PHONY: clean testclean $(SUBDIRS:%=%/__clean__) $(SUBDIRS:%=%/__testclean__) $(EXTRASUBDIRS:%=%/__clean__)
# Rules for installing
$(SUBDIRS:%=%/__install__): dummy
cd `dirname $@` && $(MAKE) install
$(SUBDIRS:%=%/__install-lib__): dummy
cd `dirname $@` && $(MAKE) install-lib
$(SUBDIRS:%=%/__install-dev__): dummy
cd `dirname $@` && $(MAKE) install-dev
$(SUBDIRS:%=%/__uninstall__): dummy
cd `dirname $@` && $(MAKE) uninstall
install:: $(INSTALLSUBDIRS:%=%/__install__)
uninstall:: $(INSTALLSUBDIRS:%=%/__uninstall__)
.PHONY: install install-lib install-dev uninstall \
$(SUBDIRS:%=%/__install__) $(SUBDIRS:%=%/__uninstall__) \
$(SUBDIRS:%=%/__install-lib__) $(SUBDIRS:%=%/__install-dev__)
# Rules for checking that no imports are missing
$(SUBDIRS:%=%/__checklink__): dummy
@cd `dirname $@` && $(MAKE) checklink
.PHONY: checklink $(SUBDIRS:%=%/__checklink__)
# Rules for testing
$(SUBDIRS:%=%/__test__): dummy
@cd `dirname $@` && $(MAKE) test
$(SUBDIRS:%=%/__crosstest__): dummy
@cd `dirname $@` && $(MAKE) crosstest
.PHONY: check test crosstest $(SUBDIRS:%=%/__test__) $(SUBDIRS:%=%/__crosstest__)
# Misc. rules
$(MC_SRCS:.mc=.mc.rc): $(WMC)
$(IDL_SRCS:.idl=.h): $(WIDL)
$(SUBDIRS): dummy
@cd $@ && $(MAKE)
dummy:
.PHONY: dummy $(SUBDIRS)
# End of global rules
# Rules for .so files
$(MODULE).so: $(MAINSPEC) $(RC_SRCS:.rc=.res) $(ALL_OBJS) $(IMPORTLIBS) Makefile.in
$(WINEGCC) -B$(TOOLSDIR)/tools/winebuild -shared $(SRCDIR)/$(MAINSPEC) $(ALL_OBJS) $(RC_SRCS:.rc=.res) $(SUBSYSTEM:%=-Wb,--subsystem,%) -o $@ -L$(DLLDIR) $(DELAYIMPORTS:%=-Wb,-d%) $(IMPORTS:%=-l%) $(ALL_LIBS)
# Rules for .dll files
$(MODULE): $(RCOBJS) $(OBJS) $(MODULE).dbg.o $(SPEC_DEF) $(IMPORTLIBS) Makefile.in
$(DLLWRAP) -k --def $(SPEC_DEF) -o $@ $(RCOBJS) $(OBJS) $(MODULE).dbg.o -L$(DLLDIR) $(DELAYIMPORTS:%=-l%) $(IMPORTS:%=-l%) $(ALL_LIBS)
$(SPEC_DEF): $(WINEBUILD)
# Rules for checking that no imports are missing
.PHONY: checklink16 $(WIN16_FILES:%=__checklink16__%)
$(WIN16_FILES:%=__checklink16__%): checklink16
checklink16:: $(MAINSPEC).o $(OBJS) $(MODULE).dbg.o dummy
$(CC) -o checklink -Wl,-rpath,$(TOPOBJDIR)/libs $(TOPSRCDIR)/dlls/checklink.c $(MAINSPEC).o $(OBJS) $(MODULE).dbg.o -L$(DLLDIR) $(ALL_LIBS) -lm && $(RM) checklink $(MAINSPEC).c $(MAINSPEC).o
checklink:: $(WIN16_FILES:%=__checklink16__%)
# Rules for testing
check test:: $(SUBDIRS:%=%/__test__)
crosstest:: $(SUBDIRS:%=%/__crosstest__)
# Rule to explicitly generate the .spec.c for debugging
$(MAINSPEC).c: $(MAINSPEC) $(RC_SRCS:.rc=.res) $(ALL_OBJS) $(IMPORTLIBS) $(WINEBUILD)
$(WINEBUILD) $(DEFS) $(DLLFLAGS) -o $@ --dll $(SRCDIR)/$(MAINSPEC) $(SUBSYSTEM:%=--subsystem %) $(RC_SRCS:.rc=.res) $(ALL_OBJS) -L$(DLLDIR) $(DELAYIMPORTS:%=-d%) $(IMPORTS:%=-l%)
# Rules for auto documentation
man: $(C_SRCS)
$(C2MAN) -o $(TOPOBJDIR)/documentation/man$(api_manext) -R$(TOPOBJDIR) -S$(api_manext) $(INCLUDES) $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16)
doc-html: $(C_SRCS)
$(C2MAN) -o $(TOPOBJDIR)/documentation/html -R$(TOPOBJDIR) $(INCLUDES) -Th $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16)
doc-sgml: $(C_SRCS)
$(C2MAN) -o $(TOPOBJDIR)/documentation/api-guide -R$(TOPOBJDIR) $(INCLUDES) -Ts $(MAINSPEC:%=-w %) $(SPEC_SRCS16:%=-w %) $(C_SRCS) $(C_SRCS16)
.PHONY: man doc-html doc-sgml
# Rules for installation
EXE_SPECS16 = $(SPEC_SRCS16:.exe.spec=.exe)
DRV_SPECS16 = $(EXE_SPECS16:.drv.spec=.drv)
ALL_SPECS16 = $(DRV_SPECS16:.spec=.dll)
WIN16_INSTALL = $(ALL_SPECS16:%=_install_/%)
.PHONY: install_lib $(ALL_SPECS16:%=_install_/%) $(ALL_SPECS16:%=_uninstall_/%)
$(ALL_SPECS16:%=_install_/%): install_lib
cd $(dlldir) && $(RM) `basename $@`$(DLLEXT) && $(LN_S) $(MODULE)$(DLLEXT) `basename $@`$(DLLEXT)
$(ALL_SPECS16:%=_uninstall_/%): dummy
$(RM) $(dlldir)/`basename $@`$(DLLEXT)
install_lib: $(MODULE)$(DLLEXT)
$(MKINSTALLDIRS) $(dlldir)
$(INSTALL_PROGRAM) $(MODULE)$(DLLEXT) $(dlldir)/$(MODULE)$(DLLEXT)
install:: install_lib $(WIN16_INSTALL)
uninstall:: $(ALL_SPECS16:%=_uninstall_/%)
$(RM) $(dlldir)/$(MODULE)$(DLLEXT)
# Misc. rules
$(SPEC_SRCS16:.spec=.spec.c): $(WINEBUILD)
# End of global dll rules
### Dependencies:

View file

@ -0,0 +1,28 @@
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = dbghelp.dll
IMPORTS = psapi kernel32 ntdll
C_SRCS = \
coff.c \
dbghelp.c \
elf_module.c \
image.c \
memory.c \
minidump.c \
module.c \
msc.c \
path.c \
pe_module.c \
source.c \
stabs.c \
stack.c \
storage.c \
symbol.c \
type.c
@MAKE_DLL_RULES@
### Dependencies:

View file

@ -0,0 +1,21 @@
# $Id: Makefile.ros-template,v 1.1 2004/12/16 17:42:10 sedwards Exp $
TARGET_NAME = dbghelp
TARGET_OBJECTS = @C_SRCS@
TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__
TARGET_SDKLIBS = @IMPORTS@ winmm.a wine.a wine_uuid.a ntdll.a
TARGET_BASE = $(TARGET_BASE_LIB_COMCTL32)
TARGET_RC_SRCS = @RC_SRCS@
TARGET_RC_BINSRC = @RC_BINSRC@
TARGET_RC_BINARIES = @RC_BINARIES@
default: all
DEP_OBJECTS = $(TARGET_OBJECTS)
include $(TOOLS_PATH)/depend.mk

454
reactos/lib/dbghelp/coff.c Normal file
View file

@ -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;
}

View file

@ -0,0 +1,338 @@
/*
* File dbghelp.c - generic routines (process) for dbghelp DLL
*
* 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
*/
#include "config.h"
#include "dbghelp_private.h"
#include "winerror.h"
#include "psapi.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/* TODO
* - support for symbols' types is still partly missing
* + C++ support
* + funcargtype:s are (partly) wrong: they should be a specific struct (like
* typedef) pointing to the actual type (and not a direct access)
* + we should store the underlying type for an enum in the symt_enum struct
* + for enums, we store the names & values (associated to the enum type),
* but those values are not directly usable from a debugger (that's why, I
* assume, that we have also to define constants for enum values, as
* Codeview does BTW.
* - most options (dbghelp_options) are not used (loading lines...)
* - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
* we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
* we could use hash if name isn't a RE, and fall back to a full search when we
* get a full RE
* - msc:
* + we should add parameters' types to the function's signature
* while processing a function's parameters
* + get rid of MSC reading FIXME:s (lots of types are not defined)
* + C++ management
* - stabs:
* + when, in a same module, the same definition is used in several compilation
* units, we get several definitions of the same object (especially
* struct/union). we should find a way not to duplicate them
* + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
* global variable is defined several times (at different scopes). We are
* getting several of those while looking for a unique symbol. Part of the
* issue is that we don't give a scope to a static variable inside a function
* + C++ management
* - implement the callback notification mechanism
*/
unsigned dbghelp_options = SYMOPT_UNDNAME;
HANDLE hMsvcrt = NULL;
/***********************************************************************
* DllMain (DEBUGHLP.@)
*/
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH: break;
case DLL_PROCESS_DETACH:
if (hMsvcrt) FreeLibrary(hMsvcrt);
break;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break;
default: break;
}
return TRUE;
}
static struct process* process_first /* = NULL */;
/******************************************************************
* process_find_by_handle
*
*/
struct process* process_find_by_handle(HANDLE hProcess)
{
struct process* p;
for (p = process_first; p && p->handle != hProcess; p = p->next);
if (!p) SetLastError(ERROR_INVALID_HANDLE);
return p;
}
/******************************************************************
* SymSetSearchPath (DBGHELP.@)
*
*/
BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
{
struct process* pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
if (!searchPath) return FALSE;
HeapFree(GetProcessHeap(), 0, pcs->search_path);
pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
searchPath);
return TRUE;
}
/***********************************************************************
* SymGetSearchPath (DBGHELP.@)
*/
BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
DWORD SearchPathLength)
{
struct process* pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
strncpy(szSearchPath, pcs->search_path, SearchPathLength);
szSearchPath[SearchPathLength - 1] = '\0';
return TRUE;
}
/******************************************************************
* invade_process
*
* SymInitialize helper: loads in dbghelp all known (and loaded modules)
* this assumes that hProcess is a handle on a valid process
*/
static BOOL process_invade(HANDLE hProcess)
{
HMODULE hMods[256];
char img[256];
DWORD i, sz;
MODULEINFO mi;
if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &sz))
return FALSE; /* FIXME should grow hMods */
for (i = 0; i < sz / sizeof(HMODULE); i++)
{
if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
!GetModuleFileNameExA(hProcess, hMods[i], img, sizeof(img)) ||
!SymLoadModule(hProcess, 0, img, NULL, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage))
return FALSE;
}
return sz != 0;
}
/******************************************************************
* SymInitialize (DBGHELP.@)
*
* The initialisation of a dbghelp's context.
* Note that hProcess doesn't need to be a valid process handle (except
* when fInvadeProcess is TRUE).
* Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
* containing PE (and NE) module(s), here's how we handle it:
* - we load every module (ELF, NE, PE) passed in SymLoadModule
* - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
* synchronization: hProcess should be a valid process handle, and we hook
* ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
* our internal ELF modules representation (loading / unloading). This way,
* we'll pair every loaded builtin PE module with its ELF counterpart (and
* access its debug information).
* - if fInvadeProcess (in SymInitialize) is FALSE, we won't be able to
* make the peering between a builtin PE module and its ELF counterpart, hence
* we won't be able to provide the requested debug information. We'll
* however be able to load native PE modules (and their debug information)
* without any trouble.
* Note also that this scheme can be intertwined with the deferred loading
* mechanism (ie only load the debug information when we actually need it).
*/
BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess)
{
struct process* pcs;
TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
if (process_find_by_handle(hProcess))
FIXME("what to do ??\n");
pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
if (!pcs) return FALSE;
pcs->handle = hProcess;
if (UserSearchPath)
{
pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1),
UserSearchPath);
}
else
{
unsigned size;
unsigned len;
pcs->search_path = HeapAlloc(GetProcessHeap(), 0, len = MAX_PATH);
while ((size = GetCurrentDirectoryA(len, pcs->search_path)) >= len)
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, len *= 2);
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1);
len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
if (len)
{
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
pcs->search_path[size] = ';';
GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
size += 1 + len;
}
len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
if (len)
{
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
pcs->search_path[size] = ';';
GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
size += 1 + len;
}
}
pcs->lmodules = NULL;
pcs->dbg_hdr_addr = 0;
pcs->next = process_first;
process_first = pcs;
if (fInvadeProcess)
{
if (!elf_read_wine_loader_dbg_info(pcs))
{
SymCleanup(hProcess);
return FALSE;
}
process_invade(hProcess);
elf_synchronize_module_list(pcs);
}
return TRUE;
}
/******************************************************************
* SymCleanup (DBGHELP.@)
*
*/
BOOL WINAPI SymCleanup(HANDLE hProcess)
{
struct process** ppcs;
struct process* next;
for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
{
if ((*ppcs)->handle == hProcess)
{
while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
next = (*ppcs)->next;
HeapFree(GetProcessHeap(), 0, *ppcs);
*ppcs = next;
return TRUE;
}
}
return FALSE;
}
/******************************************************************
* SymSetOptions (DBGHELP.@)
*
*/
DWORD WINAPI SymSetOptions(DWORD opts)
{
return dbghelp_options = opts;
}
/******************************************************************
* SymGetOptions (DBGHELP.@)
*
*/
DWORD WINAPI SymGetOptions(void)
{
return dbghelp_options;
}
/******************************************************************
* SymSetContext (DBGHELP.@)
*
*/
BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
PIMAGEHLP_CONTEXT Context)
{
struct process* pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
pcs->ctx_frame = *StackFrame;
/* MSDN states that Context is not (no longer?) used */
return TRUE;
}
/***********************************************************************
* SymRegisterCallback (DBGHELP.@)
*/
BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
PVOID UserContext)
{
FIXME("(%p, %p, %p): stub\n", hProcess, CallbackFunction, UserContext);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/* This is imagehlp version not dbghelp !! */
static API_VERSION api_version = { 4, 0, 2, 0 };
/***********************************************************************
* ImagehlpApiVersion (DBGHELP.@)
*/
LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
{
return &api_version;
}
/***********************************************************************
* ImagehlpApiVersionEx (DBGHELP.@)
*/
LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
{
if (!AppVersion) return NULL;
AppVersion->MajorVersion = api_version.MajorVersion;
AppVersion->MinorVersion = api_version.MinorVersion;
AppVersion->Revision = api_version.Revision;
AppVersion->Reserved = api_version.Reserved;
return AppVersion;
}

View file

@ -0,0 +1 @@
#include "wine/wine_common_ver.rc"

View file

@ -0,0 +1,99 @@
@ stub DbgHelpCreateUserDump
@ stub DbgHelpCreateUserDumpW
@ stdcall EnumDirTree(long str str ptr ptr ptr)
@ stdcall EnumerateLoadedModules(long ptr ptr)
@ stub EnumerateLoadedModules64
@ stub ExtensionApiVersion
@ stdcall FindDebugInfoFile(str str ptr)
@ stdcall FindDebugInfoFileEx(str str ptr ptr ptr)
@ stdcall FindExecutableImage(str str str)
@ stub FindExecutableImageEx
@ stub FindFileInPath
@ stub FindFileInSearchPath
@ stdcall GetTimestampForLoadedLibrary(long)
@ stdcall ImageDirectoryEntryToData(ptr long long ptr) ntdll.RtlImageDirectoryEntryToData
@ stub ImageDirectoryEntryToDataEx
@ stdcall ImageNtHeader(ptr) ntdll.RtlImageNtHeader
@ stdcall ImageRvaToSection(ptr ptr long) ntdll.RtlImageRvaToSection
@ stdcall ImageRvaToVa(ptr ptr long ptr) ntdll.RtlImageRvaToVa
@ stdcall ImagehlpApiVersion()
@ stdcall ImagehlpApiVersionEx(ptr)
@ stdcall MakeSureDirectoryPathExists(str)
@ stdcall MapDebugInformation(long str str long)
@ stub MiniDumpReadDumpStream
@ stub MiniDumpWriteDump
@ stdcall SearchTreeForFile(str str str)
@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr)
@ stub StackWalk64
@ stdcall SymCleanup(long)
@ stdcall SymEnumSourceFiles(ptr long long str ptr ptr)
@ stub SymEnumSym
@ stdcall SymEnumSymbols(ptr long long str ptr ptr)
@ stdcall SymEnumTypes(ptr long long ptr ptr)
@ stdcall SymEnumerateModules(long ptr ptr)
@ stub SymEnumerateModules64
@ stdcall SymEnumerateSymbols(long long ptr ptr)
@ stub SymEnumerateSymbols64
@ stub SymEnumerateSymbolsW
@ stub SymEnumerateSymbolsW64
@ stdcall SymFindFileInPath(long str str ptr long long long ptr ptr ptr)
@ stdcall SymFromAddr(ptr long long ptr ptr)
@ stdcall SymFromName(long str ptr)
@ stdcall SymFunctionTableAccess(long long)
@ stub SymFunctionTableAccess64
@ stub SymGetFileLineOffsets64
@ stdcall SymGetLineFromAddr(long long ptr ptr)
@ stub SymGetLineFromAddr64
@ stub SymGetLineFromName
@ stub SymGetLineFromName64
@ stdcall SymGetLineNext(long ptr)
@ stub SymGetLineNext64
@ stdcall SymGetLinePrev(long ptr)
@ stub SymGetLinePrev64
@ stdcall SymGetModuleBase(long long)
@ stub SymGetModuleBase64
@ stdcall SymGetModuleInfo(long long ptr)
@ stub SymGetModuleInfo64
@ stub SymGetModuleInfoW
@ stub SymGetModuleInfoW64
@ stdcall SymGetOptions()
@ stdcall SymGetSearchPath(long str long)
@ stdcall SymGetSymFromAddr(long long ptr ptr)
@ stub SymGetSymFromAddr64
@ stdcall SymGetSymFromName(long str ptr)
@ stub SymGetSymFromName64
@ stdcall SymGetSymNext(long ptr)
@ stub SymGetSymNext64
@ stdcall SymGetSymPrev(long ptr)
@ stub SymGetSymPrev64
@ stdcall SymGetTypeFromName(ptr long long str ptr)
@ stdcall SymGetTypeInfo(ptr long long long long ptr)
@ stdcall SymInitialize(long str long)
@ stdcall SymLoadModule(long long str str long long)
@ stub SymLoadModule64
@ stub SymLoadModuleEx
@ stdcall SymMatchFileName(str str ptr ptr)
@ stub SymMatchString
@ stdcall SymRegisterCallback(long ptr ptr)
@ stub SymRegisterCallback64
@ stub SymRegisterFunctionEntryCallback
@ stub SymRegisterFunctionEntryCallback64
@ stdcall SymSetContext(long ptr ptr)
@ stdcall SymSetOptions(long)
@ stdcall SymSetSearchPath(long str)
@ stub SymSetSymWithAddr64
@ stdcall SymUnDName(ptr str long)
@ stub SymUnDName64
@ stdcall SymUnloadModule(long long)
@ stub SymUnloadModule64
@ stdcall UnDecorateSymbolName(str str long long)
@ stdcall UnmapDebugInformation(ptr)
@ stub WinDbgExtensionDllInit
#@ stub dbghelp
#@ stub dh
#@ stub lm
#@ stub lmi
#@ stub omap
#@ stub srcfiles
#@ stub sym
#@ stub vc7fpo

View file

@ -0,0 +1,96 @@
; File generated automatically from dbghelp.spec; do not edit!
LIBRARY dbghelp.dll
EXPORTS
DbgHelpCreateUserDump=__wine_stub_dbghelp_dll_1 @1
DbgHelpCreateUserDumpW=__wine_stub_dbghelp_dll_2 @2
EnumDirTree@24 @3
EnumerateLoadedModules@12 @4
EnumerateLoadedModules64=__wine_stub_dbghelp_dll_5 @5
ExtensionApiVersion=__wine_stub_dbghelp_dll_6 @6
FindDebugInfoFile@12 @7
FindDebugInfoFileEx@20 @8
FindExecutableImage@12 @9
FindExecutableImageEx=__wine_stub_dbghelp_dll_10 @10
FindFileInPath=__wine_stub_dbghelp_dll_11 @11
FindFileInSearchPath=__wine_stub_dbghelp_dll_12 @12
GetTimestampForLoadedLibrary@4 @13
ImageDirectoryEntryToData@16=ntdll.RtlImageDirectoryEntryToData @14
ImageDirectoryEntryToDataEx=__wine_stub_dbghelp_dll_15 @15
ImageNtHeader@4=ntdll.RtlImageNtHeader @16
ImageRvaToSection@12=ntdll.RtlImageRvaToSection @17
ImageRvaToVa@16=ntdll.RtlImageRvaToVa @18
ImagehlpApiVersion@0 @19
ImagehlpApiVersionEx@4 @20
MakeSureDirectoryPathExists@4 @21
MapDebugInformation@16 @22
MiniDumpReadDumpStream=__wine_stub_dbghelp_dll_23 @23
MiniDumpWriteDump=__wine_stub_dbghelp_dll_24 @24
SearchTreeForFile@12 @25
StackWalk@36 @26
StackWalk64=__wine_stub_dbghelp_dll_27 @27
SymCleanup@4 @28
SymEnumSourceFiles@24 @29
SymEnumSym=__wine_stub_dbghelp_dll_30 @30
SymEnumSymbols@24 @31
SymEnumTypes@20 @32
SymEnumerateModules@12 @33
SymEnumerateModules64=__wine_stub_dbghelp_dll_34 @34
SymEnumerateSymbols@16 @35
SymEnumerateSymbols64=__wine_stub_dbghelp_dll_36 @36
SymEnumerateSymbolsW=__wine_stub_dbghelp_dll_37 @37
SymEnumerateSymbolsW64=__wine_stub_dbghelp_dll_38 @38
SymFindFileInPath@40 @39
SymFromAddr@20 @40
SymFromName@12 @41
SymFunctionTableAccess@8 @42
SymFunctionTableAccess64=__wine_stub_dbghelp_dll_43 @43
SymGetFileLineOffsets64=__wine_stub_dbghelp_dll_44 @44
SymGetLineFromAddr@16 @45
SymGetLineFromAddr64=__wine_stub_dbghelp_dll_46 @46
SymGetLineFromName=__wine_stub_dbghelp_dll_47 @47
SymGetLineFromName64=__wine_stub_dbghelp_dll_48 @48
SymGetLineNext@8 @49
SymGetLineNext64=__wine_stub_dbghelp_dll_50 @50
SymGetLinePrev@8 @51
SymGetLinePrev64=__wine_stub_dbghelp_dll_52 @52
SymGetModuleBase@8 @53
SymGetModuleBase64=__wine_stub_dbghelp_dll_54 @54
SymGetModuleInfo@12 @55
SymGetModuleInfo64=__wine_stub_dbghelp_dll_56 @56
SymGetModuleInfoW=__wine_stub_dbghelp_dll_57 @57
SymGetModuleInfoW64=__wine_stub_dbghelp_dll_58 @58
SymGetOptions@0 @59
SymGetSearchPath@12 @60
SymGetSymFromAddr@16 @61
SymGetSymFromAddr64=__wine_stub_dbghelp_dll_62 @62
SymGetSymFromName@12 @63
SymGetSymFromName64=__wine_stub_dbghelp_dll_64 @64
SymGetSymNext@8 @65
SymGetSymNext64=__wine_stub_dbghelp_dll_66 @66
SymGetSymPrev@8 @67
SymGetSymPrev64=__wine_stub_dbghelp_dll_68 @68
SymGetTypeFromName@20 @69
SymGetTypeInfo@24 @70
SymInitialize@12 @71
SymLoadModule@24 @72
SymLoadModule64=__wine_stub_dbghelp_dll_73 @73
SymLoadModuleEx=__wine_stub_dbghelp_dll_74 @74
SymMatchFileName@16 @75
SymMatchString=__wine_stub_dbghelp_dll_76 @76
SymRegisterCallback@12 @77
SymRegisterCallback64=__wine_stub_dbghelp_dll_78 @78
SymRegisterFunctionEntryCallback=__wine_stub_dbghelp_dll_79 @79
SymRegisterFunctionEntryCallback64=__wine_stub_dbghelp_dll_80 @80
SymSetContext@12 @81
SymSetOptions@4 @82
SymSetSearchPath@8 @83
SymSetSymWithAddr64=__wine_stub_dbghelp_dll_84 @84
SymUnDName@12 @85
SymUnDName64=__wine_stub_dbghelp_dll_86 @86
SymUnloadModule@8 @87
SymUnloadModule64=__wine_stub_dbghelp_dll_88 @88
UnDecorateSymbolName@16 @89
UnmapDebugInformation@4 @90
WinDbgExtensionDllInit=__wine_stub_dbghelp_dll_91 @91

View file

@ -0,0 +1,74 @@
/* File generated automatically from dbghelp.spec; do not edit! */
/* This file can be copied, modified and distributed without restriction. */
#ifdef __GNUC__
static void __wine_unimplemented( const char *func ) __attribute__((noreturn));
#endif
struct exc_record {
unsigned int code, flags;
void *rec, *addr;
unsigned int params;
const void *info[15];
};
extern void __stdcall RtlRaiseException( struct exc_record * );
static void __wine_unimplemented( const char *func )
{
struct exc_record rec;
rec.code = 0x80000100;
rec.flags = 1;
rec.rec = 0;
rec.params = 2;
rec.info[0] = "dbghelp.dll";
rec.info[1] = func;
#ifdef __GNUC__
rec.addr = __builtin_return_address(1);
#else
rec.addr = 0;
#endif
for (;;) RtlRaiseException( &rec );
}
void __wine_stub_dbghelp_dll_1(void) { __wine_unimplemented("DbgHelpCreateUserDump"); }
void __wine_stub_dbghelp_dll_2(void) { __wine_unimplemented("DbgHelpCreateUserDumpW"); }
void __wine_stub_dbghelp_dll_5(void) { __wine_unimplemented("EnumerateLoadedModules64"); }
void __wine_stub_dbghelp_dll_6(void) { __wine_unimplemented("ExtensionApiVersion"); }
void __wine_stub_dbghelp_dll_10(void) { __wine_unimplemented("FindExecutableImageEx"); }
void __wine_stub_dbghelp_dll_11(void) { __wine_unimplemented("FindFileInPath"); }
void __wine_stub_dbghelp_dll_12(void) { __wine_unimplemented("FindFileInSearchPath"); }
void __wine_stub_dbghelp_dll_15(void) { __wine_unimplemented("ImageDirectoryEntryToDataEx"); }
void __wine_stub_dbghelp_dll_23(void) { __wine_unimplemented("MiniDumpReadDumpStream"); }
void __wine_stub_dbghelp_dll_24(void) { __wine_unimplemented("MiniDumpWriteDump"); }
void __wine_stub_dbghelp_dll_27(void) { __wine_unimplemented("StackWalk64"); }
void __wine_stub_dbghelp_dll_30(void) { __wine_unimplemented("SymEnumSym"); }
void __wine_stub_dbghelp_dll_34(void) { __wine_unimplemented("SymEnumerateModules64"); }
void __wine_stub_dbghelp_dll_36(void) { __wine_unimplemented("SymEnumerateSymbols64"); }
void __wine_stub_dbghelp_dll_37(void) { __wine_unimplemented("SymEnumerateSymbolsW"); }
void __wine_stub_dbghelp_dll_38(void) { __wine_unimplemented("SymEnumerateSymbolsW64"); }
void __wine_stub_dbghelp_dll_43(void) { __wine_unimplemented("SymFunctionTableAccess64"); }
void __wine_stub_dbghelp_dll_44(void) { __wine_unimplemented("SymGetFileLineOffsets64"); }
void __wine_stub_dbghelp_dll_46(void) { __wine_unimplemented("SymGetLineFromAddr64"); }
void __wine_stub_dbghelp_dll_47(void) { __wine_unimplemented("SymGetLineFromName"); }
void __wine_stub_dbghelp_dll_48(void) { __wine_unimplemented("SymGetLineFromName64"); }
void __wine_stub_dbghelp_dll_50(void) { __wine_unimplemented("SymGetLineNext64"); }
void __wine_stub_dbghelp_dll_52(void) { __wine_unimplemented("SymGetLinePrev64"); }
void __wine_stub_dbghelp_dll_54(void) { __wine_unimplemented("SymGetModuleBase64"); }
void __wine_stub_dbghelp_dll_56(void) { __wine_unimplemented("SymGetModuleInfo64"); }
void __wine_stub_dbghelp_dll_57(void) { __wine_unimplemented("SymGetModuleInfoW"); }
void __wine_stub_dbghelp_dll_58(void) { __wine_unimplemented("SymGetModuleInfoW64"); }
void __wine_stub_dbghelp_dll_62(void) { __wine_unimplemented("SymGetSymFromAddr64"); }
void __wine_stub_dbghelp_dll_64(void) { __wine_unimplemented("SymGetSymFromName64"); }
void __wine_stub_dbghelp_dll_66(void) { __wine_unimplemented("SymGetSymNext64"); }
void __wine_stub_dbghelp_dll_68(void) { __wine_unimplemented("SymGetSymPrev64"); }
void __wine_stub_dbghelp_dll_73(void) { __wine_unimplemented("SymLoadModule64"); }
void __wine_stub_dbghelp_dll_74(void) { __wine_unimplemented("SymLoadModuleEx"); }
void __wine_stub_dbghelp_dll_76(void) { __wine_unimplemented("SymMatchString"); }
void __wine_stub_dbghelp_dll_78(void) { __wine_unimplemented("SymRegisterCallback64"); }
void __wine_stub_dbghelp_dll_79(void) { __wine_unimplemented("SymRegisterFunctionEntryCallback"); }
void __wine_stub_dbghelp_dll_80(void) { __wine_unimplemented("SymRegisterFunctionEntryCallback64"); }
void __wine_stub_dbghelp_dll_84(void) { __wine_unimplemented("SymSetSymWithAddr64"); }
void __wine_stub_dbghelp_dll_86(void) { __wine_unimplemented("SymUnDName64"); }
void __wine_stub_dbghelp_dll_88(void) { __wine_unimplemented("SymUnloadModule64"); }
void __wine_stub_dbghelp_dll_91(void) { __wine_unimplemented("WinDbgExtensionDllInit"); }

View file

@ -0,0 +1,448 @@
/*
* File dbghelp_private.h - dbghelp internal definitions
*
* Copyright (C) 1995, Alexandre Julliard
* 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
*/
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winver.h"
#include "dbghelp.h"
#include "objbase.h"
#include "oaidl.h"
#include "cvconst.h"
/* #define USE_STATS */
struct pool /* poor's man */
{
struct pool_arena* first;
unsigned arena_size;
};
void pool_init(struct pool* a, unsigned arena_size);
void pool_destroy(struct pool* a);
void* pool_alloc(struct pool* a, unsigned len);
/* void* pool_realloc(struct pool* a, void* p,
unsigned old_size, unsigned new_size); */
char* pool_strdup(struct pool* a, const char* str);
struct vector
{
void** buckets;
unsigned elt_size;
unsigned shift;
unsigned num_elts;
unsigned num_buckets;
};
void vector_init(struct vector* v, unsigned elt_sz, unsigned bucket_sz);
unsigned vector_length(const struct vector* v);
void* vector_at(const struct vector* v, unsigned pos);
void* vector_add(struct vector* v, struct pool* pool);
/*void vector_pool_normalize(struct vector* v, struct pool* pool); */
void* vector_iter_up(const struct vector* v, void* elt);
void* vector_iter_down(const struct vector* v, void* elt);
struct hash_table_elt
{
const char* name;
struct hash_table_elt* next;
};
struct hash_table
{
unsigned num_buckets;
struct hash_table_elt** buckets;
};
void hash_table_init(struct pool* pool, struct hash_table* ht,
unsigned num_buckets);
void hash_table_destroy(struct hash_table* ht);
void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt);
void* hash_table_find(const struct hash_table* ht, const char* name);
unsigned hash_table_hash(const char* name, unsigned num_buckets);
struct hash_table_iter
{
const struct hash_table* ht;
struct hash_table_elt* element;
int index;
int last;
};
void hash_table_iter_init(const struct hash_table* ht,
struct hash_table_iter* hti, const char* name);
void* hash_table_iter_up(struct hash_table_iter* hti);
#define GET_ENTRY(__i, __t, __f) \
((__t*)((char*)(__i) - (unsigned int)(&((__t*)0)->__f)))
extern unsigned dbghelp_options;
/* some more Wine extensions */
#define SYMOPT_WINE_WITH_ELF_MODULES 0x40000000
struct symt
{
enum SymTagEnum tag;
};
struct symt_ht
{
struct symt symt;
struct hash_table_elt hash_elt; /* if global symbol or type */
};
/* lexical tree */
struct symt_block
{
struct symt symt;
unsigned long address;
unsigned long size;
struct symt* container; /* block, or func */
struct vector vchildren; /* sub-blocks & local variables */
};
struct symt_compiland
{
struct symt symt;
unsigned source;
struct vector vchildren; /* global variables & functions */
};
struct symt_data
{
struct symt symt;
struct hash_table_elt hash_elt; /* if global symbol */
enum DataKind kind;
struct symt* container;
struct symt* type;
union /* depends on kind */
{
unsigned long address; /* DataIs{Global, FileStatic} */
struct
{
long offset; /* DataIs{Member,Local,Param} in bits*/
unsigned long length; /* DataIs{Member} in bits */
unsigned long reg_id; /* DataIs{Local} (0 if frame relative) */
} s;
VARIANT value; /* DataIsConstant */
} u;
};
struct symt_function
{
struct symt symt;
struct hash_table_elt hash_elt; /* if global symbol */
unsigned long address;
struct symt* container; /* compiland */
struct symt* type; /* points to function_signature */
unsigned long size;
struct vector vlines;
struct vector vchildren; /* locals, params, blocks, start/end, labels */
};
struct symt_function_point
{
struct symt symt; /* either SymTagFunctionDebugStart, SymTagFunctionDebugEnd, SymTagLabel */
struct symt_function* parent;
unsigned long offset;
const char* name; /* for labels */
};
struct symt_public
{
struct symt symt;
struct hash_table_elt hash_elt;
struct symt* container; /* compiland */
unsigned long address;
unsigned long size;
unsigned in_code : 1,
is_function : 1;
};
struct symt_thunk
{
struct symt symt;
struct hash_table_elt hash_elt;
struct symt* container; /* compiland */
unsigned long address;
unsigned long size;
THUNK_ORDINAL ordinal; /* FIXME: doesn't seem to be accessible */
};
/* class tree */
struct symt_array
{
struct symt symt;
int start;
int end;
struct symt* basetype;
};
struct symt_basic
{
struct symt symt;
struct hash_table_elt hash_elt;
enum BasicType bt;
unsigned long size;
};
struct symt_enum
{
struct symt symt;
const char* name;
struct vector vchildren;
};
struct symt_function_signature
{
struct symt symt;
struct symt* rettype;
struct vector vchildren;
};
struct symt_pointer
{
struct symt symt;
struct symt* pointsto;
};
struct symt_typedef
{
struct symt symt;
struct hash_table_elt hash_elt;
struct symt* type;
};
struct symt_udt
{
struct symt symt;
struct hash_table_elt hash_elt;
enum UdtKind kind;
int size;
struct vector vchildren;
};
enum module_type
{
DMT_UNKNOWN, /* for lookup, not actually used for a module */
DMT_ELF, /* a real ELF shared module */
DMT_PE, /* a native or builtin PE module */
};
struct module
{
IMAGEHLP_MODULE module;
struct module* next;
enum module_type type;
struct elf_module_info* elf_info;
/* memory allocation pool */
struct pool pool;
/* symbol tables */
int sortlist_valid;
struct symt_ht** addr_sorttab;
struct hash_table ht_symbols;
/* types */
struct hash_table ht_types;
struct vector vtypes;
/* source files */
unsigned sources_used;
unsigned sources_alloc;
char* sources;
};
struct process
{
struct process* next;
HANDLE handle;
char* search_path;
struct module* lmodules;
unsigned long dbg_hdr_addr;
IMAGEHLP_STACK_FRAME ctx_frame;
};
/* dbghelp.c */
extern struct process* process_find_by_handle(HANDLE hProcess);
extern HANDLE hMsvcrt;
/* elf_module.c */
extern BOOL elf_load_debug_info(struct module* module);
extern struct module*
elf_load_module(struct process* pcs, const char* name);
extern BOOL elf_read_wine_loader_dbg_info(struct process* pcs);
extern BOOL elf_synchronize_module_list(struct process* pcs);
extern DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr);
/* module.c */
extern struct module*
module_find_by_addr(const struct process* pcs, unsigned long addr,
enum module_type type);
extern struct module*
module_find_by_name(const struct process* pcs,
const char* name, enum module_type type);
extern struct module*
module_get_debug(const struct process* pcs, struct module*);
extern struct module*
module_new(struct process* pcs, const char* name,
enum module_type type, unsigned long addr,
unsigned long size, unsigned long stamp,
unsigned long checksum);
extern struct module*
module_get_container(const struct process* pcs,
const struct module* inner);
extern struct module*
module_get_containee(const struct process* pcs,
const struct module* inner);
extern void module_reset_debug_info(struct module* module);
extern BOOL module_remove(struct process* pcs,
struct module* module);
/* msc.c */
extern BOOL pe_load_debug_directory(const struct process* pcs,
struct module* module,
const BYTE* mapping,
const IMAGE_SECTION_HEADER* sectp, DWORD nsect,
const IMAGE_DEBUG_DIRECTORY* dbg, int nDbg);
/* pe_module.c */
extern struct module*
pe_load_module(struct process* pcs, char* name,
HANDLE hFile, DWORD base, DWORD size);
extern struct module*
pe_load_module_from_pcs(struct process* pcs, const char* name,
const char* mod_name, DWORD base, DWORD size);
extern BOOL pe_load_debug_info(const struct process* pcs,
struct module* module);
/* source.c */
extern unsigned source_new(struct module* module, const char* source);
extern const char* source_get(const struct module* module, unsigned idx);
/* stabs.c */
extern BOOL stabs_parse(struct module* module, unsigned long load_offset,
const void* stabs, int stablen,
const char* strs, int strtablen);
/* symbol.c */
extern const char* symt_get_name(const struct symt* sym);
extern int symt_cmp_addr(const void* p1, const void* p2);
extern int symt_find_nearest(struct module* module, DWORD addr);
extern struct symt_compiland*
symt_new_compiland(struct module* module,
const char* filename);
extern struct symt_public*
symt_new_public(struct module* module,
struct symt_compiland* parent,
const char* typename,
unsigned long address, unsigned size,
BOOL in_code, BOOL is_func);
extern struct symt_data*
symt_new_global_variable(struct module* module,
struct symt_compiland* parent,
const char* name, unsigned is_static,
unsigned long addr, unsigned long size,
struct symt* type);
extern struct symt_function*
symt_new_function(struct module* module,
struct symt_compiland* parent,
const char* name,
unsigned long addr, unsigned long size,
struct symt* type);
extern BOOL symt_normalize_function(struct module* module,
struct symt_function* func);
extern void symt_add_func_line(struct module* module,
struct symt_function* func,
unsigned source_idx, int line_num,
unsigned long offset);
extern struct symt_data*
symt_add_func_local(struct module* module,
struct symt_function* func,
int regno, int offset,
struct symt_block* block,
struct symt* type, const char* name);
extern struct symt_block*
symt_open_func_block(struct module* module,
struct symt_function* func,
struct symt_block* block,
unsigned pc, unsigned len);
extern struct symt_block*
symt_close_func_block(struct module* module,
struct symt_function* func,
struct symt_block* block, unsigned pc);
extern struct symt_function_point*
symt_add_function_point(struct module* module,
struct symt_function* func,
enum SymTagEnum point,
unsigned offset, const char* name);
extern BOOL symt_fill_func_line_info(struct module* module,
struct symt_function* func,
DWORD addr, IMAGEHLP_LINE* line);
extern BOOL symt_get_func_line_next(struct module* module, PIMAGEHLP_LINE line);
extern struct symt_thunk*
symt_new_thunk(struct module* module,
struct symt_compiland* parent,
const char* name, THUNK_ORDINAL ord,
unsigned long addr, unsigned long size);
/* type.c */
extern void symt_init_basic(struct module* module);
extern BOOL symt_get_info(const struct symt* type,
IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo);
extern struct symt_basic*
symt_new_basic(struct module* module, enum BasicType,
const char* typename, unsigned size);
extern struct symt_udt*
symt_new_udt(struct module* module, const char* typename,
unsigned size, enum UdtKind kind);
extern BOOL symt_set_udt_size(struct module* module,
struct symt_udt* type, unsigned size);
extern BOOL symt_add_udt_element(struct module* module,
struct symt_udt* udt_type,
const char* name,
struct symt* elt_type, unsigned offset,
unsigned size);
extern struct symt_enum*
symt_new_enum(struct module* module, const char* typename);
extern BOOL symt_add_enum_element(struct module* module,
struct symt_enum* enum_type,
const char* name, int value);
extern struct symt_array*
symt_new_array(struct module* module, int min, int max,
struct symt* base);
extern struct symt_function_signature*
symt_new_function_signature(struct module* module,
struct symt* ret_type);
extern BOOL symt_add_function_signature_parameter(struct module* module,
struct symt_function_signature* sig,
struct symt* param);
extern struct symt_pointer*
symt_new_pointer(struct module* module,
struct symt* ref_type);
extern struct symt_typedef*
symt_new_typedef(struct module* module, struct symt* ref,
const char* name);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,61 @@
/*
* File image.c - managing images
*
* 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
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dbghelp_private.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/***********************************************************************
* GetTimestampForLoadedLibrary (DBGHELP.@)
*/
DWORD WINAPI GetTimestampForLoadedLibrary(HMODULE Module)
{
IMAGE_NT_HEADERS* nth = RtlImageNtHeader(Module);
return (nth) ? nth->FileHeader.TimeDateStamp : 0;
}
/***********************************************************************
* MapDebugInformation (DBGHELP.@)
*/
PIMAGE_DEBUG_INFORMATION WINAPI MapDebugInformation(HANDLE FileHandle, LPSTR FileName,
LPSTR SymbolPath, DWORD ImageBase)
{
FIXME("(%p, %s, %s, 0x%08lx): stub\n", FileHandle, FileName, SymbolPath, ImageBase);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return NULL;
}
/***********************************************************************
* UnmapDebugInformation (DBGHELP.@)
*/
BOOL WINAPI UnmapDebugInformation(PIMAGE_DEBUG_INFORMATION DebugInfo)
{
FIXME("(%p): stub\n", DebugInfo);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}

View file

@ -0,0 +1,61 @@
/*
* File memory.c - managing memory
*
* 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
*/
#include "config.h"
#include <assert.h>
#include "dbghelp_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/******************************************************************
* addr_to_linear
*
* converts an address into its linear value
*/
DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr)
{
LDT_ENTRY le;
switch (addr->Mode)
{
case AddrMode1616:
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
return (le.HighWord.Bits.BaseHi << 24) +
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + LOWORD(addr->Offset);
break;
case AddrMode1632:
if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
return (le.HighWord.Bits.BaseHi << 24) +
(le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset;
break;
case AddrModeReal:
return (DWORD)(LOWORD(addr->Segment) << 4) + addr->Offset;
case AddrModeFlat:
return addr->Offset;
default:
FIXME("Unsupported (yet) mode (%x)\n", addr->Mode);
return 0;
}
FIXME("Failed to linearize address %04x:%08lx (mode %x)\n",
addr->Segment, addr->Offset, addr->Mode);
return 0;
}

View file

@ -0,0 +1,266 @@
/*
* File minidump.c - management of dumps (read & write)
*
* 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
*/
#include <time.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "dbghelp_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
#if 0
/* hard to see how we can generate this very easily (how to grab latest exception
* in a process ?)
*/
static void DumpException(struct process* pcs, HANDLE hFile, RVA* rva)
{
MINIDUMP_EXCEPTION_STREAM mdExcpt;
mdExcpt.ThreadId = DEBUG_CurrThread->tid;
mdExcpt.__alignment = 0;
mdExcpt.ExceptionRecord.
ULONG ExceptionCode;
ULONG ExceptionFlags;
ULONGLONG ExceptionRecord;
ULONGLONG ExceptionAddress;
ULONG NumberParameters;
ULONG __unusedAlignment;
ULONGLONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
}
#endif
/******************************************************************
* dump_modules
*
* Write in File the modules from pcs
*/
static void dump_modules(struct process* pcs, HANDLE hFile, RVA* rva)
{
MINIDUMP_MODULE mdModule;
MINIDUMP_MODULE_LIST mdModuleList;
DWORD written;
struct module* module = NULL;
mdModuleList.NumberOfModules = 0;
for (module = pcs->lmodules; module; module = module->next)
mdModuleList.NumberOfModules++;
WriteFile(hFile, &mdModuleList.NumberOfModules,
sizeof(mdModuleList.NumberOfModules), &written, NULL);
*rva += sizeof(mdModuleList.NumberOfModules) +
sizeof(mdModule) * mdModuleList.NumberOfModules;
for (module = pcs->lmodules; module; module = module->next)
{
mdModule.BaseOfImage = (DWORD)module->module.BaseOfImage;
mdModule.SizeOfImage = module->module.ImageSize;
mdModule.CheckSum = module->module.CheckSum;
mdModule.TimeDateStamp = module->module.TimeDateStamp;
mdModule.ModuleNameRva = *rva;
*rva += strlen(module->module.ModuleName) + 1;
memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */
mdModule.CvRecord.DataSize = 0; /* FIXME */
mdModule.CvRecord.Rva = 0; /* FIXME */
mdModule.MiscRecord.DataSize = 0; /* FIXME */
mdModule.MiscRecord.Rva = 0; /* FIXME */
mdModule.Reserved0 = 0;
mdModule.Reserved1 = 0;
WriteFile(hFile, &mdModule, sizeof(mdModule), &written, NULL);
}
for (module = pcs->lmodules; module; module = module->next)
{
WriteFile(hFile, module->module.ModuleName,
strlen(module->module.ModuleName) + 1, &written, NULL);
FIXME("CV and misc records not written\n");
}
}
/******************************************************************
* dump_system_info
*
* Dumps into File the information about the system
*/
static void dump_system_info(struct process* pcs, HANDLE hFile, RVA* rva)
{
MINIDUMP_SYSTEM_INFO mdSysInfo;
SYSTEM_INFO sysInfo;
OSVERSIONINFOA osInfo;
DWORD written;
GetSystemInfo(&sysInfo);
GetVersionExA(&osInfo);
mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
mdSysInfo.Reserved0 = 0;
mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
mdSysInfo.PlatformId = osInfo.dwPlatformId;
mdSysInfo.CSDVersionRva = *rva + sizeof(mdSysInfo);
mdSysInfo.Reserved1 = 0;
WriteFile(hFile, &mdSysInfo, sizeof(mdSysInfo), &written, NULL);
*rva += sizeof(mdSysInfo);
WriteFile(hFile, osInfo.szCSDVersion, strlen(osInfo.szCSDVersion) + 1,
&written, NULL);
*rva += strlen(osInfo.szCSDVersion) + 1;
}
/******************************************************************
* dump_threads
*
* Dumps into File the information about running threads
*/
static void dump_threads(struct process* pcs, HANDLE hFile, RVA* rva)
{
#if 0
MINIDUMP_THREAD mdThd;
MINIDUMP_THREAD_LIST mdThdList;
DWORD written;
DBG_THREAD* thd;
mdThdList.NumberOfThreads = pcs->num_threads;
WriteFile(hFile, &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads),
&written, NULL);
*rva += sizeof(mdThdList.NumberOfThreads) +
mdThdList.NumberOfThreads * sizeof(mdThd);
for (thd = pcs->threads; thd; thd = thd->next)
{
mdThd.ThreadId = thd->tid;
mdThd.SuspendCount = 0; /* FIXME */
mdThd.PriorityClass = 0; /* FIXME */
mdThd.Priority = 0; /* FIXME */
mdThd.Teb = 0; /* FIXME */
mdThd.Stack.StartOfMemoryRange = 0; /* FIXME */
mdThd.Stack.Memory.DataSize = 0; /* FIXME */
mdThd.Stack.Memory.Rva = 0; /* FIXME */
mdThd.ThreadContext.DataSize = 0;/* FIXME */
mdThd.ThreadContext.Rva = 0; /* FIXME */
WriteFile(hFile, &mdThd, sizeof(mdThd), &written, NULL);
FIXME("Stack & thread context not written\n");
}
#endif
}
/******************************************************************
* MiniDumpWriteDump (DEBUGHLP.@)
*
*
*/
BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
MINIDUMP_TYPE DumpType,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
{
struct process* pcs;
MINIDUMP_HEADER mdHead;
MINIDUMP_DIRECTORY mdDir;
DWORD currRva, written;
DWORD i, nStream, addStream;
RVA rva;
pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE; /* FIXME: should try to load it ??? */
/* 1) init */
nStream = UserStreamParam ? UserStreamParam->UserStreamCount : 0;
addStream = 0;
if (DumpType & MiniDumpNormal)
addStream += 3; /* sure ? thread stack back trace */
if (DumpType & MiniDumpWithDataSegs)
FIXME("NIY MiniDumpWithDataSegs\n");
if (DumpType & MiniDumpWithFullMemory)
FIXME("NIY MiniDumpWithFullMemory\n");
if (DumpType & MiniDumpWithHandleData)
FIXME("NIY MiniDumpWithHandleData\n");
if (DumpType & MiniDumpFilterMemory)
FIXME("NIY MiniDumpFilterMemory\n");
if (DumpType & MiniDumpScanMemory)
FIXME("NIY MiniDumpScanMemory\n");
/* 2) write header */
rva = sizeof(mdHead);
mdHead.Signature = MINIDUMP_SIGNATURE;
mdHead.Version = MINIDUMP_VERSION;
mdHead.NumberOfStreams = nStream + addStream;
mdHead.StreamDirectoryRva = rva;
mdHead.u.TimeDateStamp = time(NULL);
mdHead.Flags = DumpType;
WriteFile(hFile, &mdHead, sizeof(mdHead), &written, NULL);
/* 3) write stream directories */
rva += (nStream + addStream) * sizeof(mdDir);
/* 3.1) write data stream directories */
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
mdDir.StreamType = ModuleListStream;
mdDir.Location.Rva = rva;
dump_modules(pcs, hFile, &rva);
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
mdDir.StreamType = ThreadListStream;
mdDir.Location.Rva = rva;
dump_threads(pcs, hFile, &rva);
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
mdDir.StreamType = SystemInfoStream;
mdDir.Location.Rva = rva;
dump_system_info(pcs, hFile, &rva);
mdDir.Location.DataSize = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - mdDir.Location.Rva;
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
/* 3.2) write user define stream */
for (i = 0; i < nStream; i++)
{
mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
mdDir.Location.Rva = rva;
WriteFile(hFile, &mdDir, sizeof(mdDir), &written, NULL);
currRva = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
SetFilePointer(hFile, rva, NULL, FILE_BEGIN);
WriteFile(hFile,
UserStreamParam->UserStreamArray[i].Buffer,
UserStreamParam->UserStreamArray[i].BufferSize,
&written, NULL);
rva += UserStreamParam->UserStreamArray[i].BufferSize;
SetFilePointer(hFile, currRva, NULL, FILE_BEGIN);
}
return TRUE;
}

View file

@ -0,0 +1,505 @@
/*
* File module.c - module handling for the wine debugger
*
* Copyright (C) 1993, Eric Youngdale.
* 2000-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
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "dbghelp_private.h"
#include "psapi.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
static void module_fill_module(const char* in, char* out, unsigned size)
{
const char* ptr;
unsigned len;
for (ptr = in + strlen(in) - 1;
*ptr != '/' && *ptr != '\\' && ptr >= in;
ptr--);
if (ptr < in || *ptr == '/' || *ptr == '\\') ptr++;
strncpy(out, ptr, size);
out[size - 1] = '\0';
len = strlen(out);
if (len > 4 &&
(!strcasecmp(&out[len - 4], ".dll") || !strcasecmp(&out[len - 4], ".exe")))
out[len - 4] = '\0';
else
{
if (len > 7 &&
(!strcasecmp(&out[len - 7], ".dll.so") || !strcasecmp(&out[len - 7], ".exe.so")))
strcpy(&out[len - 7], "<elf>");
else if (len > 7 &&
out[len - 7] == '.' && !strcasecmp(&out[len - 3], ".so"))
{
if (len + 3 < size) strcpy(&out[len - 3], "<elf>");
else WARN("Buffer too short: %s\n", out);
}
}
while ((*out = tolower(*out))) out++;
}
/***********************************************************************
* Creates and links a new module to a process
*/
struct module* module_new(struct process* pcs, const char* name,
enum module_type type,
unsigned long mod_addr, unsigned long size,
unsigned long stamp, unsigned long checksum)
{
struct module* module;
if (!(module = HeapAlloc(GetProcessHeap(), 0, sizeof(*module))))
return NULL;
memset(module, 0, sizeof(*module));
module->next = pcs->lmodules;
pcs->lmodules = module;
TRACE("=> %s %08lx-%08lx %s\n",
type == DMT_ELF ? "ELF" : (type == DMT_PE ? "PE" : "---"),
mod_addr, mod_addr + size, name);
pool_init(&module->pool, 65536);
module->module.SizeOfStruct = sizeof(module->module);
module->module.BaseOfImage = mod_addr;
module->module.ImageSize = size;
module_fill_module(name, module->module.ModuleName, sizeof(module->module.ModuleName));
module->module.ImageName[0] = '\0';
strncpy(module->module.LoadedImageName, name,
sizeof(module->module.LoadedImageName));
module->module.LoadedImageName[sizeof(module->module.LoadedImageName) - 1] = '\0';
module->module.SymType = SymNone;
module->module.NumSyms = 0;
module->module.TimeDateStamp = stamp;
module->module.CheckSum = checksum;
module->type = type;
module->sortlist_valid = FALSE;
module->addr_sorttab = NULL;
/* FIXME: this seems a bit too high (on a per module basis)
* need some statistics about this
*/
hash_table_init(&module->pool, &module->ht_symbols, 4096);
hash_table_init(&module->pool, &module->ht_types, 4096);
vector_init(&module->vtypes, sizeof(struct symt*), 32);
module->sources_used = 0;
module->sources_alloc = 0;
module->sources = 0;
return module;
}
/***********************************************************************
* module_find_by_name
*
*/
struct module* module_find_by_name(const struct process* pcs,
const char* name, enum module_type type)
{
struct module* module;
if (type == DMT_UNKNOWN)
{
if ((module = module_find_by_name(pcs, name, DMT_PE)) ||
(module = module_find_by_name(pcs, name, DMT_ELF)))
return module;
}
else
{
for (module = pcs->lmodules; module; module = module->next)
{
if (type == module->type && !strcasecmp(name, module->module.LoadedImageName))
return module;
}
for (module = pcs->lmodules; module; module = module->next)
{
if (type == module->type && !strcasecmp(name, module->module.ModuleName))
return module;
}
}
SetLastError(ERROR_INVALID_NAME);
return NULL;
}
/***********************************************************************
* module_get_container
*
*/
struct module* module_get_container(const struct process* pcs,
const struct module* inner)
{
struct module* module;
for (module = pcs->lmodules; module; module = module->next)
{
if (module != inner &&
module->module.BaseOfImage <= inner->module.BaseOfImage &&
module->module.BaseOfImage + module->module.ImageSize >=
inner->module.BaseOfImage + inner->module.ImageSize)
return module;
}
return NULL;
}
/***********************************************************************
* module_get_containee
*
*/
struct module* module_get_containee(const struct process* pcs,
const struct module* outter)
{
struct module* module;
for (module = pcs->lmodules; module; module = module->next)
{
if (module != outter &&
outter->module.BaseOfImage <= module->module.BaseOfImage &&
outter->module.BaseOfImage + outter->module.ImageSize >=
module->module.BaseOfImage + module->module.ImageSize)
return module;
}
return NULL;
}
/******************************************************************
* module_get_debug
*
* get the debug information from a module:
* - if the module's type is deferred, then force loading of debug info (and return
* the module itself)
* - if the module has no debug info and has an ELF container, then return the ELF
* container (and also force the ELF container's debug info loading if deferred)
* - otherwise return the module itself if it has some debug info
*/
struct module* module_get_debug(const struct process* pcs, struct module* module)
{
struct module* parent;
if (!module) return NULL;
/* for a PE builtin, always get info from parent */
if ((parent = module_get_container(pcs, module)))
module = parent;
/* if deferred, force loading */
if (module->module.SymType == SymDeferred)
{
BOOL ret;
switch (module->type)
{
case DMT_ELF: ret = elf_load_debug_info(module); break;
case DMT_PE: ret = pe_load_debug_info(pcs, module); break;
default: ret = FALSE; break;
}
if (!ret) module->module.SymType = SymNone;
assert(module->module.SymType != SymDeferred);
}
return (module && module->module.SymType != SymNone) ? module : NULL;
}
/***********************************************************************
* module_find_by_addr
*
* either the addr where module is loaded, or any address inside the
* module
*/
struct module* module_find_by_addr(const struct process* pcs, unsigned long addr,
enum module_type type)
{
struct module* module;
if (type == DMT_UNKNOWN)
{
if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
(module = module_find_by_addr(pcs, addr, DMT_ELF)))
return module;
}
else
{
for (module = pcs->lmodules; module; module = module->next)
{
if (type == module->type && addr >= module->module.BaseOfImage &&
addr < module->module.BaseOfImage + module->module.ImageSize)
return module;
}
}
SetLastError(ERROR_INVALID_ADDRESS);
return module;
}
static BOOL module_is_elf_container_loaded(struct process* pcs, const char* ImageName,
const char* ModuleName)
{
char buffer[MAX_PATH];
size_t len;
struct module* module;
if (!ModuleName)
{
module_fill_module(ImageName, buffer, sizeof(buffer));
ModuleName = buffer;
}
len = strlen(ModuleName);
for (module = pcs->lmodules; module; module = module->next)
{
if (!strncasecmp(module->module.ModuleName, ModuleName, len) &&
module->type == DMT_ELF &&
!strcmp(module->module.ModuleName + len, "<elf>"))
return TRUE;
}
return FALSE;
}
/***********************************************************************
* SymLoadModule (DBGHELP.@)
*/
DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, char* ImageName,
char* ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
{
struct process* pcs;
struct module* module = NULL;
TRACE("(%p %p %s %s %08lx %08lx)\n",
hProcess, hFile, debugstr_a(ImageName), debugstr_a(ModuleName),
BaseOfDll, SizeOfDll);
pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
/* force transparent ELF loading / unloading */
elf_synchronize_module_list(pcs);
/* this is a Wine extension to the API just to redo the synchronisation */
if (!ImageName && !hFile) return 0;
if (module_is_elf_container_loaded(pcs, ImageName, ModuleName))
{
/* force the loading of DLL as builtin */
if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
goto done;
WARN("Couldn't locate %s\n", ImageName);
return 0;
}
TRACE("Assuming %s as native DLL\n", ImageName);
if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll)))
{
unsigned len = strlen(ImageName);
if (!strcmp(ImageName + len - 3, ".so") &&
(module = elf_load_module(pcs, ImageName))) goto done;
FIXME("should have successfully loaded some debug information for image %s\n", ImageName);
if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
goto done;
WARN("Couldn't locate %s\n", ImageName);
return 0;
}
done:
/* by default pe_load_module fills module.ModuleName from a derivation
* of ImageName. Overwrite it, if we have better information
*/
if (ModuleName)
{
strncpy(module->module.ModuleName, ModuleName,
sizeof(module->module.ModuleName));
module->module.ModuleName[sizeof(module->module.ModuleName) - 1] = '\0';
}
strncpy(module->module.ImageName, ImageName, sizeof(module->module.ImageName));
module->module.ImageName[sizeof(module->module.ImageName) - 1] = '\0';
return module->module.BaseOfImage;
}
/******************************************************************
* module_remove
*
*/
BOOL module_remove(struct process* pcs, struct module* module)
{
struct module** p;
TRACE("%s (%p)\n", module->module.ModuleName, module);
hash_table_destroy(&module->ht_symbols);
hash_table_destroy(&module->ht_types);
HeapFree(GetProcessHeap(), 0, (char*)module->sources);
HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
pool_destroy(&module->pool);
for (p = &pcs->lmodules; *p; p = &(*p)->next)
{
if (*p == module)
{
*p = module->next;
HeapFree(GetProcessHeap(), 0, module);
return TRUE;
}
}
FIXME("This shouldn't happen\n");
return FALSE;
}
/******************************************************************
* SymUnloadModule (DBGHELP.@)
*
*/
BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
{
struct process* pcs;
struct module* module;
pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
if (!module) return FALSE;
return module_remove(pcs, module);
}
/******************************************************************
* SymEnumerateModules (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumerateModules(HANDLE hProcess,
PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
PVOID UserContext)
{
struct process* pcs = process_find_by_handle(hProcess);
struct module* module;
if (!pcs) return FALSE;
for (module = pcs->lmodules; module; module = module->next)
{
if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type != DMT_PE)
continue;
if (!EnumModulesCallback(module->module.ModuleName,
module->module.BaseOfImage, UserContext))
break;
}
return TRUE;
}
/******************************************************************
* EnumerateLoadedModules (DBGHELP.@)
*
*/
BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess,
PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
PVOID UserContext)
{
HMODULE* hMods;
char base[256], mod[256];
DWORD i, sz;
MODULEINFO mi;
hMods = HeapAlloc(GetProcessHeap(), 0, sz);
if (!hMods) return FALSE;
if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
{
/* hProcess should also be a valid process handle !! */
FIXME("If this happens, bump the number in mod\n");
HeapFree(GetProcessHeap(), 0, hMods);
return FALSE;
}
sz /= sizeof(HMODULE);
for (i = 0; i < sz; i++)
{
if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
!GetModuleBaseNameA(hProcess, hMods[i], base, sizeof(base)))
continue;
module_fill_module(base, mod, sizeof(mod));
EnumLoadedModulesCallback(mod, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage,
UserContext);
}
HeapFree(GetProcessHeap(), 0, hMods);
return sz != 0 && i == sz;
}
/******************************************************************
* SymGetModuleInfo (DBGHELP.@)
*
*/
BOOL WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr,
PIMAGEHLP_MODULE ModuleInfo)
{
struct process* pcs = process_find_by_handle(hProcess);
struct module* module;
if (!pcs) return FALSE;
if (ModuleInfo->SizeOfStruct < sizeof(*ModuleInfo)) return FALSE;
module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
if (!module) return FALSE;
*ModuleInfo = module->module;
if (module->module.SymType == SymNone)
{
module = module_get_container(pcs, module);
if (module && module->module.SymType != SymNone)
ModuleInfo->SymType = module->module.SymType;
}
return TRUE;
}
/***********************************************************************
* SymGetModuleBase (IMAGEHLP.@)
*/
DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
{
struct process* pcs = process_find_by_handle(hProcess);
struct module* module;
if (!pcs) return 0;
module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
if (!module) return 0;
return module->module.BaseOfImage;
}
/******************************************************************
* module_reset_debug_info
* Removes any debug information linked to a given module.
*/
void module_reset_debug_info(struct module* module)
{
module->sortlist_valid = TRUE;
module->addr_sorttab = NULL;
hash_table_destroy(&module->ht_symbols);
module->ht_symbols.num_buckets = 0;
module->ht_symbols.buckets = NULL;
hash_table_destroy(&module->ht_types);
module->ht_types.num_buckets = 0;
module->ht_types.buckets = NULL;
module->vtypes.num_elts = 0;
hash_table_destroy(&module->ht_symbols);
module->sources_used = module->sources_alloc = 0;
module->sources = NULL;
}

2332
reactos/lib/dbghelp/msc.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

272
reactos/lib/dbghelp/path.c Normal file
View file

@ -0,0 +1,272 @@
/*
* File path.c - managing path in debugging environments
*
* 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
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dbghelp_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
static inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';}
static inline char* file_name(char* str)
{
char* p;
for (p = str + strlen(str) - 1; p >= str && !is_sep(*p); p--);
return p + 1;
}
/******************************************************************
* FindDebugInfoFile (DBGHELP.@)
*
*/
HANDLE WINAPI FindDebugInfoFile(PSTR FileName, PSTR SymbolPath, PSTR DebugFilePath)
{
HANDLE h;
h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
{
if (!SearchPathA(SymbolPath, file_name(FileName), NULL, MAX_PATH, DebugFilePath, NULL))
return NULL;
h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/******************************************************************
* FindDebugInfoFileEx (DBGHELP.@)
*
*/
HANDLE WINAPI FindDebugInfoFileEx(PSTR FileName, PSTR SymbolPath,
PSTR DebugFilePath,
PFIND_DEBUG_FILE_CALLBACK Callback,
PVOID CallerData)
{
FIXME("(%s %s %p %p %p): stub\n",
FileName, SymbolPath, DebugFilePath, Callback, CallerData);
return NULL;
}
/******************************************************************
* FindExecutableImage (DBGHELP.@)
*
*/
HANDLE WINAPI FindExecutableImage(PSTR FileName, PSTR SymbolPath, PSTR ImageFilePath)
{
HANDLE h;
if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
return NULL;
h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
/***********************************************************************
* MakeSureDirectoryPathExists (DBGHELP.@)
*/
BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
{
char path[MAX_PATH];
const char *p = DirPath;
int n;
if (p[0] && p[1] == ':') p += 2;
while (*p == '\\') p++; /* skip drive root */
while ((p = strchr(p, '\\')) != NULL)
{
n = p - DirPath + 1;
memcpy(path, DirPath, n);
path[n] = '\0';
if( !CreateDirectoryA(path, NULL) &&
(GetLastError() != ERROR_ALREADY_EXISTS))
return FALSE;
p++;
}
if (GetLastError() == ERROR_ALREADY_EXISTS)
SetLastError(ERROR_SUCCESS);
return TRUE;
}
/******************************************************************
* SymMatchFileName (DBGHELP.@)
*
*/
BOOL WINAPI SymMatchFileName(char* file, char* match,
char** filestop, char** matchstop)
{
char* fptr;
char* mptr;
TRACE("(%s %s %p %p)\n", file, match, filestop, matchstop);
fptr = file + strlen(file) - 1;
mptr = match + strlen(match) - 1;
while (fptr >= file && mptr >= match)
{
if (toupper(*fptr) != toupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr)))
break;
fptr--; mptr--;
}
if (filestop) *filestop = fptr;
if (matchstop) *matchstop = mptr;
return mptr == match - 1;
}
static BOOL do_search(const char* file, char* buffer,
PENUMDIRTREE_CALLBACK cb, void* user)
{
HANDLE h;
WIN32_FIND_DATAA fd;
unsigned pos;
BOOL found = FALSE;
pos = strlen(buffer);
if (buffer[pos - 1] != '\\') buffer[pos++] = '\\';
strcpy(buffer + pos, "*.*");
if ((h = FindFirstFileA(buffer, &fd)) == INVALID_HANDLE_VALUE)
return FALSE;
/* doc doesn't specify how the tree is enumerated...
* doing a depth first based on, but may be wrong
*/
do
{
if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue;
strcpy(buffer + pos, fd.cFileName);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
found = do_search(file, buffer, cb, user);
else if (SymMatchFileName(buffer, (char*)file, NULL, NULL))
{
if (!cb || cb(buffer, user)) found = TRUE;
}
} while (!found && FindNextFileA(h, &fd));
if (!found) buffer[--pos] = '\0';
FindClose(h);
return found;
}
/***********************************************************************
* SearchTreeForFile (DBGHELP.@)
*/
BOOL WINAPI SearchTreeForFile(LPSTR root, LPSTR file, LPSTR buffer)
{
TRACE("(%s, %s, %p)\n",
debugstr_a(root), debugstr_a(file), buffer);
strcpy(buffer, root);
return do_search(file, buffer, NULL, NULL);
}
/******************************************************************
* EnumDirTree (DBGHELP.@)
*
*
*/
BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file,
LPSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user)
{
TRACE("(%p %s %s %p %p %p)\n", hProcess, root, file, buffer, cb, user);
strcpy(buffer, root);
return do_search(file, buffer, cb, user);
}
struct sffip
{
PVOID id;
DWORD two;
DWORD three;
DWORD flags;
PFINDFILEINPATHCALLBACK cb;
void* user;
};
static BOOL CALLBACK sffip_cb(LPCSTR buffer, void* user)
{
struct sffip* s = (struct sffip*)user;
/* FIXME: should check that id/two/three match the file pointed
* by buffer
*/
/* yes, EnumDirTree and SymFindFileInPath callbacks use the opposite
* convention to stop/continue enumeration. sigh.
*/
return !(s->cb)((char*)buffer, s->user);
}
/******************************************************************
* SymFindFileInPath (DBGHELP.@)
*
*/
BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file,
PVOID id, DWORD two, DWORD three, DWORD flags,
LPSTR buffer, PFINDFILEINPATHCALLBACK cb,
PVOID user)
{
struct sffip s;
struct process* pcs = process_find_by_handle(hProcess);
char tmp[MAX_PATH];
char* ptr;
TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n",
hProcess, searchPath, file, id, two, three, flags,
buffer, cb, user);
if (!pcs) return FALSE;
if (!searchPath) searchPath = pcs->search_path;
s.id = id;
s.two = two;
s.three = three;
s.flags = flags;
s.cb = cb;
s.user = user;
file = file_name(file);
while (searchPath)
{
ptr = strchr(searchPath, ';');
if (ptr)
{
memcpy(tmp, searchPath, ptr - searchPath);
tmp[ptr - searchPath] = 0;
searchPath = ptr + 1;
}
else
{
strcpy(tmp, searchPath);
searchPath = NULL;
}
if (EnumDirTree(hProcess, tmp, file, buffer, sffip_cb, &s)) return TRUE;
}
return FALSE;
}

View file

@ -0,0 +1,424 @@
/*
* File pe_module.c - handle PE module information
*
* 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
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "dbghelp_private.h"
#include "winreg.h"
#include "winternl.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/******************************************************************
* pe_load_stabs
*
* look for stabs information in PE header (it's how the mingw compiler provides
* its debugging information)
*/
static BOOL pe_load_stabs(const struct process* pcs, struct module* module,
const void* mapping, IMAGE_NT_HEADERS* nth)
{
IMAGE_SECTION_HEADER* section;
int i, stabsize = 0, stabstrsize = 0;
unsigned int stabs = 0, stabstr = 0;
BOOL ret = FALSE;
section = (IMAGE_SECTION_HEADER*)
((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
{
if (!strcasecmp(section->Name, ".stab"))
{
stabs = section->VirtualAddress;
stabsize = section->SizeOfRawData;
}
else if (!strncasecmp(section->Name, ".stabstr", 8))
{
stabstr = section->VirtualAddress;
stabstrsize = section->SizeOfRawData;
}
}
if (stabstrsize && stabsize)
{
ret = stabs_parse(module,
module->module.BaseOfImage - nth->OptionalHeader.ImageBase,
RtlImageRvaToVa(nth, (void*)mapping, stabs, NULL),
stabsize,
RtlImageRvaToVa(nth, (void*)mapping, stabstr, NULL),
stabstrsize);
}
return ret;
}
static BOOL CALLBACK dbg_match(char* file, void* user)
{
/* accept first file */
return FALSE;
}
/******************************************************************
* pe_load_dbg_file
*
* loads a .dbg file
*/
static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
const char* dbg_name, DWORD timestamp)
{
char tmp[MAX_PATH];
HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0;
const BYTE* dbg_mapping = NULL;
const IMAGE_SEPARATE_DEBUG_HEADER* hdr;
const IMAGE_DEBUG_DIRECTORY* dbg;
BOOL ret = FALSE;
WINE_TRACE("Processing DBG file %s\n", dbg_name);
if (SymFindFileInPath(pcs->handle, NULL, (char*)dbg_name,
NULL, 0, 0, 0,
tmp, dbg_match, NULL) &&
(hFile = CreateFileA(tmp, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE &&
((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
{
hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)dbg_mapping;
if (hdr->TimeDateStamp != timestamp)
{
WINE_ERR("Warning - %s has incorrect internal timestamp\n",
dbg_name);
/*
* Well, sometimes this happens to DBG files which ARE REALLY the
* right .DBG files but nonetheless this check fails. Anyway,
* WINDBG (debugger for Windows by Microsoft) loads debug symbols
* which have incorrect timestamps.
*/
}
if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
{
/* section headers come immediately after debug header */
const IMAGE_SECTION_HEADER *sectp =
(const IMAGE_SECTION_HEADER*)(hdr + 1);
/* and after that and the exported names comes the debug directory */
dbg = (const IMAGE_DEBUG_DIRECTORY*)
(dbg_mapping + sizeof(*hdr) +
hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
hdr->ExportedNamesSize);
ret = pe_load_debug_directory(pcs, module, dbg_mapping, sectp,
hdr->NumberOfSections, dbg,
hdr->DebugDirectorySize / sizeof(*dbg));
}
else
ERR("Wrong signature in .DBG file %s\n", debugstr_a(tmp));
}
else
WINE_ERR("-Unable to peruse .DBG file %s (%s)\n", dbg_name, debugstr_a(tmp));
if (dbg_mapping) UnmapViewOfFile((void*)dbg_mapping);
if (hMap) CloseHandle(hMap);
if (hFile != NULL) CloseHandle(hFile);
return ret;
}
/******************************************************************
* pe_load_msc_debug_info
*
* Process MSC debug information in PE file.
*/
static BOOL pe_load_msc_debug_info(const struct process* pcs,
struct module* module,
const void* mapping, IMAGE_NT_HEADERS* nth)
{
BOOL ret = FALSE;
const IMAGE_DATA_DIRECTORY* dir;
const IMAGE_DEBUG_DIRECTORY*dbg = NULL;
int nDbg;
/* Read in debug directory */
dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
if (!nDbg) return FALSE;
dbg = RtlImageRvaToVa(nth, (void*)mapping, dir->VirtualAddress, NULL);
/* Parse debug directory */
if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
{
/* Debug info is stripped to .DBG file */
const IMAGE_DEBUG_MISC* misc = (const IMAGE_DEBUG_MISC*)
((const char*)mapping + dbg->PointerToRawData);
if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC ||
misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
{
WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
module->module.ModuleName);
}
else
{
ret = pe_load_dbg_file(pcs, module, misc->Data, nth->FileHeader.TimeDateStamp);
}
}
else
{
const IMAGE_SECTION_HEADER *sectp = (const IMAGE_SECTION_HEADER*)((const char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
/* Debug info is embedded into PE module */
ret = pe_load_debug_directory(pcs, module, mapping, sectp,
nth->FileHeader.NumberOfSections, dbg, nDbg);
}
return ret;
}
/***********************************************************************
* pe_load_export_debug_info
*/
static BOOL pe_load_export_debug_info(const struct process* pcs,
struct module* module,
const void* mapping, IMAGE_NT_HEADERS* nth)
{
unsigned int i;
const IMAGE_EXPORT_DIRECTORY* exports;
DWORD base = module->module.BaseOfImage;
DWORD size;
if (dbghelp_options & SYMOPT_NO_PUBLICS) return TRUE;
#if 0
/* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */
/* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */
symt_new_public(module, NULL, module->module.ModuleName, base, 0,
TRUE /* FIXME */, TRUE /* FIXME */);
#endif
/* Add entry point */
symt_new_public(module, NULL, "EntryPoint",
base + nth->OptionalHeader.AddressOfEntryPoint, 0,
TRUE, TRUE);
#if 0
/* FIXME: we'd better store addresses linked to sections rather than
absolute values */
IMAGE_SECTION_HEADER* section;
/* Add start of sections */
section = (IMAGE_SECTION_HEADER*)
((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
{
symt_new_public(module, NULL, section->Name,
RtlImageRvaToVa(nth, (void*)mapping, section->VirtualAddress, NULL),
0, TRUE /* FIXME */, TRUE /* FIXME */);
}
#endif
/* Add exported functions */
if ((exports = RtlImageDirectoryEntryToData((void*)mapping, FALSE,
IMAGE_DIRECTORY_ENTRY_EXPORT, &size)))
{
const WORD* ordinals = NULL;
const DWORD_PTR* functions = NULL;
const DWORD* names = NULL;
unsigned int j;
char buffer[16];
functions = RtlImageRvaToVa(nth, (void*)mapping, exports->AddressOfFunctions, NULL);
ordinals = RtlImageRvaToVa(nth, (void*)mapping, exports->AddressOfNameOrdinals, NULL);
names = RtlImageRvaToVa(nth, (void*)mapping, exports->AddressOfNames, NULL);
for (i = 0; i < exports->NumberOfNames; i++)
{
if (!names[i]) continue;
symt_new_public(module, NULL,
RtlImageRvaToVa(nth, (void*)mapping, names[i], NULL),
base + functions[ordinals[i]],
0, TRUE /* FIXME */, TRUE /* FIXME */);
}
for (i = 0; i < exports->NumberOfFunctions; i++)
{
if (!functions[i]) continue;
/* Check if we already added it with a name */
for (j = 0; j < exports->NumberOfNames; j++)
if ((ordinals[j] == i) && names[j]) break;
if (j < exports->NumberOfNames) continue;
snprintf(buffer, sizeof(buffer), "%ld", i + exports->Base);
symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 0,
TRUE /* FIXME */, TRUE /* FIXME */);
}
}
/* no real debug info, only entry points */
if (module->module.SymType == SymDeferred)
module->module.SymType = SymExport;
return TRUE;
}
/******************************************************************
* pe_load_debug_info
*
*/
BOOL pe_load_debug_info(const struct process* pcs, struct module* module)
{
BOOL ret = FALSE;
HANDLE hFile;
HANDLE hMap;
void* mapping;
IMAGE_NT_HEADERS* nth;
hFile = CreateFileA(module->module.LoadedImageName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) return ret;
if ((hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0)
{
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
{
nth = RtlImageNtHeader(mapping);
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
{
ret = pe_load_stabs(pcs, module, mapping, nth) ||
pe_load_msc_debug_info(pcs, module, mapping, nth);
/* if we still have no debug info (we could only get SymExport at this
* point), then do the SymExport except if we have an ELF container,
* in which case we'll rely on the export's on the ELF side
*/
}
/* FIXME shouldn't we check that? if (!module_get_debug(pcs, module))l */
if (pe_load_export_debug_info(pcs, module, mapping, nth) && !ret)
ret = TRUE;
UnmapViewOfFile(mapping);
}
CloseHandle(hMap);
}
CloseHandle(hFile);
return ret;
}
/******************************************************************
* pe_load_module
*
*/
struct module* pe_load_module(struct process* pcs, char* name,
HANDLE hFile, DWORD base, DWORD size)
{
struct module* module = NULL;
BOOL opened = FALSE;
HANDLE hMap;
void* mapping;
char loaded_name[MAX_PATH];
loaded_name[0] = '\0';
if (!hFile)
{
if (!name)
{
/* FIXME SetLastError */
return NULL;
}
if ((hFile = FindExecutableImage(name, NULL, loaded_name)) == NULL)
return NULL;
opened = TRUE;
}
else if (name) strcpy(loaded_name, name);
else if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
FIXME("Trouble ahead (no module name passed in deferred mode)\n");
if (!(module = module_find_by_name(pcs, loaded_name, DMT_PE)) &&
(hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
{
if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
{
IMAGE_NT_HEADERS* nth = RtlImageNtHeader(mapping);
if (nth)
{
if (!base) base = nth->OptionalHeader.ImageBase;
if (!size) size = nth->OptionalHeader.SizeOfImage;
module = module_new(pcs, loaded_name, DMT_PE, base, size,
nth->FileHeader.TimeDateStamp,
nth->OptionalHeader.CheckSum);
if (module)
{
if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
module->module.SymType = SymDeferred;
else
pe_load_debug_info(pcs, module);
}
}
UnmapViewOfFile(mapping);
}
CloseHandle(hMap);
}
if (opened) CloseHandle(hFile);
return module;
}
/******************************************************************
* pe_load_module_from_pcs
*
*/
struct module* pe_load_module_from_pcs(struct process* pcs, const char* name,
const char* mod_name, DWORD base, DWORD size)
{
struct module* module;
const char* ptr;
if ((module = module_find_by_name(pcs, name, DMT_PE))) return module;
if (mod_name) ptr = mod_name;
else
{
for (ptr = name + strlen(name) - 1; ptr >= name; ptr--)
{
if (*ptr == '/' || *ptr == '\\')
{
ptr++;
break;
}
}
}
if (ptr && (module = module_find_by_name(pcs, ptr, DMT_PE))) return module;
if (base && pcs->dbg_hdr_addr)
{
IMAGE_DOS_HEADER dos;
IMAGE_NT_HEADERS nth;
if (ReadProcessMemory(pcs->handle, (char*)base, &dos, sizeof(dos), NULL) &&
dos.e_magic == IMAGE_DOS_SIGNATURE &&
ReadProcessMemory(pcs->handle, (char*)(base + dos.e_lfanew),
&nth, sizeof(nth), NULL) &&
nth.Signature == IMAGE_NT_SIGNATURE)
{
if (!size) size = nth.OptionalHeader.SizeOfImage;
module = module_new(pcs, name, DMT_PE, base, size,
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum);
}
}
return module;
}

View file

@ -0,0 +1,138 @@
/*
* File source.c - source files management
*
* 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
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "dbghelp_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
/******************************************************************
* source_find
*
* check whether a source file has already been stored
*/
static unsigned source_find(const struct module* module, const char* name)
{
char* ptr = module->sources;
while (*ptr)
{
if (strcmp(ptr, name) == 0) return ptr - module->sources;
ptr += strlen(ptr) + 1;
}
return (unsigned)-1;
}
/******************************************************************
* source_new
*
* checks if source exists. if not, add it
*/
unsigned source_new(struct module* module, const char* name)
{
int len;
unsigned ret;
if (!name) return (unsigned)-1;
if (module->sources && (ret = source_find(module, name)) != (unsigned)-1)
return ret;
len = strlen(name) + 1;
if (module->sources_used + len + 1 > module->sources_alloc)
{
/* Alloc by block of 256 bytes */
module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255;
if (!module->sources)
module->sources = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc);
else
module->sources = HeapReAlloc(GetProcessHeap(), 0, module->sources,
module->sources_alloc);
}
ret = module->sources_used;
strcpy(module->sources + module->sources_used, name);
module->sources_used += len;
module->sources[module->sources_used] = '\0';
return ret;
}
/******************************************************************
* source_get
*
* returns a stored source file name
*/
const char* source_get(const struct module* module, unsigned idx)
{
if (idx == -1) return "";
assert(module->sources);
return module->sources + idx;
}
/******************************************************************
* SymEnumSourceFiles (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, LPSTR Mask,
PSYM_ENUMSOURCFILES_CALLBACK cbSrcFiles,
PVOID UserContext)
{
struct process* pcs;
struct module* module;
SOURCEFILE sf;
char* ptr;
if (!cbSrcFiles) return FALSE;
pcs = process_find_by_handle(hProcess);
if (!pcs) return FALSE;
if (ModBase)
{
module = module_find_by_addr(pcs, ModBase, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module))) return FALSE;
}
else
{
if (Mask[0] == '!')
{
module = module_find_by_name(pcs, Mask + 1, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module))) return FALSE;
}
else
{
FIXME("Unsupported yet (should get info from current context)\n");
return FALSE;
}
}
if (!module->sources) return FALSE;
for (ptr = module->sources; *ptr; ptr += strlen(ptr) + 1)
{
/* FIXME: not using Mask */
sf.ModBase = ModBase;
sf.FileName = ptr;
if (!cbSrcFiles(&sf, UserContext)) break;
}
return TRUE;
}

1480
reactos/lib/dbghelp/stabs.c Normal file

File diff suppressed because it is too large Load diff

388
reactos/lib/dbghelp/stack.c Normal file
View file

@ -0,0 +1,388 @@
/*
* Stack walking
*
* Copyright 1995 Alexandre Julliard
* Copyright 1996 Eric Youngdale
* Copyright 1999 Ove Kåven
* Copyright 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
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "dbghelp_private.h"
#include "winreg.h"
#include "ntstatus.h"
#include "thread.h" /* FIXME: must be included before winternl.h */
#include "winternl.h"
#include "wine/debug.h"
#include "stackframe.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
static const char* wine_dbgstr_addr(const ADDRESS* addr)
{
if (!addr) return "(null)";
switch (addr->Mode)
{
case AddrModeFlat:
return wine_dbg_sprintf("flat<%08lx>", addr->Offset);
case AddrMode1616:
return wine_dbg_sprintf("1616<%04x:%04lx>", addr->Segment, addr->Offset);
case AddrMode1632:
return wine_dbg_sprintf("1632<%04x:%08lx>", addr->Segment, addr->Offset);
case AddrModeReal:
return wine_dbg_sprintf("real<%04x:%04lx>", addr->Segment, addr->Offset);
default:
return "unknown";
}
}
/* indexes in Reserved array */
#define __CurrentMode 0
#define __CurrentSwitch 1
#define __NextSwitch 2
#define curr_mode (frame->Reserved[__CurrentMode])
#define curr_switch (frame->Reserved[__CurrentSwitch])
#define next_switch (frame->Reserved[__NextSwitch])
/***********************************************************************
* StackWalk (DBGHELP.@)
*/
BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
LPSTACKFRAME frame, LPVOID ctx,
PREAD_PROCESS_MEMORY_ROUTINE f_read_mem,
PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr)
{
STACK32FRAME frame32;
STACK16FRAME frame16;
char ch;
ADDRESS tmp;
DWORD p;
WORD val;
BOOL do_switch;
TRACE("(%ld, %p, %p, %p, %p, %p, %p, %p, %p)\n",
MachineType, hProcess, hThread, frame, ctx,
f_read_mem, FunctionTableAccessRoutine,
GetModuleBaseRoutine, f_xlat_adr);
if (MachineType != IMAGE_FILE_MACHINE_I386)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* sanity check */
if (curr_mode >= stm_done) return FALSE;
if (!f_read_mem) f_read_mem = ReadProcessMemory;
if (!f_xlat_adr) f_xlat_adr = addr_to_linear;
TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
wine_dbgstr_addr(&frame->AddrPC),
wine_dbgstr_addr(&frame->AddrFrame),
wine_dbgstr_addr(&frame->AddrReturn),
wine_dbgstr_addr(&frame->AddrStack),
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
curr_switch, next_switch);
if (curr_mode == stm_start)
{
THREAD_BASIC_INFORMATION info;
if ((frame->AddrPC.Mode == AddrModeFlat) &&
(frame->AddrFrame.Mode != AddrModeFlat))
{
WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
goto done_err;
}
/* Init done */
curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ?
stm_32bit : stm_16bit;
/* cur_switch holds address of curr_stack's field in TEB in debuggee
* address space
*/
if (NtQueryInformationThread(hThread, ThreadBasicInformation, &info,
sizeof(info), NULL) != STATUS_SUCCESS)
goto done_err;
curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, cur_stack);
if (!f_read_mem(hProcess, (void*)curr_switch, &next_switch,
sizeof(next_switch), NULL))
{
WARN("Can't read TEB:cur_stack\n");
goto done_err;
}
if (curr_mode == stm_16bit)
{
if (!f_read_mem(hProcess, (void*)next_switch, &frame32,
sizeof(frame32), NULL))
{
WARN("Bad stack frame 0x%08lx\n", next_switch);
goto done_err;
}
curr_switch = (DWORD)frame32.frame16;
tmp.Mode = AddrMode1616;
tmp.Segment = SELECTOROF(curr_switch);
tmp.Offset = OFFSETOF(curr_switch);
if (!f_read_mem(hProcess, (void*)f_xlat_adr(hProcess, hThread, &tmp),
&ch, sizeof(ch), NULL))
curr_switch = 0xFFFFFFFF;
frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrMode1616;
}
else
{
tmp.Mode = AddrMode1616;
tmp.Segment = SELECTOROF(next_switch);
tmp.Offset = OFFSETOF(next_switch);
p = f_xlat_adr(hProcess, hThread, &tmp);
if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
{
WARN("Bad stack frame 0x%08lx\n", p);
goto done_err;
}
curr_switch = (DWORD)frame16.frame32;
if (!f_read_mem(hProcess, (void*)curr_switch, &ch, sizeof(ch), NULL))
curr_switch = 0xFFFFFFFF;
frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat;
}
/* don't set up AddrStack on first call. Either the caller has set it up, or
* we will get it in the next frame
*/
}
else
{
if (frame->AddrFrame.Offset == 0) goto done_err;
if (frame->AddrFrame.Mode == AddrModeFlat)
{
assert(curr_mode == stm_32bit);
do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
}
else
{
assert(curr_mode == stm_16bit);
do_switch = OFFSETOF(curr_switch) &&
frame->AddrFrame.Segment == SELECTOROF(curr_switch) &&
frame->AddrFrame.Offset >= OFFSETOF(curr_switch);
}
if (do_switch)
{
if (curr_mode == stm_16bit)
{
if (!f_read_mem(hProcess, (void*)next_switch, &frame32,
sizeof(frame32), NULL))
{
WARN("Bad stack frame 0x%08lx\n", next_switch);
goto done_err;
}
frame->AddrPC.Mode = AddrModeFlat;
frame->AddrPC.Segment = 0;
frame->AddrPC.Offset = frame32.retaddr;
frame->AddrFrame.Mode = AddrModeFlat;
frame->AddrFrame.Segment = 0;
frame->AddrFrame.Offset = frame32.ebp;
frame->AddrStack.Mode = AddrModeFlat;
frame->AddrStack.Segment = 0;
frame->AddrReturn.Mode = AddrModeFlat;
frame->AddrReturn.Segment = 0;
next_switch = curr_switch;
tmp.Mode = AddrMode1616;
tmp.Segment = SELECTOROF(next_switch);
tmp.Offset = OFFSETOF(next_switch);
p = f_xlat_adr(hProcess, hThread, &tmp);
if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
{
WARN("Bad stack frame 0x%08lx\n", p);
goto done_err;
}
curr_switch = (DWORD)frame16.frame32;
curr_mode = stm_32bit;
if (!f_read_mem(hProcess, (void*)curr_switch, &ch, sizeof(ch), NULL))
curr_switch = 0xFFFFFFFF;
}
else
{
tmp.Mode = AddrMode1616;
tmp.Segment = SELECTOROF(next_switch);
tmp.Offset = OFFSETOF(next_switch);
p = f_xlat_adr(hProcess, hThread, &tmp);
if (!f_read_mem(hProcess, (void*)p, &frame16, sizeof(frame16), NULL))
{
WARN("Bad stack frame 0x%08lx\n", p);
goto done_err;
}
TRACE("Got a 16 bit stack switch:"
"\n\tframe32: %08lx"
"\n\tedx:%08lx ecx:%08lx ebp:%08lx"
"\n\tds:%04x es:%04x fs:%04x gs:%04x"
"\n\tcall_from_ip:%08lx module_cs:%04lx relay=%08lx"
"\n\tentry_ip:%04x entry_point:%08lx"
"\n\tbp:%04x ip:%04x cs:%04x\n",
(unsigned long)frame16.frame32,
frame16.edx, frame16.ecx, frame16.ebp,
frame16.ds, frame16.es, frame16.fs, frame16.gs,
frame16.callfrom_ip, frame16.module_cs, frame16.relay,
frame16.entry_ip, frame16.entry_point,
frame16.bp, frame16.ip, frame16.cs);
frame->AddrPC.Mode = AddrMode1616;
frame->AddrPC.Segment = frame16.cs;
frame->AddrPC.Offset = frame16.ip;
frame->AddrFrame.Mode = AddrMode1616;
frame->AddrFrame.Segment = SELECTOROF(next_switch);
frame->AddrFrame.Offset = frame16.bp;
frame->AddrStack.Mode = AddrMode1616;
frame->AddrStack.Segment = SELECTOROF(next_switch);
frame->AddrReturn.Mode = AddrMode1616;
frame->AddrReturn.Segment = frame16.cs;
next_switch = curr_switch;
if (!f_read_mem(hProcess, (void*)next_switch, &frame32, sizeof(frame32),
NULL))
{
WARN("Bad stack frame 0x%08lx\n", next_switch);
goto done_err;
}
curr_switch = (DWORD)frame32.frame16;
tmp.Mode = AddrMode1616;
tmp.Segment = SELECTOROF(curr_switch);
tmp.Offset = OFFSETOF(curr_switch);
if (!f_read_mem(hProcess, (void*)f_xlat_adr(hProcess, hThread, &tmp),
&ch, sizeof(ch), NULL))
curr_switch = 0xFFFFFFFF;
curr_mode = stm_16bit;
}
}
else
{
frame->AddrPC = frame->AddrReturn;
if (curr_mode == stm_16bit)
{
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
/* "pop up" previous BP value */
if (!f_read_mem(hProcess,
(void*)f_xlat_adr(hProcess, hThread, &frame->AddrFrame),
&val, sizeof(WORD), NULL))
goto done_err;
frame->AddrFrame.Offset = val;
}
else
{
frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
/* "pop up" previous EBP value */
if (!f_read_mem(hProcess, (void*)frame->AddrFrame.Offset,
&frame->AddrFrame.Offset, sizeof(DWORD), NULL))
goto done_err;
}
}
}
if (curr_mode == stm_16bit)
{
int i;
p = f_xlat_adr(hProcess, hThread, &frame->AddrFrame);
if (!f_read_mem(hProcess, (void*)(p + sizeof(WORD)), &val, sizeof(WORD), NULL))
goto done_err;
frame->AddrReturn.Offset = val;
/* get potential cs if a far call was used */
if (!f_read_mem(hProcess, (void*)(p + 2 * sizeof(WORD)),
&val, sizeof(WORD), NULL))
goto done_err;
if (frame->AddrFrame.Offset & 1)
frame->AddrReturn.Segment = val; /* far call assumed */
else
{
/* not explicitly marked as far call,
* but check whether it could be anyway
*/
if ((val & 7) == 7 && val != frame->AddrReturn.Segment)
{
LDT_ENTRY le;
if (GetThreadSelectorEntry(hThread, val, &le) &&
(le.HighWord.Bits.Type & 0x08)) /* code segment */
{
/* it is very uncommon to push a code segment cs as
* a parameter, so this should work in most cases
*/
frame->AddrReturn.Segment = val;
}
}
}
frame->AddrFrame.Offset &= ~1;
/* we "pop" parameters as 16 bit entities... of course, this won't
* work if the parameter is in fact bigger than 16bit, but
* there's no way to know that here
*/
for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
{
f_read_mem(hProcess, (void*)(p + (2 + i) * sizeof(WORD)),
&val, sizeof(val), NULL);
frame->Params[i] = val;
}
}
else
{
if (!f_read_mem(hProcess,
(void*)(frame->AddrFrame.Offset + sizeof(DWORD)),
&frame->AddrReturn.Offset, sizeof(DWORD), NULL))
goto done_err;
f_read_mem(hProcess,
(void*)(frame->AddrFrame.Offset + 2 * sizeof(DWORD)),
frame->Params, sizeof(frame->Params), NULL);
}
frame->Far = FALSE;
frame->Virtual = FALSE;
TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08lx nSwitch=%08lx\n",
wine_dbgstr_addr(&frame->AddrPC),
wine_dbgstr_addr(&frame->AddrFrame),
wine_dbgstr_addr(&frame->AddrReturn),
wine_dbgstr_addr(&frame->AddrStack),
curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
curr_switch, next_switch);
return TRUE;
done_err:
curr_mode = stm_done;
return FALSE;
}

View file

@ -0,0 +1,335 @@
/*
* Various storage structures (pool allocation, vector, hash table)
*
* Copyright (C) 1993, Eric Youngdale.
* 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
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include "wine/debug.h"
#include "dbghelp_private.h"
#ifdef USE_STATS
#include <math.h>
#endif
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
struct pool_arena
{
struct pool_arena* next;
char* current;
};
void pool_init(struct pool* a, unsigned arena_size)
{
a->arena_size = arena_size;
a->first = NULL;
}
void pool_destroy(struct pool* pool)
{
struct pool_arena* arena;
struct pool_arena* next;
#ifdef USE_STATS
unsigned alloc, used, num;
for (alloc = used = num = 0, arena = pool->first; arena; arena = arena->next)
{
alloc += pool->arena_size;
used += arena->current - (char*)arena;
num++;
}
FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas,\n"
"\t\t\t\tnon-allocation ratio: %.2f%%\n",
pool, alloc >> 10, used >> 10, num, 100.0 - (float)used / (float)alloc * 100.0);
#endif
for (arena = pool->first; arena; arena = next)
{
next = arena->next;
HeapFree(GetProcessHeap(), 0, arena);
}
pool_init(pool, 0);
}
void* pool_alloc(struct pool* pool, unsigned len)
{
struct pool_arena** parena;
struct pool_arena* arena;
void* ret;
len = (len + 3) & ~3; /* round up size on DWORD boundary */
assert(sizeof(struct pool_arena) + len <= pool->arena_size && len);
for (parena = &pool->first; *parena; parena = &(*parena)->next)
{
if ((char*)(*parena) + pool->arena_size - (*parena)->current >= len)
{
ret = (*parena)->current;
(*parena)->current += len;
return ret;
}
}
arena = HeapAlloc(GetProcessHeap(), 0, pool->arena_size);
if (!arena) {FIXME("OOM\n");return NULL;}
*parena = arena;
ret = (char*)arena + sizeof(*arena);
arena->next = NULL;
arena->current = (char*)ret + len;
return ret;
}
static struct pool_arena* pool_is_last(struct pool* pool, void* p, unsigned old_size)
{
struct pool_arena* arena;
for (arena = pool->first; arena; arena = arena->next)
{
if (arena->current == (char*)p + old_size) return arena;
}
return NULL;
}
void* pool_realloc(struct pool* pool, void* p, unsigned old_size, unsigned new_size)
{
struct pool_arena* arena;
void* new;
if ((arena = pool_is_last(pool, p, old_size)) &&
(char*)p + new_size <= (char*)arena + pool->arena_size)
{
arena->current = (char*)p + new_size;
return p;
}
if ((new = pool_alloc(pool, new_size)) && old_size)
memcpy(new, p, min(old_size, new_size));
return new;
}
char* pool_strdup(struct pool* pool, const char* str)
{
char* ret;
if ((ret = pool_alloc(pool, strlen(str) + 1))) strcpy(ret, str);
return ret;
}
void vector_init(struct vector* v, unsigned esz, unsigned bucket_sz)
{
v->buckets = NULL;
/* align size on DWORD boundaries */
v->elt_size = (esz + 3) & ~3;
switch (bucket_sz)
{
case 2: v->shift = 1; break;
case 4: v->shift = 2; break;
case 8: v->shift = 3; break;
case 16: v->shift = 4; break;
case 32: v->shift = 5; break;
case 64: v->shift = 6; break;
case 128: v->shift = 7; break;
case 256: v->shift = 8; break;
case 512: v->shift = 9; break;
case 1024: v->shift = 10; break;
default: assert(0);
}
v->num_buckets = 0;
v->num_elts = 0;
}
unsigned vector_length(const struct vector* v)
{
return v->num_elts;
}
void* vector_at(const struct vector* v, unsigned pos)
{
unsigned o;
if (pos >= v->num_elts) return NULL;
o = pos & ((1 << v->shift) - 1);
return (char*)v->buckets[pos >> v->shift] + o * v->elt_size;
}
void* vector_add(struct vector* v, struct pool* pool)
{
unsigned ncurr = v->num_elts++;
/* check that we don't wrap around */
assert(v->num_elts > ncurr);
if (ncurr == (v->num_buckets << v->shift))
{
v->buckets = pool_realloc(pool, v->buckets,
v->num_buckets * sizeof(void*),
(v->num_buckets + 1) * sizeof(void*));
v->buckets[v->num_buckets] = pool_alloc(pool, v->elt_size << v->shift);
return v->buckets[v->num_buckets++];
}
return vector_at(v, ncurr);
}
static unsigned vector_position(const struct vector* v, const void* elt)
{
int i;
for (i = 0; i < v->num_buckets; i++)
{
if (v->buckets[i] <= elt &&
(const char*)elt < (const char*)v->buckets[i] + (v->elt_size << v->shift))
{
return (i << v->shift) +
((const char*)elt - (const char*)v->buckets[i]) / v->elt_size;
}
}
assert(0);
return 0;
}
void* vector_iter_up(const struct vector* v, void* elt)
{
unsigned pos;
if (!elt) return vector_at(v, 0);
pos = vector_position(v, elt) + 1;
if (pos >= vector_length(v)) return NULL;
return vector_at(v, pos);
}
void* vector_iter_down(const struct vector* v, void* elt)
{
unsigned pos;
if (!elt) return vector_at(v, vector_length(v) - 1);
pos = vector_position(v, elt);
if (pos == 0) return NULL;
return vector_at(v, pos - 1);
}
unsigned hash_table_hash(const char* name, unsigned num_buckets)
{
unsigned hash = 0;
while (*name)
{
hash += *name++;
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash % num_buckets;
}
void hash_table_init(struct pool* pool, struct hash_table* ht, unsigned num_buckets)
{
ht->buckets = pool_alloc(pool, num_buckets * sizeof(struct hash_table_elt*));
assert(ht->buckets);
ht->num_buckets = num_buckets;
memset(ht->buckets, 0, num_buckets * sizeof(struct hash_table_elt*));
}
void hash_table_destroy(struct hash_table* ht)
{
#if defined(USE_STATS)
int i;
unsigned len;
unsigned num = 0, min = 0xffffffff, max = 0, sq = 0;
struct hash_table_elt* elt;
double mean, variance;
for (i = 0; i < ht->num_buckets; i++)
{
for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++;
if (len < min) min = len;
if (len > max) max = len;
num += len;
sq += len * len;
}
mean = (double)num / ht->num_buckets;
variance = (double)sq / ht->num_buckets - mean * mean;
FIXME("STATS: elts[num:%-4u size:%u mean:%f] buckets[min:%-4u variance:%+f max:%-4u]\n",
num, ht->num_buckets, mean, min, variance, max);
#if 1
for (i = 0; i < ht->num_buckets; i++)
{
for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++;
if (len == max)
{
FIXME("Longuest bucket:\n");
for (elt = ht->buckets[i]; elt; elt = elt->next)
FIXME("\t%s\n", elt->name);
break;
}
}
#endif
#endif
}
void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt)
{
unsigned hash = hash_table_hash(elt->name, ht->num_buckets);
struct hash_table_elt** p;
/* in some cases, we need to get back the symbols of same name in the order
* in which they've been inserted. So insert new elements at the end of the list.
*/
for (p = &ht->buckets[hash]; *p; p = &((*p)->next));
*p = elt;
elt->next = NULL;
}
void* hash_table_find(const struct hash_table* ht, const char* name)
{
unsigned hash = hash_table_hash(name, ht->num_buckets);
struct hash_table_elt* elt;
for (elt = ht->buckets[hash]; elt; elt = elt->next)
if (!strcmp(name, elt->name)) return elt;
return NULL;
}
void hash_table_iter_init(const struct hash_table* ht,
struct hash_table_iter* hti, const char* name)
{
hti->ht = ht;
if (name)
{
hti->last = hash_table_hash(name, ht->num_buckets);
hti->index = hti->last - 1;
}
else
{
hti->last = ht->num_buckets - 1;
hti->index = -1;
}
hti->element = NULL;
}
void* hash_table_iter_up(struct hash_table_iter* hti)
{
if (hti->element) hti->element = hti->element->next;
while (!hti->element && hti->index < hti->last)
hti->element = hti->ht->buckets[++hti->index];
return hti->element;
}

1228
reactos/lib/dbghelp/symbol.c Normal file

File diff suppressed because it is too large Load diff

784
reactos/lib/dbghelp/type.c Normal file
View file

@ -0,0 +1,784 @@
/*
* File types.c - management of types (hierarchical tree)
*
* Copyright (C) 1997, Eric Youngdale.
* 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 really doesn't do much at the moment, but it forms the framework
* upon which full support for datatype handling will eventually be built.
*/
#include "config.h"
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "wine/debug.h"
#include "dbghelp_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);
static const char* symt_get_tag_str(DWORD tag)
{
switch (tag)
{
case SymTagNull: return "SymTagNull";
case SymTagExe: return "SymTagExe";
case SymTagCompiland: return "SymTagCompiland";
case SymTagCompilandDetails: return "SymTagCompilandDetails";
case SymTagCompilandEnv: return "SymTagCompilandEnv";
case SymTagFunction: return "SymTagFunction";
case SymTagBlock: return "SymTagBlock";
case SymTagData: return "SymTagData";
case SymTagAnnotation: return "SymTagAnnotation";
case SymTagLabel: return "SymTagLabel";
case SymTagPublicSymbol: return "SymTagPublicSymbol";
case SymTagUDT: return "SymTagUDT";
case SymTagEnum: return "SymTagEnum";
case SymTagFunctionType: return "SymTagFunctionType";
case SymTagPointerType: return "SymTagPointerType";
case SymTagArrayType: return "SymTagArrayType";
case SymTagBaseType: return "SymTagBaseType";
case SymTagTypedef: return "SymTagTypedef,";
case SymTagBaseClass: return "SymTagBaseClass";
case SymTagFriend: return "SymTagFriend";
case SymTagFunctionArgType: return "SymTagFunctionArgType,";
case SymTagFuncDebugStart: return "SymTagFuncDebugStart,";
case SymTagFuncDebugEnd: return "SymTagFuncDebugEnd";
case SymTagUsingNamespace: return "SymTagUsingNamespace,";
case SymTagVTableShape: return "SymTagVTableShape";
case SymTagVTable: return "SymTagVTable";
case SymTagCustom: return "SymTagCustom";
case SymTagThunk: return "SymTagThunk";
case SymTagCustomType: return "SymTagCustomType";
case SymTagManagedType: return "SymTagManagedType";
case SymTagDimension: return "SymTagDimension";
default: return "---";
}
}
const char* symt_get_name(const struct symt* sym)
{
switch (sym->tag)
{
/* lexical tree */
case SymTagData: return ((const struct symt_data*)sym)->hash_elt.name;
case SymTagFunction: return ((const struct symt_function*)sym)->hash_elt.name;
case SymTagPublicSymbol: return ((const struct symt_public*)sym)->hash_elt.name;
case SymTagBaseType: return ((const struct symt_basic*)sym)->hash_elt.name;
case SymTagLabel: return ((const struct symt_function_point*)sym)->name;
case SymTagThunk: return ((const struct symt_thunk*)sym)->hash_elt.name;
/* hierarchy tree */
case SymTagEnum: return ((const struct symt_enum*)sym)->name;
case SymTagTypedef: return ((const struct symt_typedef*)sym)->hash_elt.name;
case SymTagUDT: return ((const struct symt_udt*)sym)->hash_elt.name;
default:
FIXME("Unsupported sym-tag %s\n", symt_get_tag_str(sym->tag));
/* fall through */
case SymTagArrayType:
case SymTagPointerType:
case SymTagFunctionType:
return NULL;
}
}
static struct symt* symt_find_type_by_name(struct module* module,
enum SymTagEnum sym_tag,
const char* typename)
{
void* ptr;
struct symt_ht* type;
struct hash_table_iter hti;
assert(typename);
assert(module);
hash_table_iter_init(&module->ht_types, &hti, typename);
while ((ptr = hash_table_iter_up(&hti)))
{
type = GET_ENTRY(ptr, struct symt_ht, hash_elt);
if ((sym_tag == SymTagNull || type->symt.tag == sym_tag) &&
type->hash_elt.name && !strcmp(type->hash_elt.name, typename))
return &type->symt;
}
SetLastError(ERROR_INVALID_NAME); /* FIXME ?? */
return NULL;
}
static void symt_add_type(struct module* module, struct symt* symt)
{
struct symt** p;
p = vector_add(&module->vtypes, &module->pool);
assert(p);
*p = symt;
}
struct symt_basic* symt_new_basic(struct module* module, enum BasicType bt,
const char* typename, unsigned size)
{
struct symt_basic* sym;
if (typename)
{
sym = (struct symt_basic*)symt_find_type_by_name(module, SymTagBaseType,
typename);
if (sym && sym->bt == bt && sym->size == size)
return sym;
}
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagBaseType;
if (typename)
{
sym->hash_elt.name = pool_strdup(&module->pool, typename);
hash_table_add(&module->ht_types, &sym->hash_elt);
} else sym->hash_elt.name = NULL;
sym->bt = bt;
sym->size = size;
symt_add_type(module, &sym->symt);
}
return sym;
}
struct symt_udt* symt_new_udt(struct module* module, const char* typename,
unsigned size, enum UdtKind kind)
{
struct symt_udt* sym;
TRACE_(dbghelp_symt)("Adding udt %s:%s\n", module->module.ModuleName, typename);
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagUDT;
sym->kind = kind;
sym->size = size;
if (typename)
{
sym->hash_elt.name = pool_strdup(&module->pool, typename);
hash_table_add(&module->ht_types, &sym->hash_elt);
} else sym->hash_elt.name = NULL;
vector_init(&sym->vchildren, sizeof(struct symt*), 8);
symt_add_type(module, &sym->symt);
}
return sym;
}
BOOL symt_set_udt_size(struct module* module, struct symt_udt* udt, unsigned size)
{
assert(udt->symt.tag == SymTagUDT);
if (vector_length(&udt->vchildren) != 0)
{
if (udt->size != size)
FIXME_(dbghelp_symt)("Changing size for %s from %u to %u\n",
udt->hash_elt.name, udt->size, size);
return TRUE;
}
udt->size = size;
return TRUE;
}
/******************************************************************
* symt_add_udt_element
*
* add an element to a udt (struct, class, union)
* the size & offset parameters are expressed in bits (not bytes) so that
* we can mix in the single call bytes aligned elements (regular fields) and
* the others (bit fields)
*/
BOOL symt_add_udt_element(struct module* module, struct symt_udt* udt_type,
const char* name, struct symt* elt_type,
unsigned offset, unsigned size)
{
struct symt_data* m;
struct symt** p;
assert(udt_type->symt.tag == SymTagUDT);
TRACE_(dbghelp_symt)("Adding %s to UDT %s\n", name, udt_type->hash_elt.name);
p = NULL;
while ((p = vector_iter_up(&udt_type->vchildren, p)))
{
m = (struct symt_data*)*p;
assert(m);
assert(m->symt.tag == SymTagData);
if (m->hash_elt.name[0] == name[0] && strcmp(m->hash_elt.name, name) == 0)
return TRUE;
}
if ((m = pool_alloc(&module->pool, sizeof(*m))) == NULL) return FALSE;
memset(m, 0, sizeof(*m));
m->symt.tag = SymTagData;
m->hash_elt.name = pool_strdup(&module->pool, name);
m->hash_elt.next = NULL;
m->kind = DataIsMember;
m->container = &udt_type->symt;
m->type = elt_type;
m->u.s.offset = offset;
m->u.s.length = ((offset & 7) || (size & 7)) ? size : 0;
m->u.s.reg_id = 0;
p = vector_add(&udt_type->vchildren, &module->pool);
*p = &m->symt;
return TRUE;
}
struct symt_enum* symt_new_enum(struct module* module, const char* typename)
{
struct symt_enum* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagEnum;
sym->name = (typename) ? pool_strdup(&module->pool, typename) : NULL;
vector_init(&sym->vchildren, sizeof(struct symt*), 8);
}
return sym;
}
BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type,
const char* name, int value)
{
struct symt_data* e;
struct symt** p;
assert(enum_type->symt.tag == SymTagEnum);
e = pool_alloc(&module->pool, sizeof(*e));
if (e == NULL) return FALSE;
e->symt.tag = SymTagData;
e->hash_elt.name = pool_strdup(&module->pool, name);
e->hash_elt.next = NULL;
e->kind = DataIsConstant;
e->container = &enum_type->symt;
/* CV defines the underlying type for the enumeration */
e->type = &symt_new_basic(module, btInt, "int", 4)->symt;
e->u.value.n1.n2.vt = VT_I4;
e->u.value.n1.n2.n3.lVal = value;
p = vector_add(&enum_type->vchildren, &module->pool);
if (!p) return FALSE; /* FIXME we leak e */
*p = &e->symt;
return TRUE;
}
struct symt_array* symt_new_array(struct module* module, int min, int max,
struct symt* base)
{
struct symt_array* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagArrayType;
sym->start = min;
sym->end = max;
sym->basetype = base;
symt_add_type(module, &sym->symt);
}
return sym;
}
struct symt_function_signature* symt_new_function_signature(struct module* module,
struct symt* ret_type)
{
struct symt_function_signature* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagFunctionType;
sym->rettype = ret_type;
vector_init(&sym->vchildren, sizeof(struct symt*), 4);
symt_add_type(module, &sym->symt);
}
return sym;
}
BOOL symt_add_function_signature_parameter(struct module* module,
struct symt_function_signature* sig_type,
struct symt* param)
{
struct symt** p;
assert(sig_type->symt.tag == SymTagFunctionType);
p = vector_add(&sig_type->vchildren, &module->pool);
if (!p) return FALSE; /* FIXME we leak e */
*p = param;
return TRUE;
}
struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_type)
{
struct symt_pointer* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagPointerType;
sym->pointsto = ref_type;
symt_add_type(module, &sym->symt);
}
return sym;
}
struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref,
const char* name)
{
struct symt_typedef* sym;
if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
{
sym->symt.tag = SymTagTypedef;
sym->type = ref;
sym->hash_elt.name = pool_strdup(&module->pool, name);
hash_table_add(&module->ht_types, &sym->hash_elt);
symt_add_type(module, &sym->symt);
}
return sym;
}
/******************************************************************
* SymEnumTypes (DBGHELP.@)
*
*/
BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll,
PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
PVOID UserContext)
{
struct process* pcs;
struct module* module;
char buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
const char* tmp;
struct symt* type;
void* pos = NULL;
TRACE("(%p %s %p %p)\n",
hProcess, wine_dbgstr_longlong(BaseOfDll), EnumSymbolsCallback,
UserContext);
if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module))) return FALSE;
sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);
while ((pos = vector_iter_up(&module->vtypes, pos)))
{
type = *(struct symt**)pos;
sym_info->TypeIndex = (DWORD)type;
sym_info->info = 0; /* FIXME */
symt_get_info(type, TI_GET_LENGTH, &sym_info->Size);
sym_info->ModBase = module->module.BaseOfImage;
sym_info->Flags = 0; /* FIXME */
sym_info->Value = 0; /* FIXME */
sym_info->Address = 0; /* FIXME */
sym_info->Register = 0; /* FIXME */
sym_info->Scope = 0; /* FIXME */
sym_info->Tag = type->tag;
tmp = symt_get_name(type);
if (tmp)
{
sym_info->NameLen = strlen(tmp) + 1;
strncpy(sym_info->Name, tmp, min(sym_info->NameLen, sym_info->MaxNameLen));
sym_info->Name[sym_info->MaxNameLen - 1] = '\0';
}
else sym_info->Name[sym_info->NameLen = 0] = '\0';
if (!EnumSymbolsCallback(sym_info, sym_info->Size, UserContext)) break;
}
return TRUE;
}
/******************************************************************
* symt_get_info
*
* Retrieves inforamtion about a symt (either symbol or type)
*/
BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req,
void* pInfo)
{
unsigned len;
if (!type) return FALSE;
/* helper to typecast pInfo to its expected type (_t) */
#define X(_t) (*((_t*)pInfo))
switch (req)
{
case TI_FINDCHILDREN:
{
const struct vector* v;
struct symt** pt;
unsigned i;
TI_FINDCHILDREN_PARAMS* tifp = pInfo;
switch (type->tag)
{
case SymTagUDT: v = &((const struct symt_udt*)type)->vchildren; break;
case SymTagEnum: v = &((const struct symt_enum*)type)->vchildren; break;
case SymTagFunctionType: v = &((const struct symt_function_signature*)type)->vchildren; break;
case SymTagFunction: v = &((const struct symt_function*)type)->vchildren; break;
default:
FIXME("Unsupported sym-tag %s for find-children\n",
symt_get_tag_str(type->tag));
return FALSE;
}
for (i = 0; i < tifp->Count; i++)
{
if (!(pt = vector_at(v, tifp->Start + i))) return FALSE;
tifp->ChildId[i] = (DWORD)*pt;
}
}
break;
case TI_GET_ADDRESS:
switch (type->tag)
{
case SymTagData:
switch (((const struct symt_data*)type)->kind)
{
case DataIsGlobal:
case DataIsFileStatic:
X(ULONG64) = ((const struct symt_data*)type)->u.address;
break;
default: return FALSE;
}
break;
case SymTagFunction:
X(ULONG64) = ((const struct symt_function*)type)->address;
break;
case SymTagPublicSymbol:
X(ULONG64) = ((const struct symt_public*)type)->address;
break;
case SymTagFuncDebugStart:
case SymTagFuncDebugEnd:
case SymTagLabel:
X(ULONG64) = ((const struct symt_function_point*)type)->parent->address +
((const struct symt_function_point*)type)->offset;
break;
case SymTagThunk:
X(ULONG64) = ((const struct symt_thunk*)type)->address;
break;
default:
FIXME("Unsupported sym-tag %s for get-address\n",
symt_get_tag_str(type->tag));
return FALSE;
}
break;
case TI_GET_BASETYPE:
switch (type->tag)
{
case SymTagBaseType:
X(DWORD) = ((const struct symt_basic*)type)->bt;
break;
case SymTagEnum:
X(DWORD) = btInt;
break;
default:
return FALSE;
}
break;
case TI_GET_BITPOSITION:
if (type->tag != SymTagData ||
((const struct symt_data*)type)->kind != DataIsMember ||
((const struct symt_data*)type)->u.s.length == 0)
return FALSE;
X(DWORD) = ((const struct symt_data*)type)->u.s.offset & 7;
break;
case TI_GET_CHILDRENCOUNT:
switch (type->tag)
{
case SymTagUDT:
X(DWORD) = vector_length(&((const struct symt_udt*)type)->vchildren);
break;
case SymTagEnum:
X(DWORD) = vector_length(&((const struct symt_enum*)type)->vchildren);
break;
case SymTagFunctionType:
X(DWORD) = vector_length(&((const struct symt_function_signature*)type)->vchildren);
break;
case SymTagFunction:
X(DWORD) = vector_length(&((const struct symt_function*)type)->vchildren);
break;
case SymTagPointerType: /* MS does it that way */
case SymTagArrayType: /* MS does it that way */
case SymTagThunk: /* MS does it that way */
X(DWORD) = 0;
break;
default:
FIXME("Unsupported sym-tag %s for get-children-count\n",
symt_get_tag_str(type->tag));
/* fall through */
case SymTagData:
case SymTagPublicSymbol:
case SymTagBaseType:
return FALSE;
}
break;
case TI_GET_COUNT:
/* it seems that FunctionType also react to GET_COUNT (same value as
* GET_CHILDREN_COUNT ?, except for C++ methods, where it seems to
* also include 'this' (GET_CHILDREN_COUNT+1)
*/
if (type->tag != SymTagArrayType) return FALSE;
X(DWORD) = ((const struct symt_array*)type)->end -
((const struct symt_array*)type)->start + 1;
break;
case TI_GET_DATAKIND:
if (type->tag != SymTagData) return FALSE;
X(DWORD) = ((const struct symt_data*)type)->kind;
break;
case TI_GET_LENGTH:
switch (type->tag)
{
case SymTagBaseType:
X(DWORD) = ((const struct symt_basic*)type)->size;
break;
case SymTagFunction:
X(DWORD) = ((const struct symt_function*)type)->size;
break;
case SymTagPointerType:
X(DWORD) = sizeof(void*);
break;
case SymTagUDT:
X(DWORD) = ((const struct symt_udt*)type)->size;
break;
case SymTagEnum:
X(DWORD) = sizeof(int); /* FIXME: should be size of base-type of enum !!! */
break;
case SymTagData:
if (((const struct symt_data*)type)->kind != DataIsMember ||
!((const struct symt_data*)type)->u.s.length)
return FALSE;
X(DWORD) = ((const struct symt_data*)type)->u.s.length;
break;
case SymTagArrayType:
if (!symt_get_info(((const struct symt_array*)type)->basetype,
TI_GET_LENGTH, pInfo))
return FALSE;
X(DWORD) *= ((const struct symt_array*)type)->end -
((const struct symt_array*)type)->start + 1;
break;
case SymTagPublicSymbol:
X(DWORD) = ((const struct symt_public*)type)->size;
break;
case SymTagTypedef:
return symt_get_info(((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo);
break;
case SymTagThunk:
X(DWORD) = ((const struct symt_thunk*)type)->size;
break;
default:
FIXME("Unsupported sym-tag %s for get-length\n",
symt_get_tag_str(type->tag));
/* fall through */
case SymTagFunctionType:
return 0;
}
break;
case TI_GET_LEXICALPARENT:
switch (type->tag)
{
case SymTagBlock:
X(DWORD) = (DWORD)((const struct symt_block*)type)->container;
break;
case SymTagData:
X(DWORD) = (DWORD)((const struct symt_data*)type)->container;
break;
case SymTagFunction:
X(DWORD) = (DWORD)((const struct symt_function*)type)->container;
break;
case SymTagThunk:
X(DWORD) = (DWORD)((const struct symt_thunk*)type)->container;
break;
default:
FIXME("Unsupported sym-tag %s for get-lexical-parent\n",
symt_get_tag_str(type->tag));
return FALSE;
}
break;
case TI_GET_NESTED:
switch (type->tag)
{
case SymTagUDT:
case SymTagEnum:
X(DWORD) = 0;
break;
default:
return FALSE;
}
break;
case TI_GET_OFFSET:
switch (type->tag)
{
case SymTagData:
switch (((const struct symt_data*)type)->kind)
{
case DataIsParam:
case DataIsLocal:
case DataIsMember:
X(ULONG) = ((const struct symt_data*)type)->u.s.offset >> 3;
break;
default:
FIXME("Unknown kind (%u) for get-offset\n",
((const struct symt_data*)type)->kind);
return FALSE;
}
break;
default:
FIXME("Unsupported sym-tag %s for get-offset\n",
symt_get_tag_str(type->tag));
return FALSE;
}
break;
case TI_GET_SYMNAME:
{
const char* name = symt_get_name(type);
if (!name) return FALSE;
len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
X(WCHAR*) = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!X(WCHAR*)) return FALSE;
MultiByteToWideChar(CP_ACP, 0, name, -1, X(WCHAR*), len);
}
break;
case TI_GET_SYMTAG:
X(DWORD) = type->tag;
break;
case TI_GET_TYPE:
case TI_GET_TYPEID:
switch (type->tag)
{
/* hierarchical => hierarchical */
case SymTagArrayType:
X(DWORD) = (DWORD)((const struct symt_array*)type)->basetype;
break;
case SymTagPointerType:
X(DWORD) = (DWORD)((const struct symt_pointer*)type)->pointsto;
break;
case SymTagFunctionType:
X(DWORD) = (DWORD)((const struct symt_function_signature*)type)->rettype;
break;
case SymTagTypedef:
X(DWORD) = (DWORD)((const struct symt_typedef*)type)->type;
break;
/* lexical => hierarchical */
case SymTagData:
X(DWORD) = (DWORD)((const struct symt_data*)type)->type;
break;
case SymTagFunction:
X(DWORD) = (DWORD)((const struct symt_function*)type)->type;
break;
/* FIXME: should also work for enums and FunctionArgType */
default:
FIXME("Unsupported sym-tag %s for get-type\n",
symt_get_tag_str(type->tag));
case SymTagThunk:
return FALSE;
}
break;
case TI_GET_UDTKIND:
if (type->tag != SymTagUDT) return FALSE;
X(DWORD) = ((const struct symt_udt*)type)->kind;
break;
case TI_GET_VALUE:
if (type->tag != SymTagData || ((const struct symt_data*)type)->kind != DataIsConstant)
return FALSE;
X(VARIANT) = ((const struct symt_data*)type)->u.value;
break;
#undef X
case TI_GET_ADDRESSOFFSET:
case TI_GET_ARRAYINDEXTYPEID:
case TI_GET_CALLING_CONVENTION:
case TI_GET_CLASSPARENTID:
case TI_GET_SYMINDEX:
case TI_GET_THISADJUST:
case TI_GET_VIRTUALBASECLASS:
case TI_GET_VIRTUALBASEPOINTEROFFSET:
case TI_GET_VIRTUALTABLESHAPEID:
case TI_IS_EQUIV_TO:
FIXME("Unsupported GetInfo request (%u)\n", req);
return FALSE;
}
return TRUE;
}
/******************************************************************
* SymGetTypeInfo (DBGHELP.@)
*
*/
BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase,
ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType,
PVOID pInfo)
{
struct process* pcs = process_find_by_handle(hProcess);
struct module* module;
if (!pcs) return FALSE;
module = module_find_by_addr(pcs, ModBase, DMT_UNKNOWN);
if (!(module = module_get_debug(pcs, module)))
{
FIXME("Someone didn't properly set ModBase (%s)\n", wine_dbgstr_longlong(ModBase));
return FALSE;
}
return symt_get_info((struct symt*)TypeId, GetType, pInfo);
}
/******************************************************************
* SymGetTypeFromName (DBGHELP.@)
*
*/
BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll,
LPSTR Name, PSYMBOL_INFO Symbol)
{
struct process* pcs = process_find_by_handle(hProcess);
struct module* module;
struct symt* type;
if (!pcs) return FALSE;
module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
if (!module) return FALSE;
type = symt_find_type_by_name(module, SymTagNull, Name);
if (!type) return FALSE;
Symbol->TypeIndex = (DWORD)type;
return TRUE;
}