mirror of
https://github.com/reactos/reactos.git
synced 2025-03-30 17:10:22 +00:00
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:
parent
d057566f59
commit
1aea28360c
26 changed files with 12868 additions and 0 deletions
26
reactos/lib/dbghelp/.cvsignore
Normal file
26
reactos/lib/dbghelp/.cvsignore
Normal 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
|
409
reactos/lib/dbghelp/Makefile
Normal file
409
reactos/lib/dbghelp/Makefile
Normal 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:
|
28
reactos/lib/dbghelp/Makefile.in
Normal file
28
reactos/lib/dbghelp/Makefile.in
Normal 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:
|
21
reactos/lib/dbghelp/Makefile.ros-template
Normal file
21
reactos/lib/dbghelp/Makefile.ros-template
Normal 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
454
reactos/lib/dbghelp/coff.c
Normal 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;
|
||||
}
|
338
reactos/lib/dbghelp/dbghelp.c
Normal file
338
reactos/lib/dbghelp/dbghelp.c
Normal 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;
|
||||
}
|
1
reactos/lib/dbghelp/dbghelp.rc
Normal file
1
reactos/lib/dbghelp/dbghelp.rc
Normal file
|
@ -0,0 +1 @@
|
|||
#include "wine/wine_common_ver.rc"
|
99
reactos/lib/dbghelp/dbghelp.spec
Normal file
99
reactos/lib/dbghelp/dbghelp.spec
Normal 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
|
96
reactos/lib/dbghelp/dbghelp.spec.def
Normal file
96
reactos/lib/dbghelp/dbghelp.spec.def
Normal 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
|
74
reactos/lib/dbghelp/dbghelp.stubs.c
Normal file
74
reactos/lib/dbghelp/dbghelp.stubs.c
Normal 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"); }
|
448
reactos/lib/dbghelp/dbghelp_private.h
Normal file
448
reactos/lib/dbghelp/dbghelp_private.h
Normal 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);
|
1176
reactos/lib/dbghelp/elf_module.c
Normal file
1176
reactos/lib/dbghelp/elf_module.c
Normal file
File diff suppressed because it is too large
Load diff
61
reactos/lib/dbghelp/image.c
Normal file
61
reactos/lib/dbghelp/image.c
Normal 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;
|
||||
}
|
61
reactos/lib/dbghelp/memory.c
Normal file
61
reactos/lib/dbghelp/memory.c
Normal 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;
|
||||
}
|
266
reactos/lib/dbghelp/minidump.c
Normal file
266
reactos/lib/dbghelp/minidump.c
Normal 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;
|
||||
}
|
505
reactos/lib/dbghelp/module.c
Normal file
505
reactos/lib/dbghelp/module.c
Normal 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
2332
reactos/lib/dbghelp/msc.c
Normal file
File diff suppressed because it is too large
Load diff
1424
reactos/lib/dbghelp/mscvpdb.h
Normal file
1424
reactos/lib/dbghelp/mscvpdb.h
Normal file
File diff suppressed because it is too large
Load diff
272
reactos/lib/dbghelp/path.c
Normal file
272
reactos/lib/dbghelp/path.c
Normal 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;
|
||||
}
|
424
reactos/lib/dbghelp/pe_module.c
Normal file
424
reactos/lib/dbghelp/pe_module.c
Normal 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;
|
||||
}
|
138
reactos/lib/dbghelp/source.c
Normal file
138
reactos/lib/dbghelp/source.c
Normal 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
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
388
reactos/lib/dbghelp/stack.c
Normal 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;
|
||||
}
|
335
reactos/lib/dbghelp/storage.c
Normal file
335
reactos/lib/dbghelp/storage.c
Normal 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
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
784
reactos/lib/dbghelp/type.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue