update
This commit is contained in:
@@ -93,17 +93,17 @@ bool idaapi run( size_t /*arg*/ )
|
||||
return true;
|
||||
}
|
||||
|
||||
int idaapi init( void )
|
||||
plugmod_t* idaapi init( void )
|
||||
{
|
||||
Settings.Init( );
|
||||
Settings.Load( "sigmaker.ini" );
|
||||
|
||||
return PLUGIN_OK;
|
||||
return PLUGIN_KEEP;
|
||||
}
|
||||
|
||||
plugin_t PLUGIN = {
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_KEEP,
|
||||
0,// PLUGIN_KEEP,
|
||||
init,
|
||||
NULL,
|
||||
run,
|
||||
|
||||
@@ -22,34 +22,34 @@
|
||||
<ProjectGuid>{60916877-60AB-4565-93BC-2D6097976D86}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>SigMaker</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug64|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release64|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
@@ -90,7 +90,7 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SIGMAKER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(IDADIR)\idasdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -114,7 +114,7 @@
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;__EA64__;SIGMAKER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(IDADIR)\idasdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -139,7 +139,7 @@
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<AdditionalIncludeDirectories>$(IDADIR)\idasdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<OpenMPSupport>false</OpenMPSupport>
|
||||
</ClCompile>
|
||||
@@ -179,7 +179,7 @@
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<OpenMPSupport>false</OpenMPSupport>
|
||||
<AdditionalIncludeDirectories>$(IDADIR)\idasdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
@@ -191,16 +191,18 @@
|
||||
<AdditionalOptions>/EXPORT:PLUGIN %(AdditionalOptions)</AdditionalOptions>
|
||||
<DataExecutionPrevention>false</DataExecutionPrevention>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>$(IDADIR)\idasdk\lib\x64_win_vc_64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)idasdk75\lib\x64_win_vc_64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<ProjectReference>
|
||||
<LinkLibraryDependencies>false</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
<PostBuildEvent>
|
||||
<Command>copy "$(TargetDir)$(TargetName)$(TargetExt)" "$(IDADIR)\plugins\sigmaker64.dll"</Command>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
<PostBuildEvent>
|
||||
<Message>copy "$(TargetDir)$(TargetName)$(TargetExt)" "$(IDADIR)\plugins\sigmaker64.dll"</Message>
|
||||
<Message>
|
||||
</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
823
idasdk75/allmake.mak
Normal file
823
idasdk75/allmake.mak
Normal file
@@ -0,0 +1,823 @@
|
||||
#
|
||||
# Common part of make files for IDA.
|
||||
#
|
||||
|
||||
# find directory of allmake.mak:
|
||||
IDA:=$(dir $(lastword $(MAKEFILE_LIST)))
|
||||
|
||||
# define the version number we are building
|
||||
IDAVER_MAJOR:=7
|
||||
IDAVER_MINOR:=5
|
||||
# 750
|
||||
IDAVERDECIMAL:=$(IDAVER_MAJOR)$(IDAVER_MINOR)0
|
||||
# 7.5
|
||||
IDAVERDOTTED:=$(IDAVER_MAJOR).$(IDAVER_MINOR)
|
||||
|
||||
# only 32-bit cygwin make is support on Windows
|
||||
ifeq ($(OS),Windows_NT)
|
||||
ifneq ($(MAKE_HOST),i686-pc-cygwin)
|
||||
$(error Only 32-bit cygwin make is supported on Windows. Make sure you are not using 64-bit cygwin, msys, msys2, or any other version of win32 make)
|
||||
endif
|
||||
endif
|
||||
|
||||
# if no targets are defined, default to host OS
|
||||
ifeq ($(or $(__ANDROID__),$(__ANDROID_X86__),$(__ARMLINUX__),$(__LINUX__),$(__MAC__),$(__NT__)),)
|
||||
ifeq ($(OS),Windows_NT)
|
||||
__NT__=1
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
__LINUX__=1
|
||||
endif
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
__MAC__=1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# only one build target may be defined
|
||||
ifneq ($(__ANDROID__)$(__ANDROID_X86__)$(__ARMLINUX__)$(__LINUX__)$(__MAC__)$(__NT__),1)
|
||||
$(error Only one build target may be defined (__ANDROID__, __ANDROID_X86__, __ARMLINUX__, __LINUX__, __MAC__, or __NT__))
|
||||
endif
|
||||
|
||||
# detect build configuration
|
||||
# Note: will set one of M, MM, MMH, M32, MO, MMO, MMHO, MO32, MSO, MMSO, or MSO32
|
||||
BUILD_CONFIG-1 := M
|
||||
BUILD_CONFIG-$(__EA64__) += M
|
||||
BUILD_CONFIG-$(USE_STATIC_RUNTIME) += S
|
||||
BUILD_CONFIG-$(IDAHOME) += H
|
||||
BUILD_CONFIG-$(NDEBUG) += O
|
||||
BUILD_CONFIG-$(__X86__) += 32
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
comma := ,
|
||||
BUILD_CONFIG := $(subst $(space),,$(BUILD_CONFIG-1))
|
||||
$(BUILD_CONFIG) := 1
|
||||
|
||||
# definition of a single \n character (empty lines are important!)
|
||||
define newline
|
||||
|
||||
|
||||
endef
|
||||
|
||||
# disable x86 ida64 builds
|
||||
ifeq ($(or $(MM32),$(MMO32),$(MMSO32)),1)
|
||||
$(error x86 ida64 builds have been disabled)
|
||||
endif
|
||||
|
||||
ifdef __ARM__
|
||||
PROCDEF = __ARM__
|
||||
TARGET_PROCESSOR_NAME=arm
|
||||
else ifndef __X86__
|
||||
ARCH_FLAGS = -m64
|
||||
TARGET_PROCESSOR_NAME=x64
|
||||
else
|
||||
ARCH_FLAGS = -m32
|
||||
TARGET_PROCESSOR_NAME=x86
|
||||
endif
|
||||
|
||||
# define some variables to simplify build system
|
||||
ifndef __X86__
|
||||
__X64__ = 1
|
||||
ifndef __EA64__
|
||||
__X32__ = 1
|
||||
endif
|
||||
endif
|
||||
ifndef __NT__
|
||||
__UNIX__ = 1
|
||||
endif
|
||||
|
||||
ifndef IDAHOME
|
||||
IDAADV = 1
|
||||
endif
|
||||
|
||||
# define SYSNAME
|
||||
SYSNAME-$(__LINUX__) = linux
|
||||
SYSNAME-$(__MAC__) = mac
|
||||
SYSNAME-$(__NT__) = win
|
||||
SYSNAME = $(SYSNAME-1)
|
||||
|
||||
# path functions (depending on host OS)
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# define: convert unix path to dos path by replacing slashes by backslashes
|
||||
dospath=$(subst /,\\,$(1))
|
||||
else
|
||||
# define: dospath does not do anything in unix
|
||||
dospath=$(1)
|
||||
endif
|
||||
# define: return 1 if path exists, 0 otherwise
|
||||
ls=$(if $(wildcard $(1)),1,0)
|
||||
|
||||
# define: logical negation
|
||||
not = $(if $(1),,1)
|
||||
|
||||
# define: greater or equal
|
||||
gte = $(if $(filter-out $(1),$(word 2,$(sort $(1) $(2)))),,1)
|
||||
|
||||
include $(IDA)defaults.mk
|
||||
|
||||
#############################################################################
|
||||
ifdef __NT__
|
||||
COMPILER_NAME=vc
|
||||
|
||||
# Visual C++ Toolchain and Windows SDK paths
|
||||
# Note: see comments in defaults.mk for more information about these
|
||||
# variables.
|
||||
|
||||
# This function searches for a specified path, converts it to a 8.3
|
||||
# path with forward slashes as separator, and exports it as an
|
||||
# environment variable. This way, subcalls to make do not need to
|
||||
# call $(shell) again.
|
||||
define require_path
|
||||
$$(if $(strip $$($(1))),,$$(eval $(1):=$$(subst \,/,$$(shell cygpath -d $(2) 2>/dev/null))))
|
||||
$$(if $(strip $$($(1))),,$$(error Could not find $(3) in $(2)$$(newline)*** See defaults.mk and "Visual C++ Toolchain and Windows SDK paths" in allmake.mak))
|
||||
$$(eval export $(1))
|
||||
endef
|
||||
|
||||
# This function fixes variables imported from defaults.mk/vcvars.bat
|
||||
# by ensuring that they are surrounded by quotes and by removing the
|
||||
# trailing backslash.
|
||||
fix_var=$(1):='$$(patsubst %\,%,$$(patsubst '%,%,$$(patsubst %',%,$$(patsubst "%,%,$$(patsubst %",%,$$($(1)))))))'
|
||||
|
||||
# Note: these cfg files are created in makeenv_vc.mak
|
||||
ifdef __XPCOMPAT__
|
||||
-include $(IDA)vs17paths_xp.cfg
|
||||
else
|
||||
-include $(IDA)vs17paths.cfg
|
||||
endif
|
||||
|
||||
# Visual C++ 2017 Install Directory
|
||||
ifndef MSVC_ROOT
|
||||
ifneq (,$(findstring Microsoft$(space)Visual$(space)Studio$(space),$(VCINSTALLDIR)))
|
||||
ifeq (,$(findstring 2017,$(VCINSTALLDIR)))
|
||||
$(error Please check your system environment variable VCInstallDir [$(VCINSTALLDIR)].$(newline)It seems to be pointing to an old version of Visual Studio (and not version 2017).$(newline)You may override it in defaults.mk.)
|
||||
endif
|
||||
endif
|
||||
$(eval $(call fix_var,VCINSTALLDIR))
|
||||
$(eval $(call require_path,MSVC_ROOT,$(VCINSTALLDIR),Visual C++ 2017 Install Directory))
|
||||
export MSVC_ROOT
|
||||
endif
|
||||
|
||||
# Visual C++ 2017 Tools Version
|
||||
ifndef MSVC_TOOLSVER
|
||||
ifndef VCToolsVersion
|
||||
# Try to obtain version from Microsoft.VCToolsVersion.default.txt
|
||||
MSVC_TOOLSVER_PATH = $(MSVC_ROOT)/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt
|
||||
VCToolsVersion := $(shell cat $(MSVC_TOOLSVER_PATH) 2> /dev/null)
|
||||
ifeq (,$(VCToolsVersion))
|
||||
# If that failed, try to detect latest version from the directory names
|
||||
VCToolsVersion := $(notdir $(lastword $(sort $(wildcard $(MSVC_ROOT)/Tools/MSVC/14.*))))
|
||||
endif
|
||||
ifeq (,$(VCToolsVersion))
|
||||
$(error Could not find Visual C++ 2017 Tools Version in $(MSVC_TOOLSVER_PATH))
|
||||
endif
|
||||
endif
|
||||
$(eval $(call fix_var,VCToolsVersion))
|
||||
MSVC_TOOLSVER := $(VCToolsVersion)
|
||||
export MSVC_TOOLSVER
|
||||
endif
|
||||
|
||||
# Final Visual C++ 2017 Tools path
|
||||
$(eval $(call require_path,MSVC_PATH,$(MSVC_ROOT)/Tools/MSVC/$(MSVC_TOOLSVER),Visual C++ 2017 Tools))
|
||||
|
||||
MSVC_BIN-X86 ?= $(MSVC_PATH)/bin/HostX86/x86
|
||||
MSVC_BIN-X64 ?= $(MSVC_PATH)/bin/HostX64/x64
|
||||
ifdef __X86__
|
||||
MSVC_BIN ?= $(MSVC_BIN-X86)
|
||||
else
|
||||
MSVC_BIN ?= $(MSVC_BIN-X64)
|
||||
endif
|
||||
MSVC_INCLUDE ?= $(MSVC_PATH)/Include
|
||||
|
||||
# Windows SDK Install Directory
|
||||
ifndef WSDK_PATH
|
||||
$(eval $(call fix_var,WindowsSdkDir))
|
||||
$(eval $(call require_path,WSDK_PATH,$(WindowsSdkDir),Windows SDK Install Directory))
|
||||
export WSDK_PATH
|
||||
endif
|
||||
|
||||
# Windows SDK Version
|
||||
ifndef WSDK_VER
|
||||
ifndef WindowsSDKVersion
|
||||
# Detect the latest version of the Windows SDK
|
||||
WSDK_VER_PATH = $(WSDK_PATH)/Include/10.*
|
||||
WindowsSDKVersion := $(notdir $(lastword $(sort $(wildcard $(WSDK_VER_PATH)))))
|
||||
ifeq (,$(WindowsSDKVersion))
|
||||
$(error Could not find Windows SDK Version in $(WSDK_VER_PATH))
|
||||
endif
|
||||
endif
|
||||
$(eval $(call fix_var,WindowsSDKVersion))
|
||||
WSDK_VER := $(WindowsSDKVersion)
|
||||
export WSDK_VER
|
||||
endif
|
||||
|
||||
# Windows SDK Include/Lib paths
|
||||
INCLUDE_UCRT_PATH ?= $(WSDK_PATH)/Include/$(WSDK_VER)/ucrt
|
||||
LIB_UCRT_PATH ?= $(WSDK_PATH)/Lib/$(WSDK_VER)/ucrt
|
||||
$(eval $(call require_path,INCLUDE_UCRT,$(INCLUDE_UCRT_PATH),Windows SDK Include/ucrt))
|
||||
$(eval $(call require_path,LIB_UCRT,$(LIB_UCRT_PATH),Windows SDK Lib/ucrt))
|
||||
|
||||
ifdef __XPCOMPAT__
|
||||
$(eval $(call require_path,INCLUDE_MSSDK71,$(MSSDK71_PATH)/Include,Microsoft SDK Include))
|
||||
$(eval $(call require_path,LIB_MSSDK71,$(MSSDK71_PATH)/Lib,Microsoft SDK Lib))
|
||||
$(eval $(call require_path,SDK_BIN,$(MSSDK71_PATH)/Bin,Microsoft SDK Bin))
|
||||
else
|
||||
INCLUDE_SHARED_PATH ?= $(WSDK_PATH)/Include/$(WSDK_VER)/shared
|
||||
INCLUDE_UM_PATH ?= $(WSDK_PATH)/Include/$(WSDK_VER)/um
|
||||
LIB_UM_PATH ?= $(WSDK_PATH)/Lib/$(WSDK_VER)/um
|
||||
SDK_BIN_PATH ?= $(WSDK_PATH)/Bin/$(WSDK_VER)/
|
||||
|
||||
$(eval $(call require_path,INCLUDE_SHARED,$(INCLUDE_SHARED_PATH),Windows SDK Include/shared))
|
||||
$(eval $(call require_path,INCLUDE_UM,$(INCLUDE_UM_PATH),Windows SDK Include/um))
|
||||
$(eval $(call require_path,LIB_UM,$(LIB_UM_PATH),Windows SDK Lib/um))
|
||||
$(eval $(call require_path,SDK_BIN,$(SDK_BIN_PATH),Windows SDK Bin))
|
||||
endif
|
||||
|
||||
# Export INCLUDE as an environment variable so it may be used by cl.
|
||||
ifndef INCLUDE
|
||||
ifdef __XPCOMPAT__
|
||||
INCLUDE = $(MSVC_INCLUDE);$(INCLUDE_UCRT);$(INCLUDE_MSSDK71)
|
||||
else
|
||||
INCLUDE = $(MSVC_INCLUDE);$(INCLUDE_UCRT);$(INCLUDE_UM);$(INCLUDE_SHARED)
|
||||
endif
|
||||
export INCLUDE
|
||||
endif
|
||||
|
||||
# Export LIB as an environment variable so it may be used by cl/link.
|
||||
ifndef LIB
|
||||
ifdef __XPCOMPAT__
|
||||
ifdef __X86__
|
||||
LIB = $(MSVC_PATH)/lib/x86;$(LIB_UCRT)/x86;$(LIB_MSSDK71)
|
||||
else
|
||||
LIB = $(MSVC_PATH)/lib/x64;$(LIB_UCRT)/x64;$(LIB_MSSDK71)/x64
|
||||
endif
|
||||
else
|
||||
ifdef __X86__
|
||||
LIB = $(MSVC_PATH)/lib/x86;$(LIB_UCRT)/x86;$(LIB_UM)/x86
|
||||
else
|
||||
LIB = $(MSVC_PATH)/lib/x64;$(LIB_UCRT)/x64;$(LIB_UM)/x64
|
||||
endif
|
||||
endif
|
||||
export LIB
|
||||
endif
|
||||
|
||||
# If a Visual Studio Command Prompt is used, make sure the target
|
||||
# architecture is correct.
|
||||
ifdef VSCMD_ARG_TGT_ARCH
|
||||
ifneq ($(VSCMD_ARG_TGT_ARCH),$(TARGET_PROCESSOR_NAME))
|
||||
ifdef __X86__
|
||||
EXPECTED_ARCH = x86
|
||||
else
|
||||
EXPECTED_ARCH = x64
|
||||
endif
|
||||
LOWERCASE_BUILD_CONFIG := $(subst M,m,$(subst S,s,$(subst O,o,$(BUILD_CONFIG))))
|
||||
$(error Please use the correct Visual Studio Command Prompt for the target architecture$(newline)*** The target architecture for '$(LOWERCASE_BUILD_CONFIG)' is $(EXPECTED_ARCH), and the architecture for the current Visual Studio Command Prompt is $(VSCMD_ARG_TGT_ARCH)))
|
||||
endif
|
||||
endif
|
||||
#############################################################################
|
||||
else ifdef __LINUX__
|
||||
COMPILER_NAME=gcc
|
||||
PTHR_SWITCH=-pthread
|
||||
STDLIBS += -lrt -lpthread -lc
|
||||
#############################################################################
|
||||
else ifdef __MAC__
|
||||
COMPILER_NAME=clang
|
||||
STDLIBS += -lpthread -liconv
|
||||
ARCH_FLAGS-$(__X64__) = -arch x86_64
|
||||
ARCH_FLAGS-$(__X86__) = -arch i386
|
||||
ARCH_FLAGS += $(ARCH_FLAGS-1)
|
||||
# The following value is defined in defaults.mk.
|
||||
ARCH_FLAGS += -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET)
|
||||
ifndef MACSDK
|
||||
MACSDK := $(shell /usr/bin/xcrun --sdk macosx --show-sdk-path)
|
||||
ifeq ($(MACSDK),)
|
||||
$(error Could not find MacOSX SDK)
|
||||
endif
|
||||
export MACSDK
|
||||
endif
|
||||
ARCH_FLAGS += -isysroot $(MACSDK)
|
||||
endif
|
||||
|
||||
#############################################################################
|
||||
# toolchain-specific variables
|
||||
|
||||
ifneq (,$(filter $(COMPILER_NAME),gcc clang))
|
||||
# file extensions
|
||||
A = .a
|
||||
B = $(SUFF64)
|
||||
O = .o
|
||||
II = .i
|
||||
# toolchain output switches
|
||||
OBJSW = -o # with space
|
||||
OUTAR =
|
||||
OUTII = -o # with space
|
||||
OUTSW = -o # with space
|
||||
ifdef __MAC__
|
||||
OUTMAP = -Wl,-map,
|
||||
else
|
||||
OUTMAP = -Wl,-Map,
|
||||
endif
|
||||
# misc switches
|
||||
AROPT = rc
|
||||
CPPONLY = -E
|
||||
FORCEC = -xc
|
||||
NORTTI = -fno-rtti
|
||||
ifdef __MAC__
|
||||
OUTDLL = -dynamiclib
|
||||
else
|
||||
OUTDLL = --shared
|
||||
endif
|
||||
# utilities
|
||||
CCACHE-$(USE_CCACHE) = ccache
|
||||
ifeq ($(COMPILER_NAME),clang)
|
||||
_CC = clang
|
||||
_CXX = clang++
|
||||
else
|
||||
_CC = gcc
|
||||
_CXX = g++
|
||||
ifdef USE_GOLD
|
||||
GOLD = -fuse-ld=gold
|
||||
endif
|
||||
endif
|
||||
AR = $(CROSS_PREFIX)ar$(HOST_EXE) $(AROPT)
|
||||
CC = $(CCACHE-1) $(CROSS_PREFIX)$(_CC)$(HOST_EXE) $(ARCH_FLAGS)
|
||||
CCL = $(CROSS_PREFIX)$(_CXX)$(HOST_EXE) $(ARCH_FLAGS) $(GOLD)
|
||||
CXX = $(CCACHE-1) $(CROSS_PREFIX)$(_CXX)$(HOST_EXE) $(ARCH_FLAGS)
|
||||
else ifeq ($(COMPILER_NAME),vc)
|
||||
# file extensions
|
||||
A = .lib
|
||||
B = $(SUFF64).exe
|
||||
O = .obj
|
||||
II = .i
|
||||
# toolchain output switches
|
||||
OBJSW = /Fo
|
||||
OUTAR = /OUT:
|
||||
OUTII = /Fi
|
||||
OUTSW = /OUT:
|
||||
OUTMAP = /map:
|
||||
# misc switches
|
||||
CPPONLY = /P
|
||||
FORCEC = /TC
|
||||
NOLOGO = /nologo
|
||||
NORTTI = /GR-
|
||||
OUTDLL = /DLL
|
||||
# utilities
|
||||
AR = $(MSVC_BIN)/lib.exe $(NOLOGO)
|
||||
CC = $(MSVC_BIN)/cl.exe $(NOLOGO)
|
||||
CCL = $(MSVC_BIN)/link.exe $(NOLOGO)
|
||||
CXX = $(CC)
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
# target-specific cflags/ldflags
|
||||
ifneq (,$(filter $(COMPILER_NAME),gcc clang))
|
||||
|
||||
# system cflags
|
||||
CC_DEFS += $(PROCDEF)
|
||||
ifdef __MAC__
|
||||
CC_DEFS += __MAC__
|
||||
else
|
||||
CC_DEFS += __LINUX__
|
||||
endif
|
||||
|
||||
# pic-related flags
|
||||
# Note: this variable may be overridden in other parts of the build
|
||||
PIC = -fPIC
|
||||
|
||||
ifdef __MAC__
|
||||
LDPIE = $(PIC) -Wl,-pie
|
||||
else
|
||||
LDPIE = $(PIC) -pie
|
||||
endif
|
||||
|
||||
# common cflags
|
||||
CC_DEFS += $(DEF64)
|
||||
CC_DEFS += $(DEFX86)
|
||||
|
||||
CC_F += $(PIC)
|
||||
CC_F += -fdiagnostics-show-option
|
||||
CC_F += -fno-strict-aliasing
|
||||
CC_F += -fvisibility=hidden
|
||||
CC_F += -fwrapv
|
||||
|
||||
CC_INCP += $(I)
|
||||
|
||||
CC_W += -Wall
|
||||
CC_W += -Wextra
|
||||
CC_W += -Wformat=2
|
||||
CC_W += -Werror=format-security
|
||||
CC_W += -Werror=format-nonliteral
|
||||
CC_W += -Wshadow
|
||||
CC_W += -Wunused
|
||||
|
||||
CC_WNO += -Wno-format-y2k
|
||||
CC_WNO += -Wno-missing-field-initializers
|
||||
CC_WNO += -Wno-sign-compare
|
||||
|
||||
CC_X += -g
|
||||
CC_X += -pipe
|
||||
|
||||
# enable c++11
|
||||
CXXSTD = -std=c++11
|
||||
|
||||
CXX_F += -fvisibility-inlines-hidden
|
||||
CXX_WNO += -Wno-invalid-offsetof
|
||||
|
||||
# system-specific cflags
|
||||
ifeq ($(COMPILER_NAME),clang) # mac/android
|
||||
# 'cc -dumpversion' always reports 4.2.1 for clang
|
||||
# https://stackoverflow.com/questions/12893731/why-does-clang-dumpversion-report-4-2-1
|
||||
|
||||
# clang is extra picky - need to add some warning supressions
|
||||
# must eventually get rid of most of these
|
||||
CC_WNO += -Wno-char-subscripts
|
||||
CC_WNO += -Wno-dynamic-class-memaccess
|
||||
CC_WNO += -Wno-int-to-pointer-cast
|
||||
CC_WNO += -Wno-invalid-source-encoding
|
||||
CC_WNO += -Wno-logical-not-parentheses
|
||||
CC_WNO += -Wno-logical-op-parentheses
|
||||
CC_WNO += -Wno-null-conversion
|
||||
CC_WNO += -Wno-nullability-completeness
|
||||
CC_WNO += -Wno-parentheses-equality
|
||||
CC_WNO += -Wno-self-assign
|
||||
CC_WNO += -Wno-unused-const-variable
|
||||
CC_WNO += -Wno-unused-function
|
||||
CC_WNO += -Wno-unused-private-field
|
||||
CC_WNO += -Wno-unused-variable
|
||||
CC_WNO += -Wno-varargs
|
||||
|
||||
CC_F += -fno-caret-diagnostics
|
||||
else # (arm)linux
|
||||
|
||||
# get gcc version
|
||||
ifndef _GCC_VERSION
|
||||
_GCC_VERSION:=$(wordlist 1,2,$(subst ., ,$(shell $(CC) -dumpversion)))
|
||||
export _GCC_VERSION
|
||||
endif
|
||||
GCC_VERSION=$(firstword $(_GCC_VERSION)).$(lastword $(_GCC_VERSION))
|
||||
|
||||
CC_WNO += -Wno-unused-local-typedefs
|
||||
CC_F += -fno-diagnostics-show-caret
|
||||
|
||||
CC_DEFS-$(call gte,$(GCC_VERSION),5.0) += _GLIBCXX_USE_CXX11_ABI=0
|
||||
CC_W-$(call gte,$(GCC_VERSION),7.0) += -Wimplicit-fallthrough=0
|
||||
CXX_WNO-$(call gte,$(GCC_VERSION),8.0) += -Wno-class-memaccess
|
||||
|
||||
# suppress warning about ABI change in GCC 4.4
|
||||
CC_WNO-$(__ARMLINUX__) += -Wno-psabi
|
||||
endif
|
||||
|
||||
# optimization cflags
|
||||
ifdef NDEBUG
|
||||
CC_F += -fdata-sections
|
||||
CC_F += -ffunction-sections
|
||||
ifndef __ASAN__
|
||||
CC_F += -fomit-frame-pointer
|
||||
endif
|
||||
# stack protector
|
||||
ifdef __TARGET_MAC_HOST_LINUX__
|
||||
# disable stack protector for our osxcross toolchain (we check
|
||||
# against __TARGET_MAC_HOST_LINUX__ since it is hard to check
|
||||
# for version number in clang).
|
||||
else ifeq ($(call gte,$(GCC_VERSION),4.9),1)
|
||||
CC_F += -fstack-protector-strong
|
||||
else
|
||||
CC_F += -fstack-protector
|
||||
endif
|
||||
CC_DEFS += NDEBUG
|
||||
CC_DEFS += _FORTIFY_SOURCE=2
|
||||
else
|
||||
CC_DEFS += _DEBUG
|
||||
endif
|
||||
|
||||
# system-specific ldflags
|
||||
ifdef __LINUX__
|
||||
LDFLAGS += -Wl,--build-id
|
||||
LDFLAGS += -Wl,--gc-sections
|
||||
LDFLAGS += -Wl,--warn-shared-textrel
|
||||
|
||||
NO_UNDEFS = -Wl,--no-undefined
|
||||
DLL_W += $(NO_UNDEFS)
|
||||
else ifdef __MAC__
|
||||
LDFLAGS += -Wl,-dead_strip
|
||||
|
||||
ifndef __TARGET_MAC_HOST_LINUX__
|
||||
DLL_X += -compatibility_version 1.0
|
||||
DLL_X += -current_version 1.0
|
||||
DLL_X += -single_module
|
||||
endif
|
||||
endif
|
||||
|
||||
# common linker/compiler flags
|
||||
ifdef NDEBUG
|
||||
CCOPT += -O2
|
||||
ifdef __LINUX__
|
||||
LDOPT += -Wl,-O1
|
||||
endif
|
||||
endif
|
||||
|
||||
# AddressSanitizer flags
|
||||
ifdef __ASAN__
|
||||
CC_DEFS += __ASAN__
|
||||
CC_F += -fno-omit-frame-pointer
|
||||
CC_F += -fsanitize=address
|
||||
LDFLAGS += -fsanitize=address
|
||||
export LSAN_OPTIONS=suppressions=$(IDA)etc/bin/known_leaks.txt:detect_leaks=0
|
||||
endif
|
||||
|
||||
# final compiler flags
|
||||
CC_F += $(CC_F-1)
|
||||
CC_W += $(CC_W-1)
|
||||
CC_WNO += $(CC_WNO-1)
|
||||
CXX_WNO += $(CXX_WNO-1)
|
||||
CC_DEFS += $(CC_DEFS-1)
|
||||
CC_INCP += $(CC_INCP-1)
|
||||
CC_D += $(addprefix -D,$(CC_DEFS))
|
||||
CC_I += $(addprefix -I,$(CC_INCP))
|
||||
|
||||
# the -Wno-* flags must come after the -W enabling flags
|
||||
WARNS = $(sort $(CC_W)) $(sort $(CC_WNO))
|
||||
|
||||
CFLAGS += $(sort $(CC_X))
|
||||
CFLAGS += $(CCOPT)
|
||||
CFLAGS += $(sort $(CC_I))
|
||||
CFLAGS += $(sort $(CC_D))
|
||||
CFLAGS += $(sort $(CC_F))
|
||||
CFLAGS += $(WARNS)
|
||||
CFLAGS += $(PTHR_SWITCH)
|
||||
|
||||
# for warning suppression, override the WARNS variable with NOWARNS:
|
||||
# $(TARGET): WARNS = $(NOWARNS)
|
||||
NOWARNS = -w
|
||||
|
||||
# dll linker flags
|
||||
DLLFLAGS += $(DLL_W) $(DLL_X)
|
||||
|
||||
else ifeq ($(COMPILER_NAME),vc)
|
||||
# for warning suppression, override the WARNS variable with NOWARNS:
|
||||
# $(TARGET): WARNS = $(NOWARNS)
|
||||
NOWARNS = -w -wd4702 -wd4738
|
||||
|
||||
# optimization ldflags
|
||||
LDOPT += /DEBUG
|
||||
ifdef NDEBUG
|
||||
LDOPT += /INCREMENTAL:NO /OPT:ICF /OPT:REF
|
||||
endif
|
||||
|
||||
# set c runtime to use
|
||||
ifdef NDEBUG
|
||||
ifdef USE_STATIC_RUNTIME
|
||||
RUNTIME_LIBSW = /MT
|
||||
else
|
||||
RUNTIME_LIBSW = /MD
|
||||
endif
|
||||
else
|
||||
ifdef USE_STATIC_RUNTIME
|
||||
RUNTIME_LIBSW = /MTd
|
||||
else
|
||||
RUNTIME_LIBSW = /MDd
|
||||
endif
|
||||
endif
|
||||
|
||||
# PDB options
|
||||
PDBFLAGS = /PDB:$(PDBDIR)/
|
||||
ifdef NDEBUG
|
||||
PDBFLAGS += /PDBALTPATH:%_PDB%
|
||||
endif
|
||||
# Generate debug info (old style)
|
||||
PDBFORMAT = /Z7
|
||||
|
||||
# final compiler flags
|
||||
CC_DEFS += $(DEF64)
|
||||
CC_DEFS += $(DEFX86)
|
||||
CC_DEFS += $(CC_DEFS-1)
|
||||
CC_INCP += $(CC_INCP-1)
|
||||
CC_D += $(addprefix -D,$(CC_DEFS))
|
||||
CC_I += $(addprefix -I,$(CC_INCP))
|
||||
|
||||
CFGFILE = @$(IDA)$(SYSDIR).cfg
|
||||
CFLAGS += $(CFGFILE)
|
||||
CFLAGS += $(RUNTIME_LIBSW)
|
||||
CFLAGS += $(PDBFORMAT)
|
||||
CFLAGS += /Brepro
|
||||
CFLAGS += $(sort $(CC_I))
|
||||
CFLAGS += $(sort $(CC_D))
|
||||
CFLAGS += $(sort $(CC_F))
|
||||
CFLAGS += $(WARNS)
|
||||
|
||||
# final linker flags
|
||||
LDFLAGS += /Brepro
|
||||
LDFLAGS += $(PDBFLAGS)
|
||||
LDFLAGS += /ERRORREPORT:QUEUE
|
||||
ifdef __X86__
|
||||
LDFLAGS += /LARGEADDRESSAWARE
|
||||
endif
|
||||
|
||||
ifdef __XPCOMPAT__
|
||||
XPSUBSYS-$(__X64__) = /SUBSYSTEM:CONSOLE,5.02
|
||||
XPSUBSYS-$(__X86__) = /SUBSYSTEM:CONSOLE,5.01
|
||||
LDFLAGS += $(XPSUBSYS-1)
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
# to enable obsolete functions, disable the NO_OBSOLETE_FUNCS variable:
|
||||
# $(TARGET): NO_OBSOLETE_FUNCS =
|
||||
NO_OBSOLETE_FUNCS = NO_OBSOLETE_FUNCS
|
||||
CC_DEFS += $(NO_OBSOLETE_FUNCS)
|
||||
|
||||
CXXFLAGS += $(CXXSTD)
|
||||
CXXFLAGS += $(CFLAGS)
|
||||
CXXFLAGS += $(sort $(CXX_F))
|
||||
CXXFLAGS += $(sort $(CXX_WNO))
|
||||
|
||||
LDFLAGS += $(LDOPT)
|
||||
|
||||
#############################################################################
|
||||
ifdef __X86__
|
||||
DEFX86 = __X86__
|
||||
endif
|
||||
|
||||
ifdef __EA64__
|
||||
SUFF64=64
|
||||
ADRSIZE=64
|
||||
DEF64 = __EA64__
|
||||
else
|
||||
ADRSIZE=32
|
||||
endif
|
||||
|
||||
ifdef NDEBUG
|
||||
OPTSUF=_opt
|
||||
endif
|
||||
|
||||
ifdef IDAHOME
|
||||
EXTRASUF=_home
|
||||
IDAHOME_PROCESSORS=pc arm ppc mips mc68k
|
||||
else
|
||||
ifdef USE_STATIC_RUNTIME
|
||||
EXTRASUF=_s
|
||||
endif
|
||||
endif
|
||||
|
||||
#############################################################################
|
||||
SYSDIR=$(TARGET_PROCESSOR_NAME)_$(SYSNAME)_$(COMPILER_NAME)_$(ADRSIZE)$(OPTSUF)$(EXTRASUF)
|
||||
# libraries directory
|
||||
LIBDIR=$(IDA)lib/$(TARGET_PROCESSOR_NAME)_$(SYSNAME)_$(COMPILER_NAME)_$(ADRSIZE)$(EXTRASUF)
|
||||
# object files directory (using ?= to allow overriding)
|
||||
OBJDIR?=obj/$(SYSDIR)
|
||||
# PDB files directory
|
||||
PDBDIR=$(IDA)pdb/$(TARGET_PROCESSOR_NAME)_$(SYSNAME)_$(COMPILER_NAME)_$(ADRSIZE)$(EXTRASUF)
|
||||
# output directory for target platform
|
||||
R=$(IDA)bin/
|
||||
# input directory with existing build utilities
|
||||
RS=$(IDA)bin/
|
||||
# _ida.hlp placed in main tool directory
|
||||
HI=$(RS)
|
||||
# help source
|
||||
HS=.hls
|
||||
# help headers
|
||||
HH=.hhp
|
||||
# include,help and other directories are common for all platforms and compilers:
|
||||
I =$(IDA)include/
|
||||
C =$(R)cfg/
|
||||
RI=$(R)idc/
|
||||
F=$(OBJDIR)/
|
||||
L=$(LIBDIR)/
|
||||
|
||||
DUMB=$(L)dumb$(O)
|
||||
HELP=$(L)help$(O)
|
||||
HLIB=$(HI)_ida.hlp
|
||||
|
||||
# to be used like this:
|
||||
# $(L)va$(A): $(call lib, $(VA_OBJS))
|
||||
lib=$(1); $(strip $(QARf)$(AR) $(OUTAR)$$@ $$^)
|
||||
|
||||
# to be used like this: $(call _link_exe, target, objs, libs)
|
||||
_link_exe=$(strip $(QCCL)$(CCL) $(OUTSW)$(1) $(2) $(3) $(LDFLAGS) $(STDLIBS))
|
||||
|
||||
# to be used like this: $(call link_exe, objs, libs)
|
||||
link_exe=$(call _link_exe,$@,$(1),$(2))
|
||||
|
||||
# to be used like this: $(call _link_dll, target, objs, libs)
|
||||
_link_dll=$(strip $(QCCL)$(CCL) $(OUTDLL) $(DLLFLAGS) $(OUTSW)$(1) $(2) $(3) $(LDFLAGS) $(STDLIBS))
|
||||
|
||||
# to be used like this: $(call link_dll, objs, libs)
|
||||
link_dll=$(call _link_dll,$@,$(1),$(2))
|
||||
|
||||
# to be used like this: $(call link_dumb, target, libs, objs)
|
||||
link_dumb=$(3) $(patsubst %,$(L)%$(A),$(2)); $(strip $(QCCLf)$(CCL) $(OUTSW)$(1) $(LDFLAGS) $(3) $(patsubst %,$(L)%$(A),$(2)) $(STDLIBS))
|
||||
|
||||
# to be used like this:
|
||||
# target: $(call dumb_target, libs, objs) extra_ldflags
|
||||
dumb_target=$(call link_dumb,$$@,$(1),$(2) $(DUMB))
|
||||
|
||||
# to be used like this:
|
||||
# $(R)%$(B): $(F)%$(O) $(call dumb_pattern, libs, objs) extra_ldflags
|
||||
dumb_pattern=$(call link_dumb,$$@ $$<,$(1),$(2) $(DUMB))
|
||||
|
||||
# to be used like this:
|
||||
# OBJS += $(call objs,obj1 obj2 obj3 ...)
|
||||
objs=$(addprefix $(F),$(addsuffix $(O),$(1)))
|
||||
|
||||
# output name for module dll
|
||||
module_dll=$(BIN_PATH)$(1)$(SUFF64)$(DLLEXT)
|
||||
|
||||
# output name for server executable
|
||||
server_exe=$(R)dbgsrv/$(1)
|
||||
|
||||
ifeq ($(or $(M),$(MM),$(MMH),$(MO),$(MMO),$(MMHO)),1)
|
||||
BUILD_IDA = 1
|
||||
endif
|
||||
ifeq ($(or $(M32),$(MM),$(MO32),$(MMO)),1)
|
||||
BUILD_DBGSRV = 1
|
||||
endif
|
||||
|
||||
# target-os specific variables
|
||||
ifdef __NT__
|
||||
DLLEXT=.dll
|
||||
else ifdef __MAC__
|
||||
DLLEXT=.dylib
|
||||
else
|
||||
DLLEXT=.so
|
||||
endif
|
||||
|
||||
# build system commands
|
||||
ifeq ($(OS),Windows_NT)
|
||||
CP=cp -f --preserve=all
|
||||
MKDIR=-@mkdir
|
||||
AWK=gawk
|
||||
else
|
||||
CP=cp -f
|
||||
MKDIR=-@mkdir 2>/dev/null
|
||||
AWK=awk
|
||||
endif
|
||||
RM=rm -f
|
||||
MV=mv
|
||||
|
||||
# used to silence some makefile commands
|
||||
# run 'make Q=' to prevent commands from being silenced
|
||||
Q?=@
|
||||
|
||||
# some makefiles rebuild targets when the makefile itself changes.
|
||||
# this makes debugging makefiles a pain.
|
||||
# run 'make MAKEFILE_DEP=' to disable this behaviour.
|
||||
MAKEFILE_DEP?=makefile
|
||||
|
||||
# libida-related
|
||||
# Note: $(IDALIB) should be used in the dependency list
|
||||
# $(LINKIDA) should be used in the link command
|
||||
ifdef __NT__
|
||||
# Note: on Windows, ida.lib does not have a "64" suffix for ea64
|
||||
IDALIB = $(L)ida$(A)
|
||||
LINKIDA = $(IDALIB)
|
||||
else
|
||||
IDALIB = $(L)libida$(SUFF64)$(DLLEXT)
|
||||
LINKIDA = -L$(L) -lida$(SUFF64)
|
||||
endif
|
||||
|
||||
# simplify command echo
|
||||
ifdef IDAMAKE_SIMPLIFY
|
||||
ifeq ($(Q),@)
|
||||
DO_IDAMAKE_SIMPLIFY=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef DO_IDAMAKE_SIMPLIFY
|
||||
ifdef IDAMAKE_SIMPLIFY_NO_COLOR
|
||||
qcolor=$(1)
|
||||
else
|
||||
ifeq ($(OS),Windows_NT)
|
||||
qcolor=-e #
|
||||
endif
|
||||
qcolor+="\033[1;34m$(1)\033[0m"
|
||||
endif
|
||||
QCXX = @echo $(call qcolor,compile) $< && #
|
||||
QCC = @echo $(call qcolor,compile) $< && #
|
||||
QASM = @echo $(call qcolor,asm) $< && #
|
||||
QARf = @echo $(call qcolor,lib) $$@ && #
|
||||
QCCL = @echo $(call qcolor,link) $@ && #
|
||||
QCCLf = @echo $(call qcolor,link) $$@ && #
|
||||
endif
|
||||
|
||||
# simple build rules
|
||||
CONLY?=-c
|
||||
|
||||
$(F)%$(O): %.cpp
|
||||
$(strip $(QCXX)$(CXX) $(CXXFLAGS) $(NORTTI) $(CONLY) $(OBJSW)$@ $<)
|
||||
|
||||
$(F)%$(O): %.c
|
||||
$(strip $(QCC)$(CC) $(CFLAGS) $(CONLY) $(OBJSW)$@ $(FORCEC) $<)
|
||||
|
||||
$(C)%.cfg: %.cfg
|
||||
$(CP) $? $@
|
||||
|
||||
# http://www.cmcrossroads.com/article/printing-value-makefile-variable
|
||||
print-%:
|
||||
@echo $* = "$($*)"
|
||||
@echo $*\'s origin is $(origin $*)
|
||||
|
||||
#############################################################################
|
||||
.PHONY: all test cfg includes
|
||||
|
||||
# Force make to delete the target if the rule to build it fails
|
||||
.DELETE_ON_ERROR:
|
||||
294
idasdk75/dbg/arm_debmod.cpp
Normal file
294
idasdk75/dbg/arm_debmod.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
#include <pro.h>
|
||||
#include <nalt.hpp>
|
||||
#include "arm_debmod.h"
|
||||
|
||||
#ifdef ENABLE_LOWCNDS
|
||||
inline bool has_armv5(void) { return true; }
|
||||
static arm_debmod_t *ssmod; // pointer to the current debugger module
|
||||
#endif
|
||||
|
||||
|
||||
#include "arm_regs.hpp"
|
||||
#include "deb_arm.hpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
arm_debmod_t::arm_debmod_t()
|
||||
{
|
||||
static const uchar bpt[] = ARM_BPT_CODE;
|
||||
bpt_code.append(bpt, sizeof(bpt));
|
||||
sp_idx = R_SP;
|
||||
pc_idx = R_PC;
|
||||
lr_idx = R_LR;
|
||||
sr_idx = R_PSR;
|
||||
nregs = qnumber(arm_registers);
|
||||
|
||||
is_xscale = false;
|
||||
for ( size_t i = 0; i < 2; i++ )
|
||||
{
|
||||
databpts[i] = BADADDR;
|
||||
codebpts[i] = BADADDR;
|
||||
dbptypes[i] = -1;
|
||||
cbptypes[i] = -1;
|
||||
}
|
||||
dbcon = 0;
|
||||
set_platform("linux");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi arm_debmod_t::dbg_is_ok_bpt(bpttype_t type, ea_t /*ea*/, int len)
|
||||
{
|
||||
if ( type == BPT_SOFT )
|
||||
return BPT_OK;
|
||||
|
||||
if ( !is_xscale )
|
||||
return BPT_BAD_TYPE; // hardware bpts are supported only for xScale
|
||||
|
||||
// For some reason hardware instruction breakpoints do not work
|
||||
if ( type == BPT_EXEC )
|
||||
return BPT_BAD_TYPE;
|
||||
|
||||
if ( len > 4 )
|
||||
return BPT_BAD_LEN;
|
||||
|
||||
bool ok = databpts[0] == BADADDR || databpts[1] == BADADDR;
|
||||
|
||||
return ok ? BPT_OK : BPT_TOO_MANY;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool arm_debmod_t::add_hwbpt(bpttype_t type, ea_t ea, int len)
|
||||
{
|
||||
// msg("add_hwbpt %d %a %d\n", type, ea, len);
|
||||
if ( !is_xscale || len > 4 )
|
||||
return false;
|
||||
|
||||
if ( !init_hwbpt_support() )
|
||||
return false;
|
||||
|
||||
if ( type == BPT_EXEC )
|
||||
{
|
||||
if ( codebpts[0] != BADADDR && codebpts[1] != BADADDR )
|
||||
return false;
|
||||
|
||||
int slot = codebpts[0] != BADADDR;
|
||||
codebpts[slot] = ea;
|
||||
cbptypes[slot] = type;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( databpts[0] != BADADDR && databpts[1] != BADADDR )
|
||||
return false;
|
||||
|
||||
int slot = databpts[0] != BADADDR;
|
||||
int bits;
|
||||
switch ( type )
|
||||
{
|
||||
case BPT_WRITE:
|
||||
bits = 1; // store only
|
||||
break;
|
||||
case BPT_RDWR:
|
||||
bits = 2; // load/store
|
||||
break;
|
||||
// BPT_READ: // load only
|
||||
// bits = 3;
|
||||
// break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
databpts[slot] = ea;
|
||||
dbptypes[slot] = type;
|
||||
dbcon |= bits << (slot*2);
|
||||
}
|
||||
return enable_hwbpts();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool arm_debmod_t::del_hwbpt(ea_t ea, bpttype_t type)
|
||||
{
|
||||
// msg("del_hwbpt %a\n", ea);
|
||||
if ( databpts[0] == ea && dbptypes[0] == type )
|
||||
{
|
||||
databpts[0] = BADADDR;
|
||||
dbcon &= ~3;
|
||||
}
|
||||
else if ( databpts[1] == ea && dbptypes[1] == type )
|
||||
{
|
||||
databpts[1] = BADADDR;
|
||||
dbcon &= ~(3<<2);
|
||||
}
|
||||
else if ( codebpts[0] == ea && cbptypes[0] == type )
|
||||
{
|
||||
codebpts[0] = BADADDR;
|
||||
}
|
||||
else if ( codebpts[1] == ea && cbptypes[1] == type )
|
||||
{
|
||||
codebpts[1] = BADADDR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return enable_hwbpts();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void arm_debmod_t::cleanup_hwbpts()
|
||||
{
|
||||
databpts[0] = BADADDR;
|
||||
databpts[1] = BADADDR;
|
||||
codebpts[0] = BADADDR;
|
||||
codebpts[1] = BADADDR;
|
||||
dbcon = 0;
|
||||
// disable all bpts
|
||||
if ( is_xscale )
|
||||
disable_hwbpts();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int arm_debmod_t::finalize_appcall_stack(
|
||||
call_context_t &ctx,
|
||||
regval_map_t ®s,
|
||||
bytevec_t &/*stk*/)
|
||||
{
|
||||
regs[lr_idx].ival = ctx.ctrl_ea;
|
||||
// return addrsize as the adjustment factor to add to sp
|
||||
// we do not need the return address, that's why we ignore the first 4
|
||||
// bytes of the prepared stack image
|
||||
return debapp_attrs.addrsize;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int arm_debmod_t::get_regidx(const char *regname, int *clsmask)
|
||||
{
|
||||
return arm_get_regidx(clsmask, regname);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LOWCNDS
|
||||
//--------------------------------------------------------------------------
|
||||
static const regval_t &idaapi arm_getreg(const char *name, const regval_t *regvals)
|
||||
{
|
||||
int idx = ssmod->get_regidx(name, NULL);
|
||||
QASSERT(30182, idx >= 0 && idx < ssmod->nregs);
|
||||
return regvals[idx];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static uint32 idaapi arm_get_long(ea_t ea)
|
||||
{
|
||||
uint32 v = -1;
|
||||
ssmod->dbg_read_memory(ea, &v, sizeof(v), NULL);
|
||||
return v;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static uint16 idaapi arm_get_word(ea_t ea)
|
||||
{
|
||||
uint16 v = -1;
|
||||
ssmod->dbg_read_memory(ea, &v, sizeof(v), NULL);
|
||||
return v;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static uint8 idaapi arm_get_byte(ea_t ea)
|
||||
{
|
||||
uint8 v = -1;
|
||||
ssmod->dbg_read_memory(ea, &v, sizeof(v), NULL);
|
||||
return v;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// stripped down version of get_dtype_size()
|
||||
static size_t idaapi arm_get_dtype_size(op_dtype_t dtype)
|
||||
{
|
||||
switch ( dtype )
|
||||
{
|
||||
case dt_byte: return 1; // 8 bit
|
||||
case dt_word:
|
||||
case dt_half: return 2; // 16 bit
|
||||
case dt_dword:
|
||||
case dt_float: return 4; // 4 byte
|
||||
case dt_qword:
|
||||
case dt_double: return 8; // 8 byte
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// since arm does not have a single step facility, we have to emulate it
|
||||
// with a temporary breakpoint.
|
||||
drc_t arm_debmod_t::dbg_perform_single_step(debug_event_t *dev, const insn_t &insn)
|
||||
{
|
||||
// read register values
|
||||
regvals_t values;
|
||||
values.resize(nregs);
|
||||
drc_t drc = dbg_read_registers(dev->tid, ARM_RC_GENERAL, values.begin(), NULL);
|
||||
if ( drc <= DRC_NONE )
|
||||
return drc;
|
||||
|
||||
static const opinfo_helpers_t oh =
|
||||
{
|
||||
arm_getreg,
|
||||
arm_get_byte,
|
||||
arm_get_word,
|
||||
arm_get_long,
|
||||
arm_get_dtype_size,
|
||||
NULL, // has_insn_cf_chg not needed
|
||||
};
|
||||
|
||||
// calculate the address of the next executed instruction
|
||||
lock_begin();
|
||||
ssmod = this;
|
||||
ea_t next = calc_next_exec_insn(insn, values.begin(), oh, false); // TODO pass is_mprofile parameter
|
||||
ssmod = NULL;
|
||||
lock_end();
|
||||
|
||||
// BADADDR means that the execution flow is linear
|
||||
if ( next == BADADDR )
|
||||
{
|
||||
next = insn.ea + insn.size;
|
||||
if ( (values[sr_idx].ival & BIT5) != 0 ) // thumb?
|
||||
next |= 1;
|
||||
}
|
||||
|
||||
// safety check: self jumping instruction cannot be single stepped
|
||||
if ( (next & ~1) == insn.ea )
|
||||
return DRC_FAILED;
|
||||
|
||||
// add a breakpoint there
|
||||
update_bpt_info_t ubi;
|
||||
ubi.ea = next;
|
||||
ubi.type = BPT_SOFT;
|
||||
ubi.code = 0;
|
||||
int nbpts;
|
||||
drc = dbg_update_bpts(&nbpts, &ubi, 1, 0, NULL);
|
||||
if ( drc != DRC_OK || nbpts == 0 )
|
||||
return drc != DRC_OK ? drc : DRC_FAILED;
|
||||
|
||||
drc = resume_app_and_get_event(dev);
|
||||
|
||||
// clean up: delete the temporary breakpoint
|
||||
ubi.ea &= ~1; // del_bpt requires an even address
|
||||
drc_t drc2 = dbg_update_bpts(&nbpts, &ubi, 0, 1, NULL);
|
||||
if ( drc2 != DRC_OK || nbpts == 0 )
|
||||
{
|
||||
msg("%a: failed to remove single step bpt?!\n", ubi.ea);
|
||||
drc = drc2 != DRC_OK ? drc2 : DRC_FAILED;
|
||||
}
|
||||
// the caller expects to see STEP after us:
|
||||
if ( drc == DRC_OK )
|
||||
dev->set_eid(STEP);
|
||||
return drc;
|
||||
}
|
||||
|
||||
#endif // ENABLE_LOWCNDS
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void arm_debmod_t::adjust_swbpt(ea_t *p_ea, int *p_len)
|
||||
{
|
||||
ea_t &ea = *p_ea;
|
||||
if ( (ea & 1) != 0 ) // T bit is set, use a thumb breakpoint
|
||||
{
|
||||
ea--;
|
||||
*p_len = 2;
|
||||
}
|
||||
}
|
||||
66
idasdk75/dbg/arm_debmod.h
Normal file
66
idasdk75/dbg/arm_debmod.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef __ARM_DEBMOD__
|
||||
#define __ARM_DEBMOD__
|
||||
|
||||
#include "deb_arm.hpp"
|
||||
#include "debmod.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class arm_debmod_t : public debmod_t
|
||||
{
|
||||
typedef debmod_t inherited;
|
||||
protected:
|
||||
bool is_xscale;
|
||||
ea_t databpts[2];
|
||||
ea_t codebpts[2];
|
||||
bpttype_t dbptypes[2];
|
||||
bpttype_t cbptypes[2];
|
||||
int dbcon;
|
||||
|
||||
int lr_idx;
|
||||
int sr_idx;
|
||||
|
||||
public:
|
||||
arm_debmod_t();
|
||||
void cleanup_hwbpts();
|
||||
|
||||
bool del_hwbpt(ea_t ea, bpttype_t type);
|
||||
bool add_hwbpt(bpttype_t type, ea_t ea, int len);
|
||||
ea_t is_hwbpt_triggered(thid_t id, bool is_stepping);
|
||||
|
||||
inline bool active_databpts(void)
|
||||
{
|
||||
return databpts[0] != BADADDR || databpts[1] != BADADDR;
|
||||
}
|
||||
|
||||
inline bool active_codebpts(void)
|
||||
{
|
||||
return codebpts[0] != BADADDR || codebpts[1] != BADADDR;
|
||||
}
|
||||
|
||||
inline bool active_hwbpts(void)
|
||||
{
|
||||
return active_databpts() || active_codebpts();
|
||||
}
|
||||
|
||||
// overridden base class functions
|
||||
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) override;
|
||||
virtual int finalize_appcall_stack(call_context_t &ctx, regval_map_t ®s, bytevec_t &stk) override;
|
||||
|
||||
// new virtial functions
|
||||
virtual bool init_hwbpt_support() newapi { return true; }
|
||||
virtual bool disable_hwbpts() newapi { return false; }
|
||||
virtual bool enable_hwbpts() newapi { return false; }
|
||||
virtual bool refresh_hwbpts() newapi { return false; }
|
||||
|
||||
virtual int get_regidx(const char *regname, int *clsmask) override;
|
||||
virtual void adjust_swbpt(ea_t *p_ea, int *p_len) override;
|
||||
|
||||
protected:
|
||||
#ifdef ENABLE_LOWCNDS
|
||||
virtual drc_t dbg_perform_single_step(debug_event_t *dev, const insn_t &insn) override;
|
||||
#endif
|
||||
};
|
||||
|
||||
bool is_32bit_thumb_insn(uint16 code);
|
||||
|
||||
#endif
|
||||
107
idasdk75/dbg/arm_local_impl.cpp
Normal file
107
idasdk75/dbg/arm_local_impl.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <set>
|
||||
|
||||
#include <idp.hpp>
|
||||
#include <dbg.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <segregs.hpp>
|
||||
#include <segment.hpp>
|
||||
|
||||
#include "deb_arm.hpp"
|
||||
|
||||
#include "arm_regs.cpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int is_arm_valid_bpt(bpttype_t type, ea_t ea, int len)
|
||||
{
|
||||
if ( type == BPT_SOFT )
|
||||
{
|
||||
if ( (ea & 1) != 0 )
|
||||
return BPT_BAD_ADDR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( type != BPT_RDWR // type is good?
|
||||
&& type != BPT_WRITE
|
||||
&& type != BPT_EXEC )
|
||||
{
|
||||
return BPT_BAD_TYPE;
|
||||
}
|
||||
|
||||
if ( (ea & (len-1)) != 0 ) // alignment is good?
|
||||
return BPT_BAD_ALIGN;
|
||||
|
||||
if ( len != 1 )
|
||||
{
|
||||
warning("AUTOHIDE REGISTRY\n"
|
||||
"xScale supports only 1 byte length hardware breakpoints");
|
||||
return BPT_BAD_LEN;
|
||||
}
|
||||
}
|
||||
return BPT_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// if bit0 is set, ensure that thumb mode
|
||||
// if bit0 is clear, ensure that arm mode
|
||||
static void handle_arm_thumb_modes(ea_t ea)
|
||||
{
|
||||
bool should_be_thumb = (ea & 1) != 0;
|
||||
bool is_thumb = processor_t::get_code16_mode(ea);
|
||||
if ( should_be_thumb != is_thumb )
|
||||
processor_t::set_code16_mode(ea, should_be_thumb);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static easet_t pending_addresses;
|
||||
|
||||
static ssize_t idaapi dbg_callback(void *, int code, va_list)
|
||||
{
|
||||
// we apply thumb/arm switches when the process is suspended.
|
||||
// it is quite late (normally we should do it as soon as the corresponding
|
||||
// segment is created) but i did not manage to make it work.
|
||||
// in the segm_added event the addresses are not enabled yet,
|
||||
// so switching modes fails.
|
||||
if ( code == dbg_suspend_process && !pending_addresses.empty() )
|
||||
{
|
||||
for ( easet_t::iterator p=pending_addresses.begin();
|
||||
p != pending_addresses.end();
|
||||
++p )
|
||||
{
|
||||
handle_arm_thumb_modes(*p);
|
||||
}
|
||||
pending_addresses.clear();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// For ARM processors the low bit means 1-thumb, 0-arm mode.
|
||||
// The following function goes over the address list and sets the mode
|
||||
// in IDA database according to bit0. It also resets bit0 for all addresses.
|
||||
void set_arm_thumb_modes(ea_t *addrs, int qty)
|
||||
{
|
||||
for ( int i=0; i < qty; i++ )
|
||||
{
|
||||
ea_t ea = addrs[i];
|
||||
segment_t *s = getseg(ea);
|
||||
if ( s == NULL )
|
||||
pending_addresses.insert(ea);
|
||||
else
|
||||
handle_arm_thumb_modes(ea);
|
||||
|
||||
addrs[i] = ea & ~1;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void processor_specific_init(void)
|
||||
{
|
||||
hook_to_notification_point(HT_DBG, dbg_callback);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void processor_specific_term(void)
|
||||
{
|
||||
unhook_from_notification_point(HT_DBG, dbg_callback);
|
||||
pending_addresses.clear();
|
||||
}
|
||||
213
idasdk75/dbg/arm_regs.cpp
Normal file
213
idasdk75/dbg/arm_regs.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
|
||||
#include "arm_regs.hpp"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: keep in sync with register_class_arm_t
|
||||
const char *arm_register_classes[] =
|
||||
{
|
||||
"General registers",
|
||||
"VFP registers",
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifndef __EA64__
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const psr[] =
|
||||
{
|
||||
"MODE", // 0
|
||||
"MODE", // 1
|
||||
"MODE", // 2
|
||||
"MODE", // 3
|
||||
"MODE", // 4
|
||||
"T", // 5
|
||||
"F", // 6
|
||||
"I", // 7
|
||||
"A", // 8
|
||||
"E", // 9
|
||||
"IT", // 10
|
||||
"IT", // 11
|
||||
"IT", // 12
|
||||
"IT", // 13
|
||||
"IT", // 14
|
||||
"IT", // 15
|
||||
"GE", // 16
|
||||
"GE", // 17
|
||||
"GE", // 18
|
||||
"GE", // 19
|
||||
NULL, // 20
|
||||
NULL, // 21
|
||||
NULL, // 22
|
||||
NULL, // 23
|
||||
"J", // 24
|
||||
"IT2", // 25 additional bits of IT
|
||||
"IT2", // 26 additional bits of IT
|
||||
"Q", // 27
|
||||
"V", // 28
|
||||
"C", // 29
|
||||
"Z", // 30
|
||||
"N", // 31
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const vfp_format[] =
|
||||
{
|
||||
"VFP_1_double",
|
||||
};
|
||||
#else
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const psr[] =
|
||||
{
|
||||
"M", // 0 AArch32 mode that an exception was taken from
|
||||
"M", // 1
|
||||
"M", // 2
|
||||
"M", // 3
|
||||
"M", // 4 Execution state that the exception was taken from
|
||||
"T", // 5 T32 Instruction set state bit
|
||||
"F", // 6 FIQ mask bit
|
||||
"I", // 7 IRQ mask bit
|
||||
"A", // 8 Asynchronous data abort mask bit
|
||||
"E", // 9 Endianness Execution State bit
|
||||
"IT", // 10 If-Then
|
||||
"IT", // 11
|
||||
"IT", // 12
|
||||
"IT", // 13
|
||||
"IT", // 14
|
||||
"IT", // 15
|
||||
"GE", // 16 Greater than or Equal flags
|
||||
"GE", // 17
|
||||
"GE", // 18
|
||||
"GE", // 19
|
||||
"IL", // 20 Illegal Execution State bit
|
||||
NULL, // 21
|
||||
NULL, // 22
|
||||
NULL, // 23
|
||||
NULL, // 24
|
||||
"IT2", // 25 If-Then
|
||||
"IT2", // 26
|
||||
"Q", // 27 Cumulative saturation bit
|
||||
"V", // 28 oVerflow condition flag
|
||||
"C", // 29 Carry condition flag
|
||||
"Z", // 30 Zero condition flag
|
||||
"N", // 31 Negative condition flag
|
||||
};
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: keep in sync with register_arm_t
|
||||
register_info_t arm_registers[] =
|
||||
{
|
||||
#ifndef __EA64__
|
||||
// General registers
|
||||
{ "R0", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R1", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R2", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R3", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R4", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R5", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R6", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R7", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R8", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R9", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R10", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R11", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "R12", REGISTER_ADDRESS|REGISTER_FP, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "SP", REGISTER_ADDRESS|REGISTER_SP, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "LR", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "PC", REGISTER_ADDRESS|REGISTER_IP, ARM_RC_GENERAL, dt_dword, NULL, 0 },
|
||||
{ "PSR", 0, ARM_RC_GENERAL, dt_dword, psr, 0xF800007F },
|
||||
// VFP registers
|
||||
{ "D0", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D1", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D2", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D3", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D4", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D5", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D6", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D7", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D8", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D9", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D10", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D11", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D12", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D13", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D14", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D15", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D16", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D17", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D18", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D19", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D20", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D21", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D22", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D23", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D24", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D25", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D26", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D27", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D28", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D29", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D30", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "D31", REGISTER_CUSTFMT, ARM_RC_VFP, dt_qword, vfp_format, 0 },
|
||||
{ "FPSCR", 0, ARM_RC_VFP, dt_dword, NULL, 0 },
|
||||
#else
|
||||
// General registers
|
||||
{ "X0", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X1", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X2", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X3", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X4", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X5", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X6", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X7", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X8", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X9", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X10", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X11", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X12", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X13", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X14", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X15", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X16", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X17", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X18", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X19", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X20", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X21", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X22", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X23", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X24", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X25", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X26", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X27", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X28", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X29", REGISTER_ADDRESS|REGISTER_FP, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "X30", REGISTER_ADDRESS, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "SP", REGISTER_ADDRESS|REGISTER_SP, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "PC", REGISTER_ADDRESS|REGISTER_IP, ARM_RC_GENERAL, dt_qword, NULL, 0 },
|
||||
{ "PSR", 0, ARM_RC_GENERAL, dt_dword, psr, 0xF8000000 },
|
||||
#endif
|
||||
};
|
||||
CASSERT(qnumber(arm_registers) == ARM_NREGS);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int arm_get_regidx(int *clsmask, const char *regname)
|
||||
{
|
||||
for ( size_t i = 0; i < qnumber(arm_registers); i++ )
|
||||
{
|
||||
if ( strieq(regname, arm_registers[i].name) )
|
||||
{
|
||||
if ( clsmask != NULL )
|
||||
*clsmask = arm_registers[i].register_class;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int arm_get_regclass(int idx)
|
||||
{
|
||||
if ( idx >= 0 && idx < qnumber(arm_registers) )
|
||||
return arm_registers[idx].register_class;
|
||||
return 0;
|
||||
}
|
||||
136
idasdk75/dbg/arm_regs.hpp
Normal file
136
idasdk75/dbg/arm_regs.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pro.h>
|
||||
#include <idd.hpp>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#if defined(__LINUX__) && defined(__ARM__) && !defined(__EA64__)
|
||||
# define __HAVE_ARM_VFP__
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: keep in sync with arm_register_classes
|
||||
enum register_class_arm_t
|
||||
{
|
||||
ARM_RC_GENERAL = 0x01, // General registers
|
||||
ARM_RC_VFP = 0x02, // VFP registers
|
||||
ARM_RC_ALL = ARM_RC_GENERAL
|
||||
#ifdef __HAVE_ARM_VFP__
|
||||
| ARM_RC_VFP
|
||||
#endif
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: keep in sync with arm_registers
|
||||
enum register_arm_t
|
||||
{
|
||||
#ifndef __EA64__
|
||||
// General registers
|
||||
R_R0,
|
||||
R_R1,
|
||||
R_R2,
|
||||
R_R3,
|
||||
R_R4,
|
||||
R_R5,
|
||||
R_R6,
|
||||
R_R7,
|
||||
R_R8,
|
||||
R_R9,
|
||||
R_R10,
|
||||
R_R11,
|
||||
R_R12,
|
||||
R_SP,
|
||||
R_LR,
|
||||
R_PC,
|
||||
R_PSR,
|
||||
// VFP registers
|
||||
R_D0,
|
||||
R_D1,
|
||||
R_D2,
|
||||
R_D3,
|
||||
R_D4,
|
||||
R_D5,
|
||||
R_D6,
|
||||
R_D7,
|
||||
R_D8,
|
||||
R_D9,
|
||||
R_D10,
|
||||
R_D11,
|
||||
R_D12,
|
||||
R_D13,
|
||||
R_D14,
|
||||
R_D15,
|
||||
R_D16,
|
||||
R_D17,
|
||||
R_D18,
|
||||
R_D19,
|
||||
R_D20,
|
||||
R_D21,
|
||||
R_D22,
|
||||
R_D23,
|
||||
R_D24,
|
||||
R_D25,
|
||||
R_D26,
|
||||
R_D27,
|
||||
R_D28,
|
||||
R_D29,
|
||||
R_D30,
|
||||
R_D31,
|
||||
R_FPSCR,
|
||||
#else
|
||||
// General registers
|
||||
R_R0,
|
||||
R_R1,
|
||||
R_R2,
|
||||
R_R3,
|
||||
R_R4,
|
||||
R_R5,
|
||||
R_R6,
|
||||
R_R7,
|
||||
R_R8,
|
||||
R_R9,
|
||||
R_R10,
|
||||
R_R11,
|
||||
R_R12,
|
||||
R_R13,
|
||||
R_R14,
|
||||
R_R15,
|
||||
R_R16,
|
||||
R_R17,
|
||||
R_R18,
|
||||
R_R19,
|
||||
R_R20,
|
||||
R_R21,
|
||||
R_R22,
|
||||
R_R23,
|
||||
R_R24,
|
||||
R_R25,
|
||||
R_R26,
|
||||
R_R27,
|
||||
R_R28,
|
||||
R_R29,
|
||||
R_LR,
|
||||
R_SP,
|
||||
R_PC,
|
||||
R_PSR,
|
||||
#endif
|
||||
};
|
||||
|
||||
// Number of registers in arm and aarch64
|
||||
#define ARM64_NREGS 34
|
||||
#define ARM32_NREGS 50
|
||||
|
||||
#ifdef __EA64__
|
||||
#define ARM_NREGS ARM64_NREGS
|
||||
#else
|
||||
#define ARM_NREGS ARM32_NREGS
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
extern const char *arm_register_classes[];
|
||||
extern register_info_t arm_registers[ARM_NREGS];
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int arm_get_regidx(int *clsmask, const char *regname);
|
||||
int arm_get_regclass(int idx);
|
||||
906
idasdk75/dbg/bin_search.cpp
Normal file
906
idasdk75/dbg/bin_search.cpp
Normal file
@@ -0,0 +1,906 @@
|
||||
#include <pro.h>
|
||||
#include "debmod.h"
|
||||
|
||||
//#define TEST
|
||||
#ifdef TEST
|
||||
static uchar memory[256];
|
||||
static const int PAGESZ = 4;
|
||||
static ssize_t read_page(ea_t ea, void *buf, size_t size, qstring *)
|
||||
{
|
||||
QASSERT(1517, (size % PAGESZ) == 0);
|
||||
if ( ea >= sizeof(memory) )
|
||||
return -1;
|
||||
memcpy(buf, &memory[ea], size);
|
||||
return size;
|
||||
}
|
||||
#else
|
||||
static const int PAGESZ = 4096;
|
||||
#define read_page(ea, buf, size, errbuf) mod->dbg_read_memory(ea, buf, size, errbuf)
|
||||
#endif
|
||||
static const int PAGE_HB = 1000; // page heartbeat counter
|
||||
static const int TIME_HB = (RECV_TIMEOUT_PERIOD/1000) / 2;
|
||||
// time period between heartbeats
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// memrchr is unavailable under Windows and MAC
|
||||
#if defined(_WIN32) || defined(__MAC__)
|
||||
// fixme: we need more optimized version
|
||||
static void *local_memrchr(const void *s, int c, size_t n)
|
||||
{
|
||||
const unsigned char *start = (const unsigned char *)s;
|
||||
const unsigned char *end = start + n - 1;
|
||||
while ( end >= start )
|
||||
{
|
||||
if ( *end == c )
|
||||
return (void *)end;
|
||||
end--;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#define local_memrchr memrchr
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class matcher_t
|
||||
{
|
||||
protected:
|
||||
struct partmatch_t
|
||||
{
|
||||
ea_t match_ea; // starting address of the match
|
||||
size_t ptn_idx; // index of the pattern
|
||||
size_t ptn_off; // offset inside the pattern
|
||||
};
|
||||
typedef qlist<partmatch_t> partmatches_t;
|
||||
|
||||
// constructor arguments
|
||||
ea_t *found_ea;
|
||||
debmod_t *mod;
|
||||
const compiled_binpat_vec_t &ptns;
|
||||
int srch_flags;
|
||||
qstring *errbuf; //lint !e958
|
||||
|
||||
uchar page[PAGESZ];
|
||||
ea_t page_ea;
|
||||
partmatches_t pmatches;
|
||||
ea_t failed_ea;
|
||||
|
||||
// cache
|
||||
intvec_t simple_ptns; // indexes of patterns w/o a mask and the search is case sensitive
|
||||
intvec_t complex_ptns; // other patterns
|
||||
|
||||
// heartbeat
|
||||
uint32 last_hb; // time in secs of the last heartbeat
|
||||
|
||||
matcher_t(
|
||||
ea_t *_found_ea,
|
||||
debmod_t *_mod,
|
||||
const compiled_binpat_vec_t &_ptns,
|
||||
int _srch_flags,
|
||||
qstring *_errbuf)
|
||||
: found_ea(_found_ea),
|
||||
mod(_mod),
|
||||
ptns(_ptns),
|
||||
srch_flags(_srch_flags),
|
||||
errbuf(_errbuf),
|
||||
page_ea(BADADDR),
|
||||
failed_ea(BADADDR)
|
||||
{
|
||||
for ( int i=0; i < ptns.size(); ++i )
|
||||
{
|
||||
const compiled_binpat_t &ptn = ptns[i];
|
||||
if ( ptn.bytes.empty() )
|
||||
continue;
|
||||
if ( sense_case() && ptn.all_bytes_defined() ) //TODO: && !inf_is_wide_high_byte_first() - for servers
|
||||
simple_ptns.push_back(i);
|
||||
else
|
||||
complex_ptns.push_back(i);
|
||||
}
|
||||
memset(page, 0, sizeof(page));
|
||||
last_hb = get_secs(qtime64());
|
||||
}
|
||||
|
||||
bool sense_case(void) const { return (srch_flags & BIN_SEARCH_CASE) != 0; }
|
||||
bool check_break(void) const { return (srch_flags & BIN_SEARCH_NOBREAK) == 0; }
|
||||
|
||||
bool test_cancelled(void) const
|
||||
{
|
||||
struct ida_local tester_t : public exec_request_t
|
||||
{
|
||||
virtual ~tester_t() {}
|
||||
virtual int idaapi execute(void)
|
||||
{
|
||||
return user_cancelled();
|
||||
}
|
||||
};
|
||||
tester_t tester;
|
||||
return execute_sync(tester, MFF_FAST);
|
||||
}
|
||||
|
||||
void send_heartbeat(size_t *page_counter)
|
||||
{
|
||||
*page_counter += 1;
|
||||
if ( *page_counter >= PAGE_HB )
|
||||
{
|
||||
*page_counter = 0;
|
||||
uint32 now = get_secs(qtime64());
|
||||
if ( now - last_hb >= TIME_HB )
|
||||
{
|
||||
mod->dmsg(""); // heartbeat
|
||||
last_hb = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DECLARE_VIRTUAL_DTOR(matcher_t)
|
||||
{
|
||||
found_ea = NULL;
|
||||
mod = NULL;
|
||||
errbuf = NULL;
|
||||
}
|
||||
|
||||
virtual drc_t walk_memory_ranges(const ea_t srch_start_ea, const ea_t srch_end_ea) = 0;
|
||||
|
||||
drc_t search_memory_range(ea_t range_start_ea, ea_t range_end_ea)
|
||||
{
|
||||
if ( range_is_unreadable(range_start_ea) )
|
||||
{
|
||||
#ifndef TEST
|
||||
mod->debdeb("dbg_bin_search memory range %a..%a is unreadable, skip it\n", range_start_ea, range_end_ea);
|
||||
#endif
|
||||
return DRC_FAILED;
|
||||
}
|
||||
|
||||
return find(range_start_ea, range_end_ea);
|
||||
}
|
||||
|
||||
virtual drc_t find(ea_t start_ea, ea_t end_ea) = 0;
|
||||
|
||||
bool match_pattern(
|
||||
const uchar *page_ptr,
|
||||
const compiled_binpat_t &ptn,
|
||||
size_t ptn_off,
|
||||
size_t nbytes) const
|
||||
{
|
||||
const uchar *image = ptn.bytes.begin() + ptn_off;
|
||||
const uchar *mask = ptn.all_bytes_defined() ? NULL : ptn.mask.begin() + ptn_off;
|
||||
for ( int i=0; i < nbytes; ++i, ++page_ptr, ++image )
|
||||
{
|
||||
uchar c = *page_ptr;
|
||||
if ( mask != NULL )
|
||||
{
|
||||
if ( mask == SKIP_FF_MASK )
|
||||
{
|
||||
if ( *image == 0xFF )
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mask[i] == 0 )
|
||||
continue;
|
||||
}
|
||||
}
|
||||
uchar c2 = *image;
|
||||
if ( sense_case() ? (c != c2) : (qtoupper(c) != qtoupper(c2)) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ea_t get_failed_address(void) const { return failed_ea; }
|
||||
|
||||
private:
|
||||
bool range_is_unreadable(ea_t range_start_ea)
|
||||
{
|
||||
uchar dummy;
|
||||
return mod->dbg_read_memory(range_start_ea, &dummy, sizeof(dummy), NULL) != sizeof(dummy);
|
||||
}
|
||||
};
|
||||
|
||||
typedef janitor_t<matcher_t *> matcher_janitor_t;
|
||||
template <> inline matcher_janitor_t::~janitor_t()
|
||||
{
|
||||
delete resource;
|
||||
resource = NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class forward_matcher_t : public matcher_t
|
||||
{
|
||||
size_t last_off;
|
||||
|
||||
public:
|
||||
forward_matcher_t(
|
||||
ea_t *_found_ea,
|
||||
debmod_t *_mod,
|
||||
const compiled_binpat_vec_t &_ptns,
|
||||
int _srch_flags,
|
||||
qstring *_errbuf)
|
||||
: matcher_t(_found_ea, _mod, _ptns, _srch_flags, _errbuf),
|
||||
last_off(PAGESZ)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
virtual drc_t walk_memory_ranges(const ea_t srch_start_ea, const ea_t srch_end_ea) override
|
||||
{
|
||||
meminfo_vec_t::const_iterator p=mod->old_ranges.begin();
|
||||
ea_t range_start_ea = BADADDR;
|
||||
for ( ; p < mod->old_ranges.end(); ++p )
|
||||
{
|
||||
if ( p->contains(srch_start_ea) )
|
||||
{
|
||||
range_start_ea = srch_start_ea;
|
||||
break;
|
||||
}
|
||||
if ( p->start_ea > srch_start_ea )
|
||||
break;
|
||||
}
|
||||
if ( range_start_ea == BADADDR )
|
||||
{
|
||||
if ( p == mod->old_ranges.end() || p->start_ea >= srch_end_ea )
|
||||
return DRC_FAILED; // not found
|
||||
range_start_ea = p->start_ea;
|
||||
}
|
||||
ea_t range_end_ea = srch_end_ea < p->end_ea ? srch_end_ea : p->end_ea;
|
||||
drc_t drc = search_memory_range(range_start_ea, range_end_ea);
|
||||
if ( drc != DRC_FAILED ) // not found
|
||||
return drc;
|
||||
|
||||
for ( ++p; p < mod->old_ranges.end() && srch_end_ea >= p->end_ea; ++p )
|
||||
{
|
||||
range_start_ea = p->start_ea;
|
||||
range_end_ea = srch_end_ea < p->end_ea ? srch_end_ea : p->end_ea;
|
||||
drc = search_memory_range(range_start_ea, range_end_ea);
|
||||
if ( drc != DRC_FAILED ) // not found
|
||||
return drc;
|
||||
}
|
||||
|
||||
return DRC_FAILED; // not found
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// find patterns in [start_ea, end_ea)
|
||||
virtual drc_t find(ea_t start_ea, ea_t end_ea) override
|
||||
{
|
||||
page_ea = align_down(start_ea, PAGESZ);
|
||||
ea_t page_off = start_ea - page_ea;
|
||||
size_t page_counter = 0;
|
||||
while ( page_ea < end_ea )
|
||||
{
|
||||
if ( check_break() && test_cancelled() )
|
||||
return DRC_ERROR;
|
||||
if ( read_page(page_ea, page, sizeof(page), errbuf) != sizeof(page) )
|
||||
{
|
||||
failed_ea = page_ea;
|
||||
return DRC_ERROR;
|
||||
}
|
||||
last_off = end_ea - page_ea;
|
||||
if ( last_off > PAGESZ )
|
||||
last_off = PAGESZ;
|
||||
// handle partial matches first
|
||||
for ( partmatches_t::iterator p=pmatches.begin(); p != pmatches.end(); )
|
||||
{
|
||||
switch ( finalize_partial_match(*p) )
|
||||
{
|
||||
case DRC_OK: // found a match
|
||||
return DRC_OK;
|
||||
default:
|
||||
case DRC_FAILED: // definitely failed
|
||||
p = pmatches.erase(p);
|
||||
break;
|
||||
case DRC_NONE: // need to continue matching
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// try to find new matches
|
||||
if ( match_simple_patterns(page_off) )
|
||||
return DRC_OK;
|
||||
if ( !complex_ptns.empty() )
|
||||
{
|
||||
while ( page_off < last_off )
|
||||
{
|
||||
if ( match_at(page_off) )
|
||||
return DRC_OK;
|
||||
page_off++;
|
||||
}
|
||||
}
|
||||
page_ea += PAGESZ; // advance to the next page
|
||||
page_off = 0;
|
||||
send_heartbeat(&page_counter);
|
||||
}
|
||||
return DRC_FAILED;
|
||||
}
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------------
|
||||
// try to match complex patterns at PAGE_OFF
|
||||
// too long patterns that do not fit the page will be matched partially
|
||||
// if the partial match is ok, we will remember them
|
||||
bool match_at(ea_t page_off)
|
||||
{
|
||||
const uchar *page_ptr = page + page_off;
|
||||
size_t rest = last_off - page_off;
|
||||
for ( intvec_t::const_iterator p=complex_ptns.begin();
|
||||
p != complex_ptns.end();
|
||||
++p )
|
||||
{
|
||||
const int &i = *p;
|
||||
const compiled_binpat_t &ptn = ptns[i];
|
||||
size_t vecsize = ptn.bytes.size();
|
||||
size_t nbytes = qmin(rest, vecsize);
|
||||
if ( !match_pattern(page_ptr, ptn, 0, nbytes) )
|
||||
continue;
|
||||
if ( vecsize <= rest )
|
||||
{
|
||||
*found_ea = page_ea + page_off;
|
||||
return true; // fits the page, a simple comparison is enough
|
||||
}
|
||||
// remember partial match
|
||||
partmatch_t pm;
|
||||
pm.match_ea = page_ea + page_off;
|
||||
pm.ptn_idx = i;
|
||||
pm.ptn_off = nbytes;
|
||||
pmatches.push_back(pm);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// try to match simple patterns inside the page
|
||||
// the partial match is processed as described above
|
||||
bool match_simple_patterns(ea_t page_off)
|
||||
{
|
||||
for ( intvec_t::const_iterator p=simple_ptns.begin();
|
||||
p != simple_ptns.end();
|
||||
++p )
|
||||
{
|
||||
const int &i = *p;
|
||||
const uchar *page_ptr = page + page_off;
|
||||
size_t rest = last_off - page_off;
|
||||
const bytevec_t &ptn_bytes = ptns[i].bytes;
|
||||
size_t ptn_sz = ptn_bytes.size();
|
||||
uchar ptn_ch = ptn_bytes[0];
|
||||
|
||||
const uchar *pold = page_ptr;
|
||||
while ( rest > 0 )
|
||||
{
|
||||
const uchar *pnew = (uchar *)memchr(pold, ptn_ch, rest);
|
||||
if ( pnew == NULL )
|
||||
break;
|
||||
rest -= (pnew - pold);
|
||||
size_t nbytes = qmin(rest, ptn_sz);
|
||||
if ( memcmp(pnew, ptn_bytes.begin(), nbytes) == 0 )
|
||||
{
|
||||
ea_t matched_ea = page_ea + (pnew - page);
|
||||
if ( ptn_sz <= rest )
|
||||
{
|
||||
*found_ea = matched_ea;
|
||||
return true;
|
||||
}
|
||||
// remember partial match
|
||||
partmatch_t pm;
|
||||
pm.match_ea = matched_ea;
|
||||
pm.ptn_idx = i;
|
||||
pm.ptn_off = nbytes;
|
||||
pmatches.push_back(pm);
|
||||
}
|
||||
pold = pnew + 1;
|
||||
rest -= 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// try to finalize a partial match by matching the next part of the
|
||||
// long pattern against the start of the PAGE. patterns that are still
|
||||
// too long for matching may produce new partial matches.
|
||||
drc_t finalize_partial_match(partmatch_t &pm)
|
||||
{
|
||||
const compiled_binpat_t &ptn = ptns[pm.ptn_idx];
|
||||
size_t vecsize = ptn.bytes.size();
|
||||
size_t ptn_rest = vecsize - pm.ptn_off;
|
||||
size_t nbytes = qmin(ptn_rest, last_off);
|
||||
if ( !match_pattern(page, ptn, pm.ptn_off, nbytes) )
|
||||
return DRC_FAILED;
|
||||
if ( ptn_rest <= last_off )
|
||||
{
|
||||
*found_ea = pm.match_ea;
|
||||
return DRC_OK; // finalized the match
|
||||
}
|
||||
if ( last_off != PAGESZ )
|
||||
return DRC_FAILED;
|
||||
// remember a new partial match
|
||||
pm.ptn_off += PAGESZ;
|
||||
return DRC_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class backward_matcher_t : public matcher_t
|
||||
{
|
||||
ea_t page_off;
|
||||
|
||||
public:
|
||||
backward_matcher_t(
|
||||
ea_t *_found_ea,
|
||||
debmod_t *_mod,
|
||||
const compiled_binpat_vec_t &_ptns,
|
||||
int _srch_flags,
|
||||
qstring *_errbuf)
|
||||
: matcher_t(_found_ea, _mod, _ptns, _srch_flags, _errbuf),
|
||||
page_off(0)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
virtual drc_t walk_memory_ranges(const ea_t srch_start_ea, const ea_t srch_end_ea) override
|
||||
{
|
||||
meminfo_vec_t::const_iterator p=mod->old_ranges.end() - 1;
|
||||
ea_t range_end_ea = BADADDR;
|
||||
for ( ; p >= mod->old_ranges.begin(); --p )
|
||||
{
|
||||
if ( p->start_ea < srch_end_ea )
|
||||
{
|
||||
range_end_ea = srch_end_ea < p->end_ea ? srch_end_ea : p->end_ea;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( range_end_ea == BADADDR )
|
||||
return DRC_FAILED; // not found
|
||||
ea_t range_start_ea = p->contains(srch_start_ea) ? srch_start_ea : p->start_ea;
|
||||
drc_t drc = search_memory_range(range_start_ea, range_end_ea);
|
||||
if ( drc != DRC_FAILED ) // not found
|
||||
return drc;
|
||||
|
||||
for ( --p; p >= mod->old_ranges.begin() && srch_start_ea < p->end_ea; --p )
|
||||
{
|
||||
range_end_ea = p->end_ea;
|
||||
range_start_ea = p->contains(srch_start_ea) ? srch_start_ea : p->start_ea;
|
||||
drc = search_memory_range(range_start_ea, range_end_ea);
|
||||
if ( drc != DRC_FAILED ) // not found
|
||||
return drc;
|
||||
}
|
||||
|
||||
return DRC_FAILED; // not found
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// find patterns in [start_ea, end_ea)
|
||||
virtual drc_t find(ea_t start_ea, ea_t end_ea) override
|
||||
{
|
||||
page_ea = align_down(end_ea - 1, PAGESZ);
|
||||
ea_t last_off = end_ea - page_ea;
|
||||
size_t page_counter = 0;
|
||||
while ( start_ea < page_ea + PAGESZ )
|
||||
{
|
||||
if ( check_break() && test_cancelled() )
|
||||
return DRC_ERROR;
|
||||
if ( read_page(page_ea, page, sizeof(page), errbuf) != sizeof(page) )
|
||||
{
|
||||
failed_ea = page_ea;
|
||||
return DRC_ERROR;
|
||||
}
|
||||
page_off = page_ea < start_ea ? start_ea - page_ea : 0;
|
||||
// handle partial matches first
|
||||
for ( partmatches_t::iterator p=pmatches.begin(); p != pmatches.end(); )
|
||||
{
|
||||
switch ( finalize_partial_match(*p) )
|
||||
{
|
||||
case DRC_OK: // found a match
|
||||
return DRC_OK;
|
||||
default:
|
||||
case DRC_FAILED: // definitely failed
|
||||
p = pmatches.erase(p);
|
||||
break;
|
||||
case DRC_NONE: // need to continue matching
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// try to find new matches
|
||||
if ( match_simple_patterns(last_off) )
|
||||
return DRC_OK;
|
||||
if ( !complex_ptns.empty() )
|
||||
{
|
||||
while ( page_off < last_off )
|
||||
{
|
||||
if ( match_before(last_off) )
|
||||
return DRC_OK;
|
||||
last_off--;
|
||||
}
|
||||
}
|
||||
page_ea -= PAGESZ; // advance to the next page
|
||||
last_off = PAGESZ;
|
||||
send_heartbeat(&page_counter);
|
||||
}
|
||||
return DRC_FAILED;
|
||||
}
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------------
|
||||
// try to match all patterns before LAST_OFF
|
||||
// too long patterns that do not fit the page will be matched partially
|
||||
// if the partial match is ok, we will remember them
|
||||
bool match_before(ea_t last_off)
|
||||
{
|
||||
size_t rest = last_off - page_off;
|
||||
for ( intvec_t::const_iterator p=complex_ptns.begin();
|
||||
p != complex_ptns.end();
|
||||
++p )
|
||||
{
|
||||
const int &i = *p;
|
||||
const compiled_binpat_t &ptn = ptns[i];
|
||||
size_t vecsize = ptn.bytes.size();
|
||||
size_t nbytes = qmin(rest, vecsize);
|
||||
if ( !match_pattern(page+last_off-nbytes, ptn, vecsize-nbytes, nbytes) )
|
||||
continue;
|
||||
if ( vecsize <= rest )
|
||||
{
|
||||
*found_ea = page_ea + last_off - nbytes;
|
||||
return true; // fits the page, a simple comparison is enough
|
||||
}
|
||||
// remember partial match
|
||||
partmatch_t pm;
|
||||
pm.match_ea = page_ea + last_off - vecsize;
|
||||
pm.ptn_idx = i;
|
||||
pm.ptn_off = nbytes;
|
||||
pmatches.push_back(pm);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// try to match simple patterns inside the page
|
||||
// the partial match is processed as described above
|
||||
bool match_simple_patterns(ea_t last_off)
|
||||
{
|
||||
const uchar *page_ptr = page + page_off;
|
||||
|
||||
for ( intvec_t::const_iterator q=simple_ptns.begin();
|
||||
q != simple_ptns.end();
|
||||
++q )
|
||||
{
|
||||
const int &i = *q;
|
||||
size_t rest = last_off - page_off;
|
||||
const bytevec_t &ptn_bytes = ptns[i].bytes;
|
||||
size_t ptn_sz = ptn_bytes.size();
|
||||
uchar ptn_ch = ptn_bytes[ptn_sz-1];
|
||||
|
||||
while ( rest > 0 )
|
||||
{
|
||||
const uchar *p = (uchar *)local_memrchr(page_ptr, ptn_ch, rest);
|
||||
if ( p == NULL )
|
||||
break;
|
||||
rest = p + 1 - page_ptr;
|
||||
size_t nbytes = qmin(rest, ptn_sz);
|
||||
if ( memcmp(p + 1 - nbytes, &ptn_bytes[ptn_sz - nbytes], nbytes) == 0 )
|
||||
{
|
||||
ea_t matched_ea = page_ea + (p + 1 - page) - ptn_sz;
|
||||
if ( ptn_sz <= rest )
|
||||
{
|
||||
*found_ea = matched_ea;
|
||||
return true;
|
||||
}
|
||||
// remember partial match
|
||||
partmatch_t pm;
|
||||
pm.match_ea = matched_ea;
|
||||
pm.ptn_idx = i;
|
||||
pm.ptn_off = nbytes;
|
||||
pmatches.push_back(pm);
|
||||
}
|
||||
rest -= 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// try to finalize a partial match by matching the previous part of the
|
||||
// long pattern against the end of the PAGE. patterns that are still
|
||||
// too long for matching may produce new partial matches.
|
||||
drc_t finalize_partial_match(partmatch_t &pm)
|
||||
{
|
||||
const compiled_binpat_t &ptn = ptns[pm.ptn_idx];
|
||||
size_t vecsize = ptn.bytes.size();
|
||||
size_t ptn_rest = vecsize - pm.ptn_off;
|
||||
size_t nbytes = qmin(ptn_rest, PAGESZ - page_off);
|
||||
if ( !match_pattern(page + PAGESZ - nbytes, ptn, ptn_rest - nbytes, nbytes) )
|
||||
return DRC_FAILED;
|
||||
if ( ptn_rest <= PAGESZ - page_off )
|
||||
{
|
||||
*found_ea = pm.match_ea;
|
||||
return DRC_OK; // finalized the match
|
||||
}
|
||||
if ( page_off != 0 )
|
||||
return DRC_FAILED;
|
||||
// remember a new partial match
|
||||
pm.ptn_off += PAGESZ;
|
||||
return DRC_NONE;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifndef TEST
|
||||
//--------------------------------------------------------------------------
|
||||
// Note:
|
||||
// The input search range can include the unreadable memory regions.
|
||||
// For example, "[vvar]" on Linux.
|
||||
// read_memory() returns 0 when trying to read from such region.
|
||||
// These regions must be skipped.
|
||||
drc_t idaapi debmod_t::dbg_bin_search(
|
||||
ea_t *found_ea,
|
||||
ea_t start_ea,
|
||||
ea_t end_ea,
|
||||
const compiled_binpat_vec_t &ptns,
|
||||
int srch_flags,
|
||||
qstring *errbuf)
|
||||
{
|
||||
static int forbidden = -1;
|
||||
if ( forbidden == -1 )
|
||||
forbidden = qgetenv("IDA_IDB_BIN_SEARCH", NULL);
|
||||
if ( forbidden )
|
||||
return DRC_NONE;
|
||||
|
||||
debdeb("dbg_bin_search %a..%a\n", start_ea, end_ea);
|
||||
|
||||
if ( start_ea >= end_ea || ptns.empty() || old_ranges.empty() )
|
||||
return DRC_NONE;
|
||||
|
||||
//lint -esym(429,matcher) has not been freed
|
||||
matcher_t *matcher = NULL;
|
||||
matcher_janitor_t matcher_janitor(matcher);
|
||||
|
||||
bool search_backward = (srch_flags & BIN_SEARCH_BACKWARD) != 0;
|
||||
if ( search_backward )
|
||||
matcher = new backward_matcher_t(found_ea, this, ptns, srch_flags, errbuf);
|
||||
else
|
||||
matcher = new forward_matcher_t(found_ea, this, ptns, srch_flags, errbuf);
|
||||
|
||||
drc_t drc = matcher->walk_memory_ranges(start_ea, end_ea);
|
||||
if ( drc != DRC_ERROR )
|
||||
return drc; //-V773 without releasing the 'matcher' pointer
|
||||
|
||||
ea_t failed_ea = matcher->get_failed_address();
|
||||
if ( failed_ea != BADADDR )
|
||||
{
|
||||
debdeb("dbg_bin_search failed to read memory at %a\n", failed_ea);
|
||||
if ( errbuf != NULL && errbuf->empty() )
|
||||
errbuf->sprnt("Failed to read memory at %a\n", failed_ea);
|
||||
}
|
||||
|
||||
return DRC_ERROR;
|
||||
}
|
||||
|
||||
#else // TEST
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t binary_search(
|
||||
ea_t *found_ea,
|
||||
ea_t start_ea,
|
||||
ea_t end_ea,
|
||||
const compiled_binpat_vec_t &ptns,
|
||||
int srch_flags,
|
||||
qstring *errbuf)
|
||||
{
|
||||
matcher_t *matcher;
|
||||
if ( (srch_flags & BIN_SEARCH_BACKWARD) != 0 )
|
||||
matcher = new backward_matcher_t(found_ea, NULL, ptns, srch_flags, errbuf);
|
||||
else
|
||||
matcher = new forward_matcher_t(found_ea, NULL, ptns, srch_flags, errbuf);
|
||||
drc_t drc = matcher->find(start_ea, end_ea);
|
||||
delete matcher;
|
||||
return drc;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool cmpbytes(
|
||||
const uchar *ptr,
|
||||
uchar b,
|
||||
const uchar *pptr,
|
||||
size_t ptnsize,
|
||||
bool sense_case)
|
||||
{
|
||||
if ( sense_case )
|
||||
return *ptr == b && memcmp(ptr+1, pptr, ptnsize) == 0; //lint !e670
|
||||
if ( qtoupper(b) != qtoupper(*ptr) )
|
||||
return false;
|
||||
++ptr;
|
||||
for ( int i=0; i < ptnsize; ++i, ++ptr, ++pptr )
|
||||
{
|
||||
if ( qtoupper(*ptr) != qtoupper(*pptr) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void *memmem(
|
||||
const void *buf,
|
||||
size_t bufsize,
|
||||
const void *ptn,
|
||||
size_t ptnsize,
|
||||
bool sense_case)
|
||||
{
|
||||
if ( int(ptnsize) <= 0 || int(bufsize) < 0 || ptnsize > bufsize )
|
||||
return NULL;
|
||||
const uchar *ptr = (const uchar *)buf;
|
||||
const uchar *const end = ptr + bufsize - ptnsize + 1;
|
||||
const uchar *pptr = (const uchar *)ptn;
|
||||
uchar b = *pptr++;
|
||||
ptnsize--;
|
||||
while ( ptr < end )
|
||||
{
|
||||
if ( cmpbytes(ptr, b, pptr, ptnsize, sense_case) )
|
||||
return (void *)ptr;
|
||||
++ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void *memmemr(
|
||||
const void *buf,
|
||||
size_t bufsize,
|
||||
const void *ptn,
|
||||
size_t ptnsize,
|
||||
bool sense_case)
|
||||
{
|
||||
if ( int(ptnsize) <= 0 || int(bufsize) < 0 || ptnsize > bufsize )
|
||||
return NULL;
|
||||
const uchar *ptr = (const uchar *)buf + bufsize - ptnsize;
|
||||
const uchar *const start = (const uchar *)buf;
|
||||
const uchar *pptr = (const uchar *)ptn;
|
||||
uchar b = *pptr++;
|
||||
ptnsize--;
|
||||
while ( start <= ptr )
|
||||
{
|
||||
if ( cmpbytes(ptr, b, pptr, ptnsize, sense_case) )
|
||||
return (void *)ptr;
|
||||
--ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t simple_binary_search(
|
||||
eavec_t *found_eas,
|
||||
ea_t start_ea,
|
||||
ea_t end_ea,
|
||||
const compiled_binpat_vec_t &ptns,
|
||||
int srch_flags,
|
||||
qstring * /*errbuf*/)
|
||||
{
|
||||
if ( start_ea >= end_ea || start_ea > sizeof(memory) )
|
||||
return DRC_FAILED;
|
||||
bool sense_case = (srch_flags & BIN_SEARCH_CASE) != 0;
|
||||
found_eas->clear();
|
||||
bool backward = (srch_flags & BIN_SEARCH_BACKWARD) != 0;
|
||||
for ( compiled_binpat_vec_t::const_iterator p=ptns.begin();
|
||||
p != ptns.end();
|
||||
++p )
|
||||
{
|
||||
const bytevec_t &vec = p->bytes;
|
||||
uchar *start = memory + start_ea;
|
||||
asize_t nbytes = qmin(sizeof(memory)-start_ea, end_ea-start_ea);
|
||||
uchar *f = (uchar *)(backward
|
||||
? memmemr(start, nbytes, vec.begin(), vec.size(), sense_case)
|
||||
: memmem(start, nbytes, vec.begin(), vec.size(), sense_case));
|
||||
if ( f == NULL )
|
||||
continue;
|
||||
ea_t idx = f - memory;
|
||||
if ( idx >= end_ea )
|
||||
continue;
|
||||
found_eas->push_back(idx);
|
||||
}
|
||||
return found_eas->empty() ? DRC_FAILED : DRC_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool check(qstring *found1_s, const eavec_t &found1, ea_t found2)
|
||||
{
|
||||
bool ok = found1.empty() && found2 == BADADDR;
|
||||
for ( int k=0; k < found1.size(); ++k )
|
||||
{
|
||||
if ( found1[k] == found2 )
|
||||
ok = true;
|
||||
if ( k > 0 )
|
||||
found1_s->append(',');
|
||||
found1_s->cat_sprnt("%a", found1[k]);
|
||||
}
|
||||
if ( found1_s->empty() )
|
||||
found1_s->sprnt("%a", BADADDR);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
bool sense_case = false;
|
||||
int max_ptns = 3;
|
||||
for ( int i=1; i < argc; ++i )
|
||||
{
|
||||
char argch = argv[i][0];
|
||||
if ( argch == 'C' )
|
||||
{
|
||||
sense_case = true;
|
||||
}
|
||||
else if ( '0' < argch && argch <= '9' )
|
||||
{
|
||||
max_ptns = argch - '0';
|
||||
}
|
||||
}
|
||||
msg("Test bin_search with %d pattern[s] and %s\n",
|
||||
max_ptns,
|
||||
sense_case ? "case sensitive" : "case ignored");
|
||||
|
||||
for ( int i=0; i < sizeof(memory); i++ )
|
||||
memory[i] = i;//rand();
|
||||
|
||||
for ( int i=0; i < 1000000; i++ )
|
||||
{
|
||||
// prepare a pattern for searching
|
||||
compiled_binpat_vec_t ptns;
|
||||
int ptns_cnt = max_ptns == 1 ? 1 : (rand() % max_ptns) + 1;
|
||||
ptns.resize(ptns_cnt);
|
||||
qstring out;
|
||||
for ( int c=0; c < ptns.size(); c++ )
|
||||
{
|
||||
size_t off = rand() % sizeof(memory);
|
||||
size_t len = (rand() % sizeof(memory)/20) + 1;
|
||||
if ( (rand() % 50) == 0 )
|
||||
len += 8;
|
||||
compiled_binpat_t &pat = ptns[c];
|
||||
pat.bytes.resize(len, 0xFF);
|
||||
size_t copyable = qmin(sizeof(memory)-off, len);
|
||||
memcpy(pat.bytes.begin(), &memory[off], copyable);
|
||||
if ( c > 0 )
|
||||
out.append(",");
|
||||
out.cat_sprnt("%X:%X", int(off), int(len));
|
||||
// if some rare cases make the pattern possibly insearchable
|
||||
if ( (rand() % 50) == 0 )
|
||||
{
|
||||
pat.bytes[0] = 0xAA;
|
||||
out.append("-");
|
||||
}
|
||||
}
|
||||
ea_t start_ea = rand() % sizeof(memory);
|
||||
ea_t end_ea = start_ea + (rand() % sizeof(memory));
|
||||
if ( end_ea > sizeof(memory) )
|
||||
end_ea = sizeof(memory); // no need to test out of memory
|
||||
int flags = sense_case ? BIN_SEARCH_CASE : BIN_SEARCH_NOCASE;
|
||||
|
||||
eavec_t found1;
|
||||
simple_binary_search(&found1, start_ea, end_ea, ptns, flags|BIN_SEARCH_FORWARD, NULL);
|
||||
|
||||
ea_t found2 = BADADDR;
|
||||
binary_search(&found2, start_ea, end_ea, ptns, flags|BIN_SEARCH_FORWARD, NULL);
|
||||
|
||||
qstring found1_s;
|
||||
bool ok = check(&found1_s, found1, found2);
|
||||
msg("%3d find (%s) in (%a..%a) => %s %a\n", i, out.c_str(), start_ea, end_ea, found1_s.c_str(), found2);
|
||||
if ( !ok )
|
||||
{
|
||||
msg("FAILED!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
found1.clear();
|
||||
simple_binary_search(&found1, start_ea, end_ea, ptns, flags|BIN_SEARCH_BACKWARD, NULL);
|
||||
|
||||
found2 = BADADDR;
|
||||
binary_search(&found2, start_ea, end_ea, ptns, flags|BIN_SEARCH_BACKWARD, NULL);
|
||||
|
||||
found1_s.qclear();
|
||||
ok = check(&found1_s, found1, found2);
|
||||
msg("%3d findr(%s) in (%a..%a) => %s %a\n", i, out.c_str(), start_ea, end_ea, found1_s.c_str(), found2);
|
||||
if ( !ok )
|
||||
{
|
||||
msg("FAILED!\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
msg("OK\n");
|
||||
return 0;
|
||||
}
|
||||
#endif // TEST
|
||||
34
idasdk75/dbg/bochs/bochsext.h
Normal file
34
idasdk75/dbg/bochs/bochsext.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* ALL RIGHTS RESERVED.
|
||||
* Copyright (c) 1990-2020 Hex-Rays
|
||||
*
|
||||
*
|
||||
* This file defines the Bochs Debugger module extension functions.
|
||||
* Use debugger_t->get_debmod_extensions() to retrieve this structure.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BOCHSEXT__
|
||||
#define __BOCHSEXT__
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#define BOCHSEXT_VER 1
|
||||
|
||||
struct bochsext_t
|
||||
{
|
||||
// the structure version
|
||||
uint32 version;
|
||||
|
||||
// Sends an arbitrary command to Bochs internal debugger
|
||||
// cmd - command to send
|
||||
// out - pointer to qstring that will hold the output of the command
|
||||
// Returns: true if ok; false if failed to send command to bochs or receive
|
||||
// a reply
|
||||
bool (idaapi *send_command)(const char *cmd, qstring *out);
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
62
idasdk75/dbg/bochs/ctrl/bochsys.h
Normal file
62
idasdk75/dbg/bochs/ctrl/bochsys.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* ALL RIGHTS RESERVED.
|
||||
* Copyright (c) 1990-2020 Hex-Rays
|
||||
*
|
||||
*
|
||||
* This file defines the functions prototypes that are exported by bochsys.dll
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BOCHSYS_DLL__
|
||||
#define __BOCHSYS_DLL__
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#define BX_CALLCONV WINAPI
|
||||
|
||||
typedef wchar_t wchar16_t;
|
||||
//CASSERT(sizeof(wchar16_t) == 2);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// These functions are similar to MS Windows functions. Please refer
|
||||
// to the SDK documentation for more information on how to use them.
|
||||
extern FARPROC WINAPI BxGetProcAddress(HMODULE hMod, LPCSTR ProcName);
|
||||
extern HMODULE WINAPI BxGetModuleHandleA(LPCSTR ModuleFileName);
|
||||
extern DWORD WINAPI BxGetModuleFileNameA(HINSTANCE hModule, LPCSTR lpFilename, DWORD nSize);
|
||||
extern DWORD WINAPI BxGetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize);
|
||||
extern HMODULE WINAPI BxLoadLibraryA(LPCTSTR lpFileName);
|
||||
extern LPVOID WINAPI BxVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
|
||||
extern BOOL WINAPI BxVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
|
||||
extern DWORD WINAPI BxExitProcess(DWORD);
|
||||
extern DWORD WINAPI BxGetTickCount(VOID);
|
||||
extern BOOL WINAPI BxVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
|
||||
extern DWORD WINAPI BxWin32SetLastError(DWORD ErrorCode);
|
||||
extern DWORD WINAPI BxWin32GetLastError(VOID);
|
||||
extern LPCSTR WINAPI BxWin32GetCommandLineA(VOID);
|
||||
extern LPWSTR WINAPI BxWin32GetCommandLineW(VOID);
|
||||
extern LPCSTR WINAPI BxWin32GetEnvironmentStringsA(VOID);
|
||||
extern LPWSTR WINAPI BxWin32GetEnvironmentStringsW(VOID);
|
||||
extern LPVOID WINAPI BxWin32TlsGetValue(DWORD dwTlsIndex);
|
||||
extern BOOL WINAPI BxWin32TlsSetValue(DWORD dwTlsIndex,LPVOID lpTlsValue);
|
||||
extern BOOL WINAPI BxWin32TlsFree(DWORD dwTlsIndex);
|
||||
extern DWORD WINAPI BxWin32TlsAlloc(VOID);
|
||||
extern DWORD WINAPI BxWin32FlsAlloc(VOID);
|
||||
extern char * WINAPI BxStrCpyA(char *Dst, char *Src);
|
||||
extern wchar16_t * WINAPI BxStrCpyW(wchar16_t *Dst, wchar16_t *Src);
|
||||
extern char * WINAPI BxStrCatA(char *Dst, char *Src);
|
||||
extern wchar16_t * WINAPI BxStrCatW(wchar16_t *Dst, wchar16_t *Src);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Installs an exception handler. Only one exception handler
|
||||
// can be installed at one time. You need to uninstall one
|
||||
// before reinstalling another.
|
||||
// These two functions will return non-zero on success.
|
||||
typedef DWORD (*PEXCEPTION_HANDLER)(PEXCEPTION_RECORD, struct _EXCEPTION_REGISTRATION_RECORD *, PCONTEXT,struct _EXCEPTION_REGISTRATION_RECORD **);
|
||||
|
||||
extern DWORD WINAPI BxInstallSEH(PEXCEPTION_HANDLER Handler);
|
||||
extern DWORD WINAPI BxUninstallSEH();
|
||||
|
||||
#endif
|
||||
271
idasdk75/dbg/bochs/ctrl/startup.idc
Normal file
271
idasdk75/dbg/bochs/ctrl/startup.idc
Normal file
@@ -0,0 +1,271 @@
|
||||
// This file contains bochs startup and exit procedures bochs_startup() and bochs_exit()
|
||||
// The former is called when the process starts
|
||||
// The latter is called when the process is about to exit
|
||||
// Both functions cause IDA debugger to suspend if they return a non zero value
|
||||
|
||||
// This section declares which DLLs will be available:
|
||||
// * Use the "stub" to mark a dll for stubbing
|
||||
|
||||
// * Use the "load" to mark a dll to be loaded as is
|
||||
// The "load" keyword has an additional attributes called "R0UserEntry"
|
||||
// This attribute is used to designate an exported function that will be called from ring0
|
||||
// Such a mechanism is useful to extend bochsys kernel or even replace it after it is loaded
|
||||
// One simple application is to modify the IDT and add R3 callable interrupts into your kernel
|
||||
|
||||
// Only lines containing three forward slashes ("/") are processed:
|
||||
|
||||
/// stub ntdll.dll
|
||||
/// stub kernel32.dll
|
||||
/// stub user32.dll
|
||||
/// stub shell32.dll
|
||||
/// stub shlwapi.dll
|
||||
/// stub urlmon.dll
|
||||
/// stub advapi32.dll
|
||||
/// stub mswsock.dll
|
||||
/// stub wininet.dll
|
||||
/// stub msvcrt.dll
|
||||
/// stub gdi32.dll
|
||||
/// stub ole32.dll
|
||||
/// stub wsock32.dll
|
||||
/// stub ws2_32.dll
|
||||
|
||||
// Define our own environment variables.
|
||||
// (add triple slashes to enable)
|
||||
// env path=c:\games\bin;d:\bin\asdf\
|
||||
// env userprofile=c:\games\
|
||||
|
||||
// Define your dependency mappings
|
||||
// (add triple slashes to enable the following lines)
|
||||
// map /home/guest/sys_dlls/user32.dll=d:\winnt\system32\user32.dll
|
||||
// map /home/guest/sys_dlls/shell32.dll=d:\winnt\system32\shell32.dll
|
||||
// map /home/guest/sys_dlls/kernel32.dll=d:\winnt\system32\kernel32.dll
|
||||
// map /home/guest/sys_dlls/shlwapi.dll=d:\winnt\system32\shlwapi.dll
|
||||
// map /home/guest/sys_dlls/urlmon.dll=d:\winnt\system32\urlmon.dll
|
||||
// map /home/guest/sys_dlls/mswsock.dll=d:\winnt\system32\mswsock.dll
|
||||
// map /home/guest/sys_dlls/wininet.dll=d:\winnt\system32\wininet.dll
|
||||
// map /home/guest/sys_dlls/msvcrt.dll=d:\winnt\system32\msvcrt.dll
|
||||
// map /home/guest/sys_dlls/gdi32.dll=d:\winnt\system32\gdi32.dll
|
||||
// map /home/guest/sys_dlls/ntdll.dll=d:\winnt\system32\ntdll.dll
|
||||
// map /home/guest/sys_dlls/advapi32.dll=d:\winnt\system32\advapi32.dll
|
||||
|
||||
// Define additional DLL path
|
||||
// (add triple slashes to enable the following lines)
|
||||
// path /home/guest/sys_dlls/=c:\winnt\system32\
|
||||
|
||||
// Bochs debugger plugin also allows you to specify the DLL path through the environment variable IDABXPATHMAP
|
||||
// (It is possible to specify more than one key/value pair by separating them with a semi-colon)
|
||||
// For example:
|
||||
// $ export IDABXPATHMAP="/home/guest/sys_dlls/=c:/winnt/system32/;/home/user2/other_dlls/=c:/program files/common files/3rd party/"
|
||||
// Similarly, one can specify the environment variables through the environment variable IDABXENVMAP
|
||||
// (it is possible to specify more than one key/value pair by separating them with a "++")
|
||||
// For example:
|
||||
// $ export IDABXENVMAP="TMP=c:/Users/Guest/Temp++SystemDrive=C:++windir=c:/windows/"
|
||||
//
|
||||
// Please note that the forward slashes "/" in the value part of the key/value pair will always be replaced with a backslash
|
||||
|
||||
//
|
||||
// The following are oneshot options. Once set they cannot be unset.
|
||||
// To define them simply preceed the option name with triple slashes.
|
||||
// - nosearchpath: Disables SearchPath() use for finding DLLs (this option is applicable on MS Windows only).
|
||||
// By turning this option, Bochs plugin will try to load DLLs from the current directory.
|
||||
// It useful for loading certain (old or new) versions of system DLLs instead of the ones currently installed
|
||||
// on the system.
|
||||
// - noactivationcontext: Disables the use of "Activation Context" (this option is applicable on MS Windows only).
|
||||
//
|
||||
|
||||
//
|
||||
// For loading drivers, you may uncomment the following stub definition(s):
|
||||
//
|
||||
// stub ntoskrnl.exe
|
||||
|
||||
// For example: to load a dll as is: load mydll.dll
|
||||
// For example: to load a dll as is and specify a user R0 entry: load mydll.dll R0UserEntry=MyExportedFunc
|
||||
|
||||
#include <idc.idc>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// IDC scripts that will be available during the debugging session
|
||||
|
||||
// MS Windows related functions
|
||||
// ------------------------------
|
||||
// BochsVirtXXXX functions allocate/free virtual memory in the emulated session.
|
||||
// The "size" parameter is always rounded to a page.
|
||||
//
|
||||
|
||||
//
|
||||
// Allocate virtual memory
|
||||
// This function emulates the VirtualAlloc function from MS Windows
|
||||
// addr - the preferred address for the allocation. Zero means no preference
|
||||
// size - size of the block to allocate
|
||||
// writable - should be allocated memory be wrtiable?
|
||||
// Currently only read/write page protections are supported
|
||||
// Returns: the address of the allocated block or zero
|
||||
//
|
||||
// long BochsVirtAlloc(long addr, long size, bool writable);
|
||||
//
|
||||
|
||||
//
|
||||
// Change protection of memory page
|
||||
// This function emulates the VirtualProtect function from MS Windows
|
||||
// addr - the desired address to change protection.
|
||||
// size - size of the block
|
||||
// attr - the new page attribute:
|
||||
// 0 = Read only
|
||||
// 1 = Read/Write
|
||||
// Returns: the old protection value or -1 on failure
|
||||
//
|
||||
// long BochsVirtProtect(long addr, long size, long attr);
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// Free virtual memory
|
||||
// This function emulates the VirtualFree function from MS Windows
|
||||
// addr - the address of previously allocated memory block
|
||||
// size - the size of the block. If zero, then the entire block at addr
|
||||
// will be freed.
|
||||
// Returns: success
|
||||
//
|
||||
// bool BochsVirtFree(long addr, long size);
|
||||
//
|
||||
|
||||
//
|
||||
// Returns the base address of a given module name
|
||||
// module_name - The name of the module.
|
||||
// The name can be full path or filename with extension, or simply filename without extension
|
||||
// Returns: zero if it fails
|
||||
//
|
||||
// long BochsGetModuleHandle(string module_name);
|
||||
//
|
||||
|
||||
//
|
||||
// Returns a procedure's address
|
||||
// This function calls the internal GetProcAddress to resolve function addresses.
|
||||
// hmod - the module handle
|
||||
// procname - name of the procedure inside the module
|
||||
// Returns: the zero if procedure not found, otherwise the address
|
||||
//
|
||||
// long BochsGetProcAddress(long hmod, string procname);
|
||||
//
|
||||
|
||||
//
|
||||
// Returns the module name given its base address
|
||||
// module_handle: the base address of a given module
|
||||
// Returns: empty string if module was not found
|
||||
//
|
||||
// string BochsGetModuleFileName(long module_handle)
|
||||
//
|
||||
|
||||
//
|
||||
// Returns the command line value passed to the application
|
||||
//
|
||||
// string BochsGetCommandLine()
|
||||
//
|
||||
|
||||
//
|
||||
// Set last error code
|
||||
// This function emulates the SetLastError function from MS Windows.
|
||||
// It writes the specified code to TIB.
|
||||
// error_code - new error code to set
|
||||
// Returns: success
|
||||
//
|
||||
// success BochsWin32SetLastError(long error_num);
|
||||
//
|
||||
|
||||
//
|
||||
// Other functions:
|
||||
// -------------------
|
||||
//
|
||||
|
||||
//
|
||||
// Sends arbitrary commands to the internal debugger of BOCHS. The output is returned as a string.
|
||||
// This is useful for example to send some commands to BOCHS that are not exposed via the GUI of IDA.
|
||||
// command: the command you want to send
|
||||
// Returns: output string or empty string if it failed
|
||||
//
|
||||
// string send_dbg_command(string command)
|
||||
//
|
||||
|
||||
//
|
||||
// Retrieves the parameter value passed to an IDC script that is implementing a given API.
|
||||
// This same function can be implemented with this expression: #define BX_GETPARAM(n) get_wide_dword(esp+4*(n+1))
|
||||
// arg_num: the argument number (starting by one)
|
||||
// Returns: the value or zero in case it fails
|
||||
//
|
||||
// string BochsGetParam(long arg_num)
|
||||
//
|
||||
|
||||
//
|
||||
// Calls a function inside Bochs
|
||||
// This function can call functions inside Bochs. Very useful if you want to call
|
||||
// functions in the user's code. The arguments are pushed from right to left.
|
||||
// func_ptr - The address of the function to be called
|
||||
// argN - a set of dwords that contain the arguments.
|
||||
// Arguments can be numbers or pointers
|
||||
// Returns: success
|
||||
//
|
||||
// long BochsCall(long func_ptr, arg1, arg2, ...);
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// These functions will return the total physical memory amount and the remaining free
|
||||
// memory in bytes.
|
||||
// Returns: memory size in bytes
|
||||
//
|
||||
// long BochsGetFreeMem()
|
||||
// long BochsGetMaxMem()
|
||||
//
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static BochsPatchDbgDword(ea, dv)
|
||||
{
|
||||
auto i;
|
||||
for (i=0;i<4;i++)
|
||||
{
|
||||
patch_dbg_byte(ea, dv & 0xFF);
|
||||
ea = ea + 1;
|
||||
dv = dv >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Utility function that can be used as a conditional breakpoint condition
|
||||
// in order to skip to the next instruction w/o suspending IDA
|
||||
static bochs_skipnext()
|
||||
{
|
||||
Eip = next_head(eip, BADADDR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Utility function that can be used as a conditional breakpoint condition
|
||||
// in order to execute the contents of the comments at the bp location
|
||||
static bochs_execidc_comments()
|
||||
{
|
||||
exec_idc(Comment(eip));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Utility function used to dump registers. The output can be used as a comment
|
||||
// with the bochs_execidc_comments() bp condition
|
||||
static bochs_dump_registers()
|
||||
{
|
||||
msg("eax=0x%x;ebx=0x%x;ecx=0x%x;edx=0x%x;esi=0x%x;edi=0x%x;ebp=0x%x;", eax, ebx, ecx, edx, esi, edi, ebp);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static bochs_startup()
|
||||
{
|
||||
msg("Bochs debugger has been initialized.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static bochs_exit()
|
||||
{
|
||||
msg("Bochs debugger has been terminated.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
2
idasdk75/dbg/bochs/sdk/api_user32.idc
Normal file
2
idasdk75/dbg/bochs/sdk/api_user32.idc
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
///func=MessageBoxA entry=bxtest.MyMessageBox
|
||||
89
idasdk75/dbg/bochs/sdk/bxtest.c
Normal file
89
idasdk75/dbg/bochs/sdk/bxtest.c
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "bochsys.h"
|
||||
#include <windows.h>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// dummy entry point so that linker does not use entrypoints from CRT
|
||||
DWORD WINAPI Entry(DWORD a, DWORD b, DWORD c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This function will be called by bochsys.dll from R0 before switching to R3
|
||||
// This is even called before TLS callbacks
|
||||
void WINAPI MyR0Entry(VOID)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
nop
|
||||
mov dx, 0378h
|
||||
in eax, dx
|
||||
nop
|
||||
nop
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
DWORD MyHandler(
|
||||
PEXCEPTION_RECORD rec,
|
||||
struct _EXCEPTION_REGISTRATION_RECORD *reg,
|
||||
PCONTEXT ctx,
|
||||
struct _EXCEPTION_REGISTRATION_RECORD **reg2)
|
||||
{
|
||||
ctx->Eip += 2;
|
||||
return ExceptionContinueExecution;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void BuggyFunction()
|
||||
{
|
||||
BxInstallSEH(MyHandler);
|
||||
__asm
|
||||
{
|
||||
xor eax, eax
|
||||
mov eax, [eax]
|
||||
}
|
||||
BxUninstallSEH();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// In this function, BxXXXXXX functions are used from the bochsys library
|
||||
int __stdcall MyMessageBox(
|
||||
HWND hWnd,
|
||||
LPCTSTR lpText,
|
||||
LPCTSTR lpCaption,
|
||||
UINT uType)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
// Allocate memory
|
||||
p = BxVirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_READWRITE);
|
||||
|
||||
// Fill the memory
|
||||
for (i=1;i<=0x1000;i++)
|
||||
*p++ = i & 0xFF;
|
||||
|
||||
// Resolve an entry and call it
|
||||
(VOID (__stdcall *)(int, int)) BxGetProcAddress(BxLoadLibraryA("kernel32.dll"), "Beep")(5, 1);
|
||||
|
||||
// Call a function that might cause an exception
|
||||
BuggyFunction();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// In this function we import from user32 and kernel32
|
||||
// (because VirtualAlloc->BxVirtualAlloc and MessageBoxA->bxtest.MyMessageBox are redirected and implemented)
|
||||
int __stdcall MyRoutine(
|
||||
HWND hWnd,
|
||||
LPCTSTR lpText,
|
||||
LPCTSTR lpCaption,
|
||||
UINT uType)
|
||||
{
|
||||
VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_READWRITE);
|
||||
MessageBoxA(0, "hey", "info", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
4
idasdk75/dbg/bochs/sdk/bxtest.def
Normal file
4
idasdk75/dbg/bochs/sdk/bxtest.def
Normal file
@@ -0,0 +1,4 @@
|
||||
EXPORTS
|
||||
MyMessageBox
|
||||
MyRoutine
|
||||
MyR0Entry
|
||||
BIN
idasdk75/dbg/bochs/sdk/bxtest.dll
Normal file
BIN
idasdk75/dbg/bochs/sdk/bxtest.dll
Normal file
Binary file not shown.
11
idasdk75/dbg/bochs/sdk/compile.bat
Normal file
11
idasdk75/dbg/bochs/sdk/compile.bat
Normal file
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\cl.exe" -c /Zl /Gd /Tc bxtest.c "/IC:/Program Files (x86)/Windows Kits/8.1/Include/um" "/IC:/Program Files (x86)/Windows Kits/8.1/Include/shared" "/IC:/PROGRA~2/WI3CF2~1/10/Include/10.0.10150.0/ucrt" /I"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include"
|
||||
if errorlevel 1 goto end
|
||||
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\link.exe" bxtest.obj bochsys.lib kernel32.lib user32.lib /OUT:bxtest.dll /ENTRY:Entry /def:bxtest.def /DRIVER /SAFESEH:NO /NODEFAULTLIB /SUBSYSTEM:WINDOWS /LIBPATH:"C:\Program Files\Microsoft Visual Studio 14.0\VC\Lib" /LIBPATH:"C:/Program Files (x86)/Windows Kits/8.1/Lib/winv6.3/um/x86"
|
||||
if errorlevel 1 goto end
|
||||
|
||||
if exist bxtest.obj del bxtest.obj
|
||||
if exist bxtest.exp del bxtest.exp
|
||||
if exist bxtest.lib del bxtest.lib
|
||||
|
||||
:end
|
||||
90
idasdk75/dbg/bochs/sdk/readme.txt
Normal file
90
idasdk75/dbg/bochs/sdk/readme.txt
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
Custom DLLs for emulated MS Windows environment
|
||||
-----------------------------------------------
|
||||
|
||||
This directory contains files that demonstrate how to build a custom DLL
|
||||
for the PE loader of the Bochs debugger.
|
||||
|
||||
compile.bat shows how to build a custom DLL with the MS compiler/linker.
|
||||
The general rule is not to link with runtime libraries, but linking with
|
||||
import libraries is ok.
|
||||
|
||||
"bxtest.c" demonstrates how to call functions in bochsys.dll.
|
||||
"bochsys.h" has the list of functions that can be called from custom DLLs.
|
||||
"bochsys.lib" is the corresponding import library
|
||||
|
||||
Custom DLLs must be mentioned in plugins\bochs\startup.idc.
|
||||
For that please add a line like this:
|
||||
|
||||
/// load bxtest.dll
|
||||
|
||||
This will cause the DLL to be present in the memory space of the debugged process.
|
||||
For the custom DLL to be useful, its exported functions should be connected
|
||||
to API function names. For example, the following line redirects MessageBoxA
|
||||
to bxtest.MyMessageBox:
|
||||
|
||||
/// func=MessageBoxA entry=bxtest.MyMessageBox
|
||||
|
||||
The exact format of the startup.idc file is explained in its header.
|
||||
|
||||
On the other hand, it is also possible to write a custom DLL that replaces system
|
||||
DLLs like kernel32.dll or user32.dll.
|
||||
|
||||
|
||||
The "load" command has an additional parameter "R0UserEntry=MyR0Entry" used as:
|
||||
///load bxtest.dll R0UserEntry=MyR0Entry
|
||||
|
||||
Which means that bxtest.dll should be loaded into the process memory and
|
||||
that this DLL has an exported entry that should be called by bochsys from ring0.
|
||||
Such a facility is ideal if you're looking to replace or enhance bochsys's kernel.
|
||||
|
||||
To test how MessageBoxA is redirected to MyMessageBox, please follow these
|
||||
steps:
|
||||
|
||||
- compile and link bxtest.dll with compile.bat
|
||||
(we provide ready-to-use bxtest.dll for your convenience, so you
|
||||
skip this step)
|
||||
|
||||
- add two lines mentioned above to startup.idc and api_user32.idc respectively
|
||||
|
||||
- load test.pe into IDA and select Bochs debugger
|
||||
|
||||
- run it and single step into the MessageBoxA function
|
||||
|
||||
With any questions, please contact us at support@hex-rays.com
|
||||
|
||||
|
||||
Bochs plugin debugger extensions
|
||||
-----------------------------------
|
||||
|
||||
Bochs extensions allow for accessing extended debugger functionality.
|
||||
|
||||
To get and use the extensions, query the currently loaded debugger using
|
||||
get_debmod_extensions(). Usually it returns a pointer to a structure with
|
||||
pointers to functions. Please follow this example:
|
||||
|
||||
#include "bochsext.h"
|
||||
|
||||
void idaapi run(int)
|
||||
{
|
||||
if ( dbg == NULL )
|
||||
{
|
||||
msg("dbg == NULL\n");
|
||||
return;
|
||||
}
|
||||
const bochsext_t *ext = (const bochsext_t *)dbg->get_debmod_extensions();
|
||||
if ( ext == NULL )
|
||||
{
|
||||
msg("no debugger extensions!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// dump 10 bytes from physical memory at 0x0
|
||||
qstring out;
|
||||
if ( !ext->send_command("xp /10mb 0x0\r\n", &out) )
|
||||
{
|
||||
msg("failed to send command!\n");
|
||||
return;
|
||||
}
|
||||
msg("->result=%s\n", out.c_str());
|
||||
}
|
||||
36
idasdk75/dbg/bochs/sdk/test.asm
Normal file
36
idasdk75/dbg/bochs/sdk/test.asm
Normal file
@@ -0,0 +1,36 @@
|
||||
; #########################################################################
|
||||
|
||||
.386
|
||||
.model flat, stdcall
|
||||
option casemap :none ; case sensitive
|
||||
|
||||
; #########################################################################
|
||||
|
||||
include d:\masm32\include\windows.inc
|
||||
include d:\masm32\include\user32.inc
|
||||
include d:\masm32\include\kernel32.inc
|
||||
|
||||
includelib d:\masm32\lib\user32.lib
|
||||
includelib d:\masm32\lib\kernel32.lib
|
||||
|
||||
; #########################################################################
|
||||
; --------------------------------------------------------
|
||||
.data
|
||||
szDlgTitle db "Minimum MASM",0
|
||||
szMsg db " --- Assembler Pure and Simple --- ",0
|
||||
.code
|
||||
start:
|
||||
; --------------------------------------------------------
|
||||
; script
|
||||
push MB_OK
|
||||
push offset szDlgTitle
|
||||
push offset szMsg
|
||||
push 0
|
||||
call MessageBox
|
||||
|
||||
; --------------------------------------------------------
|
||||
; idacall
|
||||
push -2
|
||||
call ExitProcess
|
||||
|
||||
end start
|
||||
BIN
idasdk75/dbg/bochs/sdk/test.pe
Normal file
BIN
idasdk75/dbg/bochs/sdk/test.pe
Normal file
Binary file not shown.
857
idasdk75/dbg/common_local_impl.cpp
Normal file
857
idasdk75/dbg/common_local_impl.cpp
Normal file
@@ -0,0 +1,857 @@
|
||||
//
|
||||
// This file is included from other files, do not directly compile it.
|
||||
// It contains the debugger_t structure definition and a few other helper functions
|
||||
//
|
||||
|
||||
#include <loader.hpp>
|
||||
#include <segregs.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
bool plugin_inited;
|
||||
bool debugger_inited;
|
||||
|
||||
#define IS_GDB_DEBUGGER (DEBUGGER_ID == DEBUGGER_ID_GDB_USER || DEBUGGER_ID == DEBUGGER_ID_ARM_IPHONE_USER || DEBUGGER_ID == DEBUGGER_ID_XNU_USER)
|
||||
|
||||
#if TARGET_PROCESSOR == PLFM_386
|
||||
#define REGISTERS x86_registers
|
||||
#define REGISTERS_SIZE qnumber(x86_registers)
|
||||
#define REGISTER_CLASSES x86_register_classes
|
||||
#define REGISTER_CLASSES_DEFAULT X86_RC_GENERAL
|
||||
#define READ_REGISTERS x86_read_registers
|
||||
#define WRITE_REGISTER x86_write_register
|
||||
#if !IS_GDB_DEBUGGER
|
||||
#define is_valid_bpt is_x86_valid_bpt
|
||||
#endif
|
||||
#define BPT_CODE X86_BPT_CODE
|
||||
#define BPT_CODE_SIZE X86_BPT_SIZE
|
||||
#elif TARGET_PROCESSOR == PLFM_ARM
|
||||
#define REGISTERS arm_registers
|
||||
#define REGISTERS_SIZE qnumber(arm_registers)
|
||||
#define REGISTER_CLASSES arm_register_classes
|
||||
#define REGISTER_CLASSES_DEFAULT ARM_RC_GENERAL
|
||||
#define READ_REGISTERS s_read_registers
|
||||
#define WRITE_REGISTER s_write_register
|
||||
#if !IS_GDB_DEBUGGER
|
||||
#define is_valid_bpt is_arm_valid_bpt
|
||||
#else
|
||||
#define is_valid_bpt gdb_valid_bpt
|
||||
#endif
|
||||
#define BPT_CODE ARM_BPT_CODE
|
||||
#define BPT_CODE_SIZE ARM_BPT_SIZE
|
||||
#elif TARGET_PROCESSOR == PLFM_DALVIK
|
||||
#define BPT_CODE { 0 }
|
||||
#define BPT_CODE_SIZE 0
|
||||
#define READ_REGISTERS s_read_registers
|
||||
#define WRITE_REGISTER s_write_register
|
||||
#define is_valid_bpt is_dalvik_valid_bpt
|
||||
#elif IS_GDB_DEBUGGER
|
||||
#define REGISTERS NULL
|
||||
#define REGISTERS_SIZE 0
|
||||
#define REGISTER_CLASSES NULL
|
||||
#define REGISTER_CLASSES_DEFAULT 0
|
||||
#define READ_REGISTERS simple_read_registers
|
||||
#define WRITE_REGISTER simple_write_register
|
||||
#define is_valid_bpt gdb_valid_bpt
|
||||
#define BPT_CODE { 0 }
|
||||
#define BPT_CODE_SIZE 0
|
||||
#else
|
||||
#error This processor is not supported yet
|
||||
#endif
|
||||
|
||||
static const uchar bpt_code[] = BPT_CODE;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi is_ok_bpt(bpttype_t type, ea_t ea, int len)
|
||||
{
|
||||
int ret = is_valid_bpt(type, ea, len);
|
||||
if ( ret != BPT_OK )
|
||||
return ret;
|
||||
else
|
||||
return g_dbgmod.dbg_is_ok_bpt(type, ea, len);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// For ARM, we have to set the low bit of the address to 1 for thumb mode
|
||||
#if DEBUGGER_ID == DEBUGGER_ID_ARM_LINUX_USER
|
||||
static drc_t idaapi arm_update_bpts(
|
||||
int *nbpts,
|
||||
update_bpt_info_t *bpts,
|
||||
int nadd,
|
||||
int ndel,
|
||||
qstring *errbuf)
|
||||
{
|
||||
// This function is called from debthread, but to use get_sreg() we must
|
||||
// switch to the mainthread
|
||||
struct ida_local arm_bptea_fixer_t : public exec_request_t
|
||||
{
|
||||
update_bpt_info_t *bpts;
|
||||
update_bpt_info_t *e;
|
||||
qvector<ea_t *> thumb_mode;
|
||||
virtual int idaapi execute(void) override
|
||||
{
|
||||
for ( update_bpt_info_t *b=bpts; b != e; b++ )
|
||||
{
|
||||
if ( b->type == BPT_SOFT && get_sreg(b->ea, ARM_T) == 1 )
|
||||
{
|
||||
b->ea++; // odd address means that thumb bpt must be set
|
||||
thumb_mode.push_back(&b->ea);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
arm_bptea_fixer_t(update_bpt_info_t *p1, update_bpt_info_t *p2)
|
||||
: bpts(p1), e(p2) {}
|
||||
};
|
||||
arm_bptea_fixer_t abf(bpts, bpts+nadd);
|
||||
execute_sync(abf, MFF_READ);
|
||||
|
||||
drc_t drc = s_update_bpts(nbpts, bpts, nadd, ndel, errbuf);
|
||||
|
||||
// reset the odd bit because the addresses are required by the caller
|
||||
for ( int i=0; i < abf.thumb_mode.size(); i++ )
|
||||
(*abf.thumb_mode[i])--;
|
||||
|
||||
return drc;
|
||||
}
|
||||
#define s_update_bpts arm_update_bpts
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static drc_t idaapi update_bpts(
|
||||
int *nbpts,
|
||||
update_bpt_info_t *bpts,
|
||||
int nadd,
|
||||
int ndel,
|
||||
qstring *errbuf)
|
||||
{
|
||||
bool valid_bpt_exists = false;
|
||||
update_bpt_info_t *e = bpts + nadd;
|
||||
for ( update_bpt_info_t *b=bpts; b != e; b++ )
|
||||
{
|
||||
if ( b->code == BPT_SKIP )
|
||||
continue;
|
||||
|
||||
b->code = is_valid_bpt(b->type, b->ea, b->size);
|
||||
if ( b->code == BPT_OK )
|
||||
valid_bpt_exists = true;
|
||||
}
|
||||
|
||||
if ( !valid_bpt_exists && ndel == 0 )
|
||||
{
|
||||
if ( nbpts != NULL )
|
||||
*nbpts = 0;
|
||||
return DRC_OK; // none of bpts is writable
|
||||
}
|
||||
|
||||
drc_t drc = s_update_bpts(nbpts, bpts, nadd, ndel, errbuf);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#ifndef REMOTE_DEBUGGER
|
||||
// another copy of this function (for remote debugging) is defined in dbg_rpc_handler.cpp
|
||||
int send_ioctl(
|
||||
void *,
|
||||
int fn,
|
||||
const void *buf,
|
||||
size_t size,
|
||||
void **poutbuf,
|
||||
ssize_t *poutsize)
|
||||
{
|
||||
return g_dbgmod.handle_ioctl(fn, buf, size, poutbuf, poutsize);
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
THREAD_SAFE int debmod_t::send_debug_names_to_ida(
|
||||
ea_t *addrs,
|
||||
const char *const *names,
|
||||
int qty)
|
||||
{
|
||||
return ::send_debug_names_to_ida(addrs, names, qty);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
THREAD_SAFE int send_debug_names_to_ida(
|
||||
ea_t *addrs,
|
||||
const char *const *names,
|
||||
int qty)
|
||||
{
|
||||
struct debug_name_handler_t : public exec_request_t
|
||||
{
|
||||
ea_t *addrs;
|
||||
const char *const *names;
|
||||
int qty;
|
||||
debug_name_handler_t(ea_t *_addrs, const char *const *_names, int _qty)
|
||||
: addrs(_addrs), names(_names), qty(_qty) {}
|
||||
int idaapi execute(void) override
|
||||
{
|
||||
set_arm_thumb_modes(addrs, qty);
|
||||
return set_debug_names(addrs, names, qty);
|
||||
}
|
||||
};
|
||||
debug_name_handler_t dnh(addrs, names, qty);
|
||||
return execute_sync(dnh, MFF_WRITE);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
THREAD_SAFE int debmod_t::send_debug_event_to_ida(
|
||||
const debug_event_t *ev,
|
||||
int rqflags)
|
||||
{
|
||||
return ::send_debug_event_to_ida(ev, rqflags);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
THREAD_SAFE int send_debug_event_to_ida(
|
||||
const debug_event_t *ev,
|
||||
int rqflags)
|
||||
{
|
||||
return handle_debug_event(ev, rqflags);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
THREAD_SAFE int import_dll(const import_request_t &req)
|
||||
{
|
||||
struct dll_importer_t : public exec_request_t
|
||||
{
|
||||
const import_request_t &req;
|
||||
dll_importer_t(const import_request_t &_req) : req(_req) {}
|
||||
int idaapi execute(void) override
|
||||
{
|
||||
return g_dbgmod.import_dll(req) ? 0 : 1;
|
||||
}
|
||||
};
|
||||
dll_importer_t di(req);
|
||||
return execute_sync(di, MFF_WRITE);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#if TARGET_PROCESSOR != PLFM_ARM
|
||||
void set_arm_thumb_modes(ea_t * /*addrs*/, int /*qty*/)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// installs or uninstalls debugger specific idc functions
|
||||
bool add_idc_funcs(const ext_idcfunc_t efuncs[], size_t nfuncs, bool reg)
|
||||
{
|
||||
if ( reg )
|
||||
{
|
||||
for ( int i=0; i < nfuncs; i++ )
|
||||
if ( !add_idc_func(efuncs[i]) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i=0; i < nfuncs; i++ )
|
||||
if ( !del_idc_func(efuncs[i].name) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static drc_t init_debugger(
|
||||
const char *hostname,
|
||||
int port_num,
|
||||
const char *password,
|
||||
qstring *errbuf)
|
||||
{
|
||||
g_dbgmod.dbg_set_debugging((debug & IDA_DEBUG_DEBUGGER) != 0);
|
||||
|
||||
if ( !s_open_remote(hostname, port_num, password, errbuf) )
|
||||
return DRC_FAILED;
|
||||
|
||||
uint32_t flags2 = 0;
|
||||
drc_t drc = s_init(&flags2, errbuf);
|
||||
if ( drc != DRC_OK )
|
||||
{
|
||||
s_close_remote();
|
||||
return drc;
|
||||
}
|
||||
|
||||
debugger.flags2 |= flags2;
|
||||
#if defined(REMOTE_DEBUGGER) && !defined(NO_OPEN_FILE)
|
||||
setflag(debugger.flags2, DBG_HAS_OPEN_FILE, true);
|
||||
#endif
|
||||
#ifdef HAVE_UPDATE_CALL_STACK
|
||||
setflag(debugger.flags2, DBG_HAS_UPDATE_CALL_STACK, true);
|
||||
#endif
|
||||
#ifdef HAVE_APPCALL
|
||||
setflag(debugger.flags2, DBG_HAS_APPCALL, true);
|
||||
#endif
|
||||
#ifdef HAVE_MAP_ADDRESS
|
||||
setflag(debugger.flags2, DBG_HAS_MAP_ADDRESS, true);
|
||||
#endif
|
||||
debugger_inited = true;
|
||||
processor_specific_init();
|
||||
register_idc_funcs(true);
|
||||
init_dbg_idcfuncs(true);
|
||||
#if DEBUGGER_ID == DEBUGGER_ID_X86_IA32_WIN32_USER || DEBUGGER_ID == DEBUGGER_ID_X86_IA32_BOCHS
|
||||
install_x86seh_menu();
|
||||
#endif
|
||||
return DRC_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static drc_t term_debugger(void)
|
||||
{
|
||||
if ( debugger_inited )
|
||||
{
|
||||
debugger_inited = false;
|
||||
#if DEBUGGER_ID == DEBUGGER_ID_X86_IA32_WIN32_USER || DEBUGGER_ID == DEBUGGER_ID_X86_IA32_BOCHS
|
||||
remove_x86seh_menu();
|
||||
#endif
|
||||
init_dbg_idcfuncs(false);
|
||||
register_idc_funcs(false);
|
||||
processor_specific_term();
|
||||
g_dbgmod.dbg_term();
|
||||
return s_close_remote();
|
||||
}
|
||||
return DRC_FAILED;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static ssize_t idaapi idd_notify(void *, int msgid, va_list va)
|
||||
{
|
||||
int retcode = DRC_NONE;
|
||||
qstring *errbuf;
|
||||
|
||||
switch ( msgid )
|
||||
{
|
||||
case debugger_t::ev_init_debugger:
|
||||
{
|
||||
const char *hostname = va_arg(va, const char *);
|
||||
int portnum = va_arg(va, int);
|
||||
const char *password = va_arg(va, const char *);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
QASSERT(1522, errbuf != NULL);
|
||||
retcode = init_debugger(hostname, portnum, password, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_term_debugger:
|
||||
retcode = term_debugger();
|
||||
break;
|
||||
|
||||
case debugger_t::ev_get_processes:
|
||||
{
|
||||
procinfo_vec_t *procs = va_arg(va, procinfo_vec_t *);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = g_dbgmod.dbg_get_processes(procs, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_start_process:
|
||||
{
|
||||
const char *path = va_arg(va, const char *);
|
||||
const char *args = va_arg(va, const char *);
|
||||
const char *startdir = va_arg(va, const char *);
|
||||
uint32 dbg_proc_flags = va_arg(va, uint32);
|
||||
const char *input_path = va_arg(va, const char *);
|
||||
uint32 input_file_crc32 = va_arg(va, uint32);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = s_start_process(path,
|
||||
args,
|
||||
startdir,
|
||||
dbg_proc_flags,
|
||||
input_path,
|
||||
input_file_crc32,
|
||||
errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_attach_process:
|
||||
{
|
||||
pid_t pid = va_argi(va, pid_t);
|
||||
int event_id = va_arg(va, int);
|
||||
uint32 dbg_proc_flags = va_arg(va, uint32);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = s_attach_process(pid, event_id, dbg_proc_flags, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_detach_process:
|
||||
retcode = g_dbgmod.dbg_detach_process();
|
||||
break;
|
||||
|
||||
case debugger_t::ev_get_debapp_attrs:
|
||||
{
|
||||
debapp_attrs_t *out_pattrs = va_arg(va, debapp_attrs_t *);
|
||||
g_dbgmod.dbg_get_debapp_attrs(out_pattrs);
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_rebase_if_required_to:
|
||||
{
|
||||
ea_t new_base = va_arg(va, ea_t);
|
||||
rebase_if_required_to(new_base);
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_request_pause:
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = g_dbgmod.dbg_prepare_to_pause_process(errbuf);
|
||||
break;
|
||||
|
||||
case debugger_t::ev_exit_process:
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = g_dbgmod.dbg_exit_process(errbuf);
|
||||
break;
|
||||
|
||||
case debugger_t::ev_get_debug_event:
|
||||
{
|
||||
gdecode_t *code = va_arg(va, gdecode_t *);
|
||||
debug_event_t *event = va_arg(va, debug_event_t *);
|
||||
int timeout_ms = va_arg(va, int);
|
||||
*code = g_dbgmod.dbg_get_debug_event(event, timeout_ms);
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_resume:
|
||||
{
|
||||
debug_event_t *event = va_arg(va, debug_event_t *);
|
||||
retcode = g_dbgmod.dbg_continue_after_event(event);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_set_exception_info:
|
||||
{
|
||||
exception_info_t *info = va_arg(va, exception_info_t *);
|
||||
int qty = va_arg(va, int);
|
||||
g_dbgmod.dbg_set_exception_info(info, qty);
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_suspended:
|
||||
{
|
||||
bool dlls_added = va_argi(va, bool);
|
||||
thread_name_vec_t *thr_names = va_arg(va, thread_name_vec_t *);
|
||||
s_stopped_at_debug_event(thr_names, dlls_added);
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_thread_suspend:
|
||||
{
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
retcode = g_dbgmod.dbg_thread_suspend(tid);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_thread_continue:
|
||||
{
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
retcode = g_dbgmod.dbg_thread_continue(tid);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_set_resume_mode:
|
||||
{
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
resume_mode_t resmod = va_argi(va, resume_mode_t);
|
||||
retcode = g_dbgmod.dbg_set_resume_mode(tid, resmod);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_read_registers:
|
||||
{
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
int clsmask = va_arg(va, int);
|
||||
regval_t *values = va_arg(va, regval_t *);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = READ_REGISTERS(tid, clsmask, values, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_write_register:
|
||||
{
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
int regidx = va_arg(va, int);
|
||||
const regval_t *value = va_arg(va, const regval_t *);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = WRITE_REGISTER(tid, regidx, value, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_thread_get_sreg_base:
|
||||
{
|
||||
ea_t *answer = va_arg(va, ea_t *);
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
int sreg_value = va_arg(va, int);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = g_dbgmod.dbg_thread_get_sreg_base(answer, tid, sreg_value, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_get_memory_info:
|
||||
{
|
||||
meminfo_vec_t *ranges = va_arg(va, meminfo_vec_t *);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = g_dbgmod.dbg_get_memory_info(*ranges, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_read_memory:
|
||||
{
|
||||
size_t *nbytes = va_arg(va, size_t *);
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
void *buffer = va_arg(va, void *);
|
||||
size_t size = va_arg(va, size_t);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
ssize_t code = g_dbgmod.dbg_read_memory(ea, buffer, size, errbuf);
|
||||
*nbytes = code >= 0 ? code : 0;
|
||||
retcode = code >= 0 ? DRC_OK : DRC_NOPROC;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_write_memory:
|
||||
{
|
||||
size_t *nbytes = va_arg(va, size_t *);
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
const void *buffer = va_arg(va, void *);
|
||||
size_t size = va_arg(va, size_t);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
ssize_t code = g_dbgmod.dbg_write_memory(ea, buffer, size, errbuf);
|
||||
*nbytes = code >= 0 ? code : 0;
|
||||
retcode = code >= 0 ? DRC_OK : DRC_NOPROC;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_check_bpt:
|
||||
{
|
||||
int *bptvc = va_arg(va, int *);
|
||||
bpttype_t type = va_argi(va, bpttype_t);
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
int len = va_arg(va, int);
|
||||
*bptvc = is_ok_bpt(type, ea, len);
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_update_bpts:
|
||||
{
|
||||
int *nbpts = va_arg(va, int *);
|
||||
update_bpt_info_t *bpts = va_arg(va, update_bpt_info_t *);
|
||||
int nadd = va_arg(va, int);
|
||||
int ndel = va_arg(va, int);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = update_bpts(nbpts, bpts, nadd, ndel, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_update_lowcnds:
|
||||
{
|
||||
int *nupdated = va_arg(va, int *);
|
||||
const lowcnd_t *lowcnds = va_arg(va, const lowcnd_t *);
|
||||
int nlowcnds = va_arg(va, int);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = g_dbgmod.dbg_update_lowcnds(nupdated, lowcnds, nlowcnds, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_open_file:
|
||||
{
|
||||
const char *file = va_arg(va, const char *);
|
||||
uint64 *fsize = va_arg(va, uint64 *);
|
||||
bool readonly = va_argi(va, bool);
|
||||
retcode = g_dbgmod.dbg_open_file(file, fsize, readonly);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_close_file:
|
||||
{
|
||||
int fn = va_arg(va, int);
|
||||
g_dbgmod.dbg_close_file(fn);
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_read_file:
|
||||
{
|
||||
int fn = va_arg(va, int);
|
||||
qoff64_t off = va_arg(va, qoff64_t);
|
||||
void *buf = va_arg(va, void *);
|
||||
size_t size = va_arg(va, size_t);
|
||||
retcode = g_dbgmod.dbg_read_file(fn, off, buf, size);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_write_file:
|
||||
{
|
||||
int fn = va_arg(va, int);
|
||||
qoff64_t off = va_arg(va, qoff64_t);
|
||||
const void *buf = va_arg(va, const void *);
|
||||
size_t size = va_arg(va, size_t);
|
||||
retcode = g_dbgmod.dbg_write_file(fn, off, buf, size);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_map_address:
|
||||
{
|
||||
ea_t *mapped = va_arg(va, ea_t *);
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
const regval_t *regs = va_arg(va, const regval_t *);
|
||||
int regnum = va_arg(va, int);
|
||||
*mapped = g_dbgmod.map_address(ea, regs, regnum);
|
||||
return DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef GET_DEBMOD_EXTS
|
||||
case debugger_t::ev_get_debmod_extensions:
|
||||
{
|
||||
const void **ext = va_arg(va, const void **);
|
||||
*ext = GET_DEBMOD_EXTS();
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UPDATE_CALL_STACK
|
||||
case debugger_t::ev_update_call_stack:
|
||||
{
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
call_stack_t *trace = va_arg(va, call_stack_t *);
|
||||
retcode = g_dbgmod.dbg_update_call_stack(tid, trace);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_APPCALL
|
||||
case debugger_t::ev_appcall:
|
||||
{
|
||||
ea_t *blob_ea = va_arg(va, ea_t *);
|
||||
ea_t func_ea = va_arg(va, ea_t);
|
||||
thid_t tid = va_arg(va, thid_t);
|
||||
const func_type_data_t *fti = va_arg(va, const func_type_data_t *);
|
||||
int nargs = va_arg(va, int);
|
||||
const regobjs_t *regargs = va_arg(va, const regobjs_t *);
|
||||
relobj_t *stkargs = va_arg(va, relobj_t *);
|
||||
regobjs_t *retregs = va_arg(va, regobjs_t *);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
debug_event_t *event = va_arg(va, debug_event_t *);
|
||||
int opts = va_arg(va, int);
|
||||
qnotused(nargs);
|
||||
*blob_ea = g_dbgmod.dbg_appcall(func_ea, tid, fti->stkargs, regargs, stkargs, retregs, errbuf, event, opts);
|
||||
retcode = DRC_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_cleanup_appcall:
|
||||
{
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
retcode = g_dbgmod.dbg_cleanup_appcall(tid);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case debugger_t::ev_eval_lowcnd:
|
||||
{
|
||||
thid_t tid = va_argi(va, thid_t);
|
||||
ea_t ea = va_arg(va, ea_t);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
retcode = g_dbgmod.dbg_eval_lowcnd(tid, ea, errbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_send_ioctl:
|
||||
{
|
||||
int fn = va_arg(va, int);
|
||||
const void *buf = va_arg(va, const void *);
|
||||
size_t size = va_arg(va, size_t);
|
||||
void **poutbuf = va_arg(va, void **);
|
||||
ssize_t *poutsize = va_arg(va, ssize_t *);
|
||||
retcode = g_dbgmod.handle_ioctl(fn, buf, size, poutbuf, poutsize);
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_dbg_enable_trace:
|
||||
{
|
||||
thid_t tid = va_arg(va, thid_t);
|
||||
bool enable = va_argi(va, bool);
|
||||
int trace_flags = va_arg(va, int);
|
||||
retcode = g_dbgmod.dbg_enable_trace(tid, enable, trace_flags) ? DRC_OK : DRC_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_is_tracing_enabled:
|
||||
{
|
||||
thid_t tid = va_arg(va, thid_t);
|
||||
int tracebit = va_arg(va, int);
|
||||
retcode = g_dbgmod.dbg_is_tracing_enabled(tid, tracebit) ? DRC_OK : DRC_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case debugger_t::ev_rexec:
|
||||
{
|
||||
const char *cmdline = va_arg(va, const char *);
|
||||
retcode = g_dbgmod.dbg_rexec(cmdline);
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef HAVE_GET_SRCINFO_PATH
|
||||
case debugger_t::ev_get_srcinfo_path:
|
||||
{
|
||||
qstring *path = va_arg(va, qstring *);
|
||||
ea_t base = va_arg(va, ea_t);
|
||||
bool ok = g_dbgmod.dbg_get_srcinfo_path(path, base);
|
||||
retcode = ok ? DRC_OK : DRC_NONE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case debugger_t::ev_bin_search:
|
||||
{
|
||||
ea_t *ea = va_arg(va, ea_t *);
|
||||
ea_t start_ea = va_arg(va, ea_t);
|
||||
ea_t end_ea = va_arg(va, ea_t);
|
||||
const compiled_binpat_vec_t *ptns = va_arg(va, const compiled_binpat_vec_t *);
|
||||
int srch_flags = va_arg(va, int);
|
||||
errbuf = va_arg(va, qstring *);
|
||||
if ( ptns != NULL )
|
||||
retcode = g_dbgmod.dbg_bin_search(ea, start_ea, end_ea, *ptns, srch_flags, errbuf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialize debugger plugin
|
||||
static plugmod_t *idaapi init(void)
|
||||
{
|
||||
// copy of the definitions from loader.hpp
|
||||
// we will delete them after improving the debuggers to use PLUGIN_MULTI.
|
||||
#define PLUGIN_SKIP nullptr
|
||||
#define PLUGIN_KEEP ((plugmod_t *)2)
|
||||
|
||||
if ( init_plugin() )
|
||||
{
|
||||
update_idd_registers();
|
||||
dbg = &debugger;
|
||||
plugin_inited = true;
|
||||
return PLUGIN_KEEP;
|
||||
}
|
||||
return PLUGIN_SKIP;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Terminate debugger plugin
|
||||
static void idaapi term(void)
|
||||
{
|
||||
if ( plugin_inited )
|
||||
{
|
||||
term_plugin();
|
||||
plugin_inited = false;
|
||||
}
|
||||
// we're being unloaded, clear the 'dbg' pointer if it's ours
|
||||
if ( dbg == &debugger )
|
||||
dbg = NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// The plugin method - usually is not used for debugger plugins
|
||||
static bool idaapi run(size_t arg)
|
||||
{
|
||||
#ifdef HAVE_PLUGIN_RUN
|
||||
plugin_run(int(arg));
|
||||
#else
|
||||
qnotused(arg);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// DEBUGGER DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#ifdef SET_DBG_OPTIONS
|
||||
# define S_SET_DBG_OPTIONS s_set_dbg_options
|
||||
#else
|
||||
# define S_SET_DBG_OPTIONS NULL
|
||||
# define SET_DBG_OPTIONS NULL
|
||||
#endif
|
||||
|
||||
#ifndef S_FILETYPE
|
||||
# define S_FILETYPE 0
|
||||
#endif
|
||||
|
||||
// arm has no single step mechanism
|
||||
// DBG_HAS_SET_RESUME_MODE must be set before init_debugger
|
||||
#if TARGET_PROCESSOR == PLFM_ARM
|
||||
# define S_DBG_HAS_SET_RESUME_MODE 0
|
||||
#else
|
||||
# define S_DBG_HAS_SET_RESUME_MODE DBG_HAS_SET_RESUME_MODE
|
||||
#endif
|
||||
|
||||
#ifndef DEBUGGER_RESMOD
|
||||
# define DEBUGGER_RESMOD 0
|
||||
#endif
|
||||
|
||||
debugger_t debugger =
|
||||
{
|
||||
IDD_INTERFACE_VERSION,
|
||||
DEBUGGER_NAME,
|
||||
DEBUGGER_ID,
|
||||
PROCESSOR_NAME,
|
||||
DEBUGGER_FLAGS, // flags
|
||||
DBG_HAS_ATTACH_PROCESS
|
||||
| DBG_HAS_REQUEST_PAUSE
|
||||
| DBG_HAS_SET_EXCEPTION_INFO
|
||||
| DBG_HAS_THREAD_SUSPEND
|
||||
| DBG_HAS_THREAD_CONTINUE
|
||||
| S_DBG_HAS_SET_RESUME_MODE
|
||||
| DBG_HAS_THREAD_GET_SREG_BASE
|
||||
| DBG_HAS_CHECK_BPT
|
||||
| DBG_HAS_REXEC, // flags2
|
||||
|
||||
REGISTER_CLASSES,
|
||||
REGISTER_CLASSES_DEFAULT,
|
||||
REGISTERS,
|
||||
REGISTERS_SIZE,
|
||||
|
||||
MEMORY_PAGE_SIZE,
|
||||
|
||||
bpt_code,
|
||||
sizeof(bpt_code),
|
||||
S_FILETYPE,
|
||||
DEBUGGER_RESMOD,
|
||||
|
||||
S_SET_DBG_OPTIONS,
|
||||
idd_notify,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_HIDE|PLUGIN_DBG, // plugin flags
|
||||
init, // initialize
|
||||
|
||||
term, // terminate. this pointer may be NULL.
|
||||
|
||||
run, // invoke plugin
|
||||
|
||||
comment, // long comment about the plugin
|
||||
// it could appear in the status line
|
||||
// or as a hint
|
||||
|
||||
comment, // multiline help about the plugin
|
||||
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
"" // the preferred hotkey to run the plugin
|
||||
};
|
||||
258
idasdk75/dbg/common_stub_impl.cpp
Normal file
258
idasdk75/dbg/common_stub_impl.cpp
Normal file
@@ -0,0 +1,258 @@
|
||||
//
|
||||
// This file is included from other files, do not directly compile it.
|
||||
// It contains the implementation of debugger plugin callback functions
|
||||
//
|
||||
|
||||
#include <err.h>
|
||||
#include <name.hpp>
|
||||
#include <expr.hpp>
|
||||
#include <segment.hpp>
|
||||
#include <typeinf.hpp>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//lint -esym(714, rebase_or_warn) not referenced
|
||||
int rebase_or_warn(ea_t base, ea_t new_base)
|
||||
{
|
||||
int code = rebase_program(new_base - base, MSF_FIXONCE);
|
||||
if ( code != MOVE_SEGM_OK )
|
||||
{
|
||||
msg("Failed to rebase program, error code %d\n", code);
|
||||
warning("IDA failed to rebase the program.\n"
|
||||
"Most likely it happened because of the debugger\n"
|
||||
"segments created to reflect the real memory state.\n\n"
|
||||
"Please stop the debugger and rebase the program manually.\n"
|
||||
"For that, please select the whole program and\n"
|
||||
"use Edit, Segments, Rebase program with delta 0x%08a",
|
||||
new_base - base);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void idaapi s_stopped_at_debug_event(thread_name_vec_t *thr_names, bool dlls_added)
|
||||
{
|
||||
// Let the debugger module populate the names
|
||||
g_dbgmod.dbg_stopped_at_debug_event(NULL, dlls_added, thr_names);
|
||||
if ( dlls_added )
|
||||
{
|
||||
#ifndef RPC_CLIENT
|
||||
// Pass the debug names to the kernel
|
||||
g_dbgmod.set_debug_names();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This code is compiled for local debuggers (like win32_user.plw)
|
||||
#ifndef RPC_CLIENT
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
AS_PRINTF(3,0) ssize_t dvmsg(int code, rpc_engine_t *, const char *format, va_list va)
|
||||
{
|
||||
if ( code == 0 )
|
||||
return vmsg(format, va);
|
||||
if ( code > 0 )
|
||||
vwarning(format, va);
|
||||
else
|
||||
verror(format, va);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
AS_PRINTF(2,0) void dmsg(rpc_engine_t *rpc, const char *format, va_list va)
|
||||
{
|
||||
dvmsg(0, rpc, format, va);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
AS_PRINTF(2,0) void derror(rpc_engine_t *rpc, const char *format, va_list va)
|
||||
{
|
||||
dvmsg(-1, rpc, format, va);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
AS_PRINTF(2,0) void dwarning(rpc_engine_t *rpc, const char *format, va_list va)
|
||||
{
|
||||
dvmsg(1, rpc, format, va);
|
||||
}
|
||||
|
||||
#endif // end of 'local debugger' code
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool lock_begin(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool lock_end(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void report_idc_error(
|
||||
rpc_engine_t *,
|
||||
ea_t ea,
|
||||
error_t code,
|
||||
ssize_t errval,
|
||||
const char *errprm)
|
||||
{
|
||||
// Copy errval/errprm to the locations expected by qstrerror()
|
||||
if ( errprm != NULL && errprm != get_error_string(0) )
|
||||
QPRM(1, errprm);
|
||||
else if ( code == eOS )
|
||||
errno = errval;
|
||||
else
|
||||
set_error_data(0, errval);
|
||||
|
||||
warning("AUTOHIDE NONE\n%a: %s", ea, qstrerror(code));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int for_all_debuggers(debmod_visitor_t &v)
|
||||
{
|
||||
return v.visit(&g_dbgmod);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi s_write_register(thid_t tid, int reg_idx, const regval_t *value, qstring *errbuf)
|
||||
{
|
||||
return g_dbgmod.dbg_write_register(tid, reg_idx, value, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi s_read_registers(thid_t tid, int clsmask, regval_t *values, qstring *errbuf)
|
||||
{
|
||||
return g_dbgmod.dbg_read_registers(tid, clsmask, values, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi s_update_bpts(
|
||||
int *nbpts,
|
||||
update_bpt_info_t *bpts,
|
||||
int nadd,
|
||||
int ndel,
|
||||
qstring *errbuf)
|
||||
{
|
||||
return g_dbgmod.dbg_update_bpts(nbpts, bpts, nadd, ndel, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void update_idd_registers(void)
|
||||
{
|
||||
size_t nregs = g_dbgmod.idaregs.nregs();
|
||||
if ( nregs > 0 )
|
||||
{
|
||||
// register classes
|
||||
debugger.regclasses = g_dbgmod.idaregs.regclasses();
|
||||
debugger.default_regclasses = 1; // TODO 1 is the general register set
|
||||
|
||||
// registers
|
||||
debugger.nregs = nregs;
|
||||
debugger.registers = g_dbgmod.idaregs.registers();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t s_init(uint32_t *flags2, qstring *errbuf)
|
||||
{
|
||||
g_dbgmod.debugger_flags = debugger.flags;
|
||||
drc_t retcode = g_dbgmod.dbg_init(flags2, errbuf);
|
||||
if ( retcode > DRC_NONE )
|
||||
update_idd_registers();
|
||||
return retcode;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static drc_t s_attach_process(
|
||||
pid_t process_id,
|
||||
int event_id,
|
||||
int flags,
|
||||
qstring *errbuf)
|
||||
{
|
||||
drc_t retcode = g_dbgmod.dbg_attach_process(process_id, event_id, flags, errbuf);
|
||||
if ( retcode > DRC_NONE )
|
||||
update_idd_registers();
|
||||
return retcode;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static drc_t s_start_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
qstring *errbuf)
|
||||
{
|
||||
drc_t retcode = g_dbgmod.dbg_start_process(path,
|
||||
args,
|
||||
startdir,
|
||||
flags,
|
||||
input_path,
|
||||
input_file_crc32,
|
||||
errbuf);
|
||||
if ( retcode > DRC_NONE )
|
||||
update_idd_registers();
|
||||
return retcode;
|
||||
}
|
||||
|
||||
#ifdef SET_DBG_OPTIONS
|
||||
//--------------------------------------------------------------------------
|
||||
// forward declaration
|
||||
const char *idaapi SET_DBG_OPTIONS(
|
||||
const char *keyword,
|
||||
int pri,
|
||||
int value_type,
|
||||
const void *value);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *idaapi s_set_dbg_options(
|
||||
const char *keyword,
|
||||
int pri,
|
||||
int value_type,
|
||||
const void *value)
|
||||
{
|
||||
const char *ret = SET_DBG_OPTIONS(keyword, pri, value_type, value);
|
||||
update_idd_registers();
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#ifdef REMOTE_DEBUGGER
|
||||
bool s_open_remote(const char *hostname, int port_number, const char *password, qstring *errbuf)
|
||||
{
|
||||
return g_dbgmod.open_remote(hostname, port_number, password, errbuf);
|
||||
}
|
||||
drc_t s_close_remote(void)
|
||||
{
|
||||
return g_dbgmod.close_remote();
|
||||
}
|
||||
#else
|
||||
bool s_open_remote(const char *, int, const char *, qstring *)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
drc_t s_close_remote(void)
|
||||
{
|
||||
return DRC_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Local debuggers must call setup_lowcnd_regfuncs() in order to handle
|
||||
// register read/write requests from low level bpts.
|
||||
void init_dbg_idcfuncs(bool init)
|
||||
{
|
||||
#if !defined(ENABLE_LOWCNDS) \
|
||||
|| defined(REMOTE_DEBUGGER) \
|
||||
|| DEBUGGER_ID == DEBUGGER_ID_X86_IA32_BOCHS
|
||||
qnotused(init);
|
||||
#else
|
||||
setup_lowcnd_regfuncs(init ? idc_get_reg_value : NULL,
|
||||
init ? idc_set_reg_value : NULL);
|
||||
#endif
|
||||
}
|
||||
57
idasdk75/dbg/dbg_pe_hlp.cpp
Normal file
57
idasdk75/dbg/dbg_pe_hlp.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#if defined(__NT__) && !defined(__X86__)
|
||||
//--------------------------------------------------------------------------
|
||||
static bool path_start_match(const char *s, const char *f)
|
||||
{
|
||||
if ( f == NULL || s == NULL || *f == 0 || *s == 0 )
|
||||
return false;
|
||||
if ( s == f )
|
||||
return true;
|
||||
qstring t1(s);
|
||||
qstring t2(f);
|
||||
size_t l1 = t1.length();
|
||||
size_t l2 = t2.length();
|
||||
t1.replace("\\", "/");
|
||||
t2.replace("\\", "/");
|
||||
if ( t1[l1-1] == '/' )
|
||||
--l1;
|
||||
if ( t2[l2-1] == '/' )
|
||||
--l2;
|
||||
if ( l1 > l2
|
||||
|| l1 < l2 && t2[l1] != '/' )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return memicmp(t1.c_str(), t2.c_str(), l1) == 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void replace_system32(char *path, size_t sz)
|
||||
{
|
||||
char spath[MAXSTR];
|
||||
spath[0] = 0;
|
||||
GetSystemDirectoryA(spath, sizeof(spath));
|
||||
if ( spath[0] == 0 || !path_start_match(spath, path) )
|
||||
return;
|
||||
char wpath[MAXSTR];
|
||||
wpath[0] = 0;
|
||||
GetSystemWow64Directory(wpath, sizeof(wpath));
|
||||
if ( wpath[0] == 0 || path_start_match(wpath, spath) )
|
||||
return;
|
||||
size_t len = strlen(wpath);
|
||||
if ( wpath[len-1] == '/' || wpath[len-1] == '\\' )
|
||||
wpath[len-1] = 0;
|
||||
len = strlen(spath);
|
||||
if ( spath[len-1] == '/' || spath[len-1] == '\\' )
|
||||
{
|
||||
--len;
|
||||
path[len] = 0;
|
||||
}
|
||||
qstring n;
|
||||
n.sprnt("%s%s", wpath, &path[len]);
|
||||
qstrncpy(path, n.c_str(), sz);
|
||||
}
|
||||
#else
|
||||
#define replace_system32(PATH, SZ) do {} while ( false )
|
||||
#endif
|
||||
|
||||
|
||||
246
idasdk75/dbg/dbg_rpc_client.cpp
Normal file
246
idasdk75/dbg/dbg_rpc_client.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
|
||||
// This file is included in the debugger stub that runs on the computer with IDA
|
||||
|
||||
#include <pro.h>
|
||||
#include <name.hpp>
|
||||
#include <diskio.hpp>
|
||||
|
||||
#include "dbg_rpc_client.h"
|
||||
#include "dbg_rpc_hlp.h"
|
||||
#include "debmod.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// check and send to the remote server the specified stub
|
||||
// do it only if its crc does not match the specified crc
|
||||
// this function runs on the local machine with ida interface
|
||||
static uchar *sync_stub(const char *fname, uint32 crc, size_t *psize)
|
||||
{
|
||||
bool complain = true;
|
||||
uchar *retval = NULL;
|
||||
char path[QMAXPATH];
|
||||
if ( getsysfile(path, sizeof(path), fname, NULL) != NULL )
|
||||
{
|
||||
linput_t *li = open_linput(path, false);
|
||||
if ( li != NULL )
|
||||
{
|
||||
int64 size = qlsize(li);
|
||||
if ( size > 0 )
|
||||
{
|
||||
bytevec_t buf;
|
||||
buf.resize(size);
|
||||
if ( qlread(li, buf.begin(), size) == size )
|
||||
{
|
||||
complain = false;
|
||||
if ( calc_crc32(0, buf.begin(), size) != crc )
|
||||
{
|
||||
*psize = size;
|
||||
retval = buf.extract();
|
||||
}
|
||||
else
|
||||
{
|
||||
msg("Kernel debugger stub is up to date...\n");
|
||||
*psize = 1; // signal ok
|
||||
}
|
||||
}
|
||||
}
|
||||
close_linput(li);
|
||||
}
|
||||
}
|
||||
if ( complain )
|
||||
warning("AUTOHIDE NONE\nCould not find/read debugger stub %s", fname);
|
||||
return retval;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
dbg_rpc_client_t::dbg_rpc_client_t(idarpc_stream_t *_irs)
|
||||
: dbg_rpc_engine_t(/*is_client=*/ true),
|
||||
client_irs(_irs)
|
||||
{
|
||||
pending_event.clear_all();
|
||||
verbose = false;
|
||||
recv_timeout = RECV_TIMEOUT_PERIOD;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void dbg_rpc_client_t::my_update_wait_dialog(
|
||||
const char *message,
|
||||
const rpc_packet_t *rp)
|
||||
{
|
||||
if ( send_request_data.wait_dialog_displayed )
|
||||
{
|
||||
if ( rp->code != send_request_data.code )
|
||||
replace_wait_box("%s", message);
|
||||
}
|
||||
else
|
||||
{
|
||||
show_wait_box("%s", message);
|
||||
send_request_data.wait_dialog_displayed = true;
|
||||
}
|
||||
send_request_data.code = rp->code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// requests received from the server.
|
||||
// here the client handles certain server -> client requests
|
||||
bytevec_t dbg_rpc_client_t::on_send_request_interrupt(const rpc_packet_t *rp)
|
||||
{
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
bytevec_t req = prepare_rpc_packet(RPC_OK);
|
||||
|
||||
switch ( rp->code )
|
||||
{
|
||||
// send_debug_names_to_ida() is thread safe
|
||||
case RPC_SET_DEBUG_NAMES:
|
||||
{
|
||||
my_update_wait_dialog("Downloading Symbols", rp);
|
||||
int qty = mmdsr.unpack_dd();
|
||||
ea_t *addrs = OPERATOR_NEW(ea_t, qty);
|
||||
char **names = OPERATOR_NEW(char *, qty);
|
||||
qstring name;
|
||||
ea_t old = 0;
|
||||
for ( int i=0; i < qty; i++ )
|
||||
{
|
||||
adiff_t o2 = mmdsr.unpack_ea64();
|
||||
if ( mmdsr.unpack_dd() )
|
||||
o2 = -o2;
|
||||
old += o2;
|
||||
addrs[i] = old;
|
||||
int oldlen = mmdsr.unpack_dd();
|
||||
QASSERT(1203, oldlen >= 0 && oldlen <= name.length());
|
||||
//keep the prefix
|
||||
name.resize(oldlen);
|
||||
if ( !mmdsr.unpack_str(&name) )
|
||||
INTERR(1294);
|
||||
names[i] = qstrdup(name.c_str());
|
||||
}
|
||||
int result = send_debug_names_to_ida(addrs, names, qty);
|
||||
verb(("set_debug_name(qty=%d) => %d\n", qty, result));
|
||||
req.pack_dd(result);
|
||||
for ( int i=0; i < qty; i++ )
|
||||
qfree(names[i]);
|
||||
delete [] addrs;
|
||||
delete [] names;
|
||||
}
|
||||
break;
|
||||
|
||||
// import_dll() is thread safe
|
||||
case RPC_IMPORT_DLL:
|
||||
{
|
||||
my_update_wait_dialog("Importing DLLs", rp);
|
||||
ea_t base = mmdsr.unpack_ea64();
|
||||
const char *path = mmdsr.unpack_str();
|
||||
int n = mmdsr.unpack_dd();
|
||||
const void *bytes = mmdsr.unpack_obj_inplace(n);
|
||||
bytevec_t uuid(bytes, n);
|
||||
int result = import_dll(import_request_t(base, path, uuid));
|
||||
verb(("import_dll(base=%a, path=%s) => %d\n", base, path, result));
|
||||
req.pack_dd(result);
|
||||
}
|
||||
break;
|
||||
|
||||
// send_debug_event_to_ida() is thread safe
|
||||
case RPC_HANDLE_DEBUG_EVENT:
|
||||
{
|
||||
debug_event_t ev;
|
||||
extract_debug_event(&ev, mmdsr);
|
||||
int rqflags = mmdsr.unpack_dd();
|
||||
int code = send_debug_event_to_ida(&ev, rqflags);
|
||||
req.pack_dd(code);
|
||||
}
|
||||
break;
|
||||
|
||||
// sync_stub() is thread safe
|
||||
case RPC_SYNC_STUB:
|
||||
{
|
||||
const char *fname = mmdsr.unpack_str();
|
||||
uint32 crc = mmdsr.unpack_dd();
|
||||
|
||||
// security problem: the debugger server should not be able to
|
||||
// read an arbitrary file on the local computer. therefore we completely
|
||||
// ignore the file name and use a hardcoded name.
|
||||
qnotused(fname);
|
||||
fname = "ida_kdstub.dll";
|
||||
|
||||
size_t size = 0;
|
||||
uchar *contents = sync_stub(fname, crc, &size);
|
||||
req.pack_dd((uint32)size);
|
||||
if ( contents != NULL )
|
||||
{
|
||||
req.append(contents, size);
|
||||
qfree(contents);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// msg/error/warning are thread safe
|
||||
case RPC_ERROR:
|
||||
case RPC_MSG:
|
||||
case RPC_WARNING:
|
||||
{
|
||||
const char *str = mmdsr.unpack_str();
|
||||
if ( *str != '\0' )
|
||||
{
|
||||
if ( rp->code == RPC_MSG )
|
||||
msg("%s", str);
|
||||
else if ( rp->code == RPC_ERROR )
|
||||
error("%s", str);
|
||||
else
|
||||
warning("%s", str);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// no external functions are called
|
||||
case RPC_EVENT:
|
||||
{
|
||||
extract_debug_event(&pending_event, mmdsr);
|
||||
has_pending_event = true;
|
||||
req = prepare_rpc_packet(RPC_EVOK);
|
||||
verbev(("got event, storing it and sending RPC_EVOK\n"));
|
||||
}
|
||||
break;
|
||||
|
||||
// i doubt that this code is used on the client side
|
||||
// ioctl_handler is NULL
|
||||
case RPC_IOCTL:
|
||||
{
|
||||
int code = handle_ioctl_packet(req, mmdsr.ptr, mmdsr.end);
|
||||
if ( code != RPC_OK )
|
||||
return prepare_rpc_packet((uchar)code);
|
||||
}
|
||||
break;
|
||||
|
||||
// report_idc_error() is thread safe
|
||||
case RPC_REPORT_IDC_ERROR:
|
||||
{
|
||||
ea_t ea = mmdsr.unpack_ea64();
|
||||
error_t code = mmdsr.unpack_dd();
|
||||
const char *errprm;
|
||||
ssize_t errval;
|
||||
if ( mmdsr.unpack_db() )
|
||||
{
|
||||
errprm = mmdsr.unpack_str();
|
||||
errval = (ssize_t)errprm;
|
||||
}
|
||||
else
|
||||
{
|
||||
errprm = NULL;
|
||||
errval = mmdsr.unpack_ea64();
|
||||
}
|
||||
report_idc_error(NULL, ea, code, errval, errprm);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return prepare_rpc_packet(RPC_UNK);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void dbg_rpc_client_t::on_send_request_end(const rpc_packet_t *)
|
||||
{
|
||||
if ( send_request_data.wait_dialog_displayed )
|
||||
hide_wait_box();
|
||||
send_request_data.reset();
|
||||
}
|
||||
35
idasdk75/dbg/dbg_rpc_client.h
Normal file
35
idasdk75/dbg/dbg_rpc_client.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __RPC_CLIENT__
|
||||
#define __RPC_CLIENT__
|
||||
|
||||
#include "dbg_rpc_engine.h"
|
||||
|
||||
class dbg_rpc_client_t: public dbg_rpc_engine_t
|
||||
{
|
||||
protected:
|
||||
debug_event_t pending_event;
|
||||
idarpc_stream_t *client_irs;
|
||||
bool verbose;
|
||||
|
||||
struct send_request_data_t
|
||||
{
|
||||
uchar code;
|
||||
bool wait_dialog_displayed;
|
||||
|
||||
send_request_data_t() { reset(); }
|
||||
void reset() { code = uchar(-1); wait_dialog_displayed = false; }
|
||||
};
|
||||
send_request_data_t send_request_data;
|
||||
|
||||
void my_update_wait_dialog(const char *message, const rpc_packet_t *rp);
|
||||
|
||||
virtual bytevec_t on_send_request_interrupt(const rpc_packet_t *rp) override;
|
||||
virtual void on_send_request_end(const rpc_packet_t *result) override;
|
||||
|
||||
public:
|
||||
dbg_rpc_client_t(idarpc_stream_t *irs);
|
||||
virtual ~dbg_rpc_client_t() {}
|
||||
|
||||
virtual idarpc_stream_t *get_irs() const override { return client_irs; }
|
||||
};
|
||||
|
||||
#endif
|
||||
97
idasdk75/dbg/dbg_rpc_engine.cpp
Normal file
97
idasdk75/dbg/dbg_rpc_engine.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
#include <network.hpp>
|
||||
|
||||
#include "dbg_rpc_engine.h"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
dbg_rpc_engine_t::dbg_rpc_engine_t(bool _is_client)
|
||||
: rpc_engine_t(_is_client),
|
||||
has_pending_event(false),
|
||||
poll_debug_events(false)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// sends a request and waits for a reply
|
||||
// may occasionally send another request based on the reply
|
||||
rpc_packet_t *dbg_rpc_engine_t::send_request_and_receive_reply(bytevec_t &req, int flags)
|
||||
{
|
||||
bool displayed = false;
|
||||
rpc_packet_t *result = NULL;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
if ( displayed && user_cancelled() )
|
||||
req = prepare_rpc_packet(RPC_CANCELLED);
|
||||
|
||||
if ( !req.empty() )
|
||||
{
|
||||
int code = send_data(req);
|
||||
if ( code != 0 || (flags & PREQ_GET_EVENT) != 0 )
|
||||
break;
|
||||
|
||||
rpc_packet_t *reqp = (rpc_packet_t *)req.begin();
|
||||
if ( reqp->code == RPC_ERROR )
|
||||
qexit(1); // sent error packet, may die now
|
||||
}
|
||||
|
||||
rpc_packet_t *rp = recv_packet();
|
||||
if ( rp == NULL )
|
||||
break;
|
||||
|
||||
switch ( rp->code )
|
||||
{
|
||||
case RPC_UNK:
|
||||
dwarning("rpc: remote did not understand our request");
|
||||
goto FAILURE;
|
||||
case RPC_MEM:
|
||||
dwarning("rpc: no remote memory");
|
||||
goto FAILURE;
|
||||
case RPC_CANCELLED:
|
||||
msg("rpc: user cancelled the operation\n");
|
||||
goto FAILURE;
|
||||
case RPC_OK:
|
||||
result = rp;
|
||||
goto END;
|
||||
default:
|
||||
// other replies are passed to the handler
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !logged_in )
|
||||
{
|
||||
lprintf("Exploit packet has been detected and ignored\n");
|
||||
FAILURE:
|
||||
qfree(rp);
|
||||
break;
|
||||
}
|
||||
//handle actual command in the request
|
||||
//FIXME: use a better function name
|
||||
req = on_send_request_interrupt(rp);
|
||||
qfree(rp);
|
||||
}
|
||||
|
||||
END:
|
||||
on_send_request_end(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int dbg_rpc_engine_t::_send_request_get_int_result(
|
||||
bytevec_t &req,
|
||||
int failure_code,
|
||||
qstring *errbuf)
|
||||
{
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return failure_code;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
int rc = mmdsr.unpack_dd();
|
||||
if ( rc < 0 && errbuf != NULL )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
|
||||
qfree(rp);
|
||||
return rc;
|
||||
}
|
||||
37
idasdk75/dbg/dbg_rpc_engine.h
Normal file
37
idasdk75/dbg/dbg_rpc_engine.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef __DBG_RPC_ENGINE__
|
||||
#define __DBG_RPC_ENGINE__
|
||||
|
||||
#include <pro.h>
|
||||
#include <idd.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
class dbg_rpc_engine_t : public rpc_engine_t
|
||||
{
|
||||
public:
|
||||
bool has_pending_event;
|
||||
bool poll_debug_events;
|
||||
|
||||
dbg_rpc_engine_t(bool _is_client);
|
||||
|
||||
#define PREQ_MUST_LOGIN 0x01
|
||||
#define PREQ_GET_EVENT 0x02
|
||||
rpc_packet_t *send_request_and_receive_reply(bytevec_t &pkt, int flags);
|
||||
|
||||
virtual rpc_packet_t *send_request_and_receive_reply(bytevec_t &pkt) override
|
||||
{
|
||||
return send_request_and_receive_reply(pkt, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
int send_request_get_long_result(bytevec_t &pkt) { return _send_request_get_int_result(pkt, -1, NULL); }
|
||||
drc_t send_request_get_drc_result(bytevec_t &pkt, qstring *errbuf) { return drc_t(_send_request_get_int_result(pkt, DRC_NETERR, errbuf)); }
|
||||
|
||||
virtual bytevec_t on_send_request_interrupt(const rpc_packet_t *rp) = 0;
|
||||
virtual void on_send_request_end(const rpc_packet_t *result) newapi { qnotused(result); }
|
||||
|
||||
private:
|
||||
int _send_request_get_int_result(bytevec_t &pkt, int failure_code, qstring *errbuf);
|
||||
};
|
||||
|
||||
#endif // __DBG_RPC_ENGINE__
|
||||
1418
idasdk75/dbg/dbg_rpc_handler.cpp
Normal file
1418
idasdk75/dbg/dbg_rpc_handler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
65
idasdk75/dbg/dbg_rpc_handler.h
Normal file
65
idasdk75/dbg/dbg_rpc_handler.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef __DBG_RPC_HANDLER__
|
||||
#define __DBG_RPC_HANDLER__
|
||||
|
||||
#include <network.hpp>
|
||||
|
||||
#include "dbg_rpc_engine.h"
|
||||
#define MIN_SERVER_IOCTL 0x01000000
|
||||
|
||||
#include "debmod.h"
|
||||
|
||||
struct dbgsrv_dispatcher_t;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
class dbg_rpc_handler_t
|
||||
: public client_handler_t,
|
||||
public dbg_rpc_engine_t
|
||||
{
|
||||
public:
|
||||
dbg_rpc_handler_t(idarpc_stream_t *_irs, dbgsrv_dispatcher_t *_dispatcher);
|
||||
virtual ~dbg_rpc_handler_t();
|
||||
|
||||
virtual bool handle() override;
|
||||
virtual void shutdown_gracefully(int signum) override;
|
||||
|
||||
private:
|
||||
debug_event_t ev;
|
||||
debug_event_t pending_event;
|
||||
debmod_t *dbg_mod;
|
||||
dbgsrv_dispatcher_t *dispatcher;
|
||||
DECLARE_UNCOPYABLE(dbg_rpc_handler_t);
|
||||
void append_start_or_attach(bytevec_t &req, drc_t drc, const qstring &errbuf) const;
|
||||
int poll_events(int timeout_ms);
|
||||
void extract_path_and_arch(
|
||||
const char **out_file_path,
|
||||
int *out_arch,
|
||||
int *out_is_be,
|
||||
memory_deserializer_t &mmdsr) const;
|
||||
int on_recv_packet_progress(bool *performed);
|
||||
|
||||
protected:
|
||||
void rpc_update_lowcnds(bytevec_t &rcmd, memory_deserializer_t &mmdsr);
|
||||
int rpc_update_bpts(bytevec_t &rcmd, memory_deserializer_t &mmdsr);
|
||||
drc_t rpc_attach_process(qstring *errbuf, memory_deserializer_t &mmdsr);
|
||||
bool check_broken_connection(pid_t pid);
|
||||
virtual int handle_server_ioctl(int fn, void **out, ssize_t *outsz, memory_deserializer_t &mmdsr) newapi;
|
||||
virtual bytevec_t on_send_request_interrupt(const rpc_packet_t *rp) override;
|
||||
|
||||
public:
|
||||
void set_debugger_instance(debmod_t *instance);
|
||||
debmod_t *get_debugger_instance();
|
||||
void prepare_broken_connection();
|
||||
bool rpc_sync_stub(const char *server_stub_name, const char *ida_stub_name);
|
||||
int send_debug_names_to_ida(ea_t *ea, const char *const *names, int qty);
|
||||
int send_debug_event_to_ida(const debug_event_t *ev, int rqflags);
|
||||
void process_import_requests(const import_infos_t &infos);
|
||||
virtual idarpc_stream_t *get_irs() const override { return irs; }
|
||||
virtual bool get_broken_connection(void) override;
|
||||
virtual void set_broken_connection(void) override;
|
||||
int kill_process(void); // returns 0-ok, >0-failed, after that many seconds
|
||||
};
|
||||
|
||||
// defined only in the single threaded version of the server:
|
||||
extern dbg_rpc_handler_t *g_global_server;
|
||||
|
||||
#endif // __DBG_RPC_HANDLER__
|
||||
70
idasdk75/dbg/dbg_rpc_handler_ioctls.h
Normal file
70
idasdk75/dbg/dbg_rpc_handler_ioctls.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef __DBG_RPC_HANDLER_IOCTLS__
|
||||
#define __DBG_RPC_HANDLER_IOCTLS__
|
||||
|
||||
// Note: the dbg_rpc_handler_t implementation will consider all
|
||||
// IOCTL IDs >= 0x01000000 as being server IOCTLs, and those will
|
||||
// consequently *not* be passed to the debugger module.
|
||||
#define MIN_SERVER_IOCTL 0x01000000
|
||||
|
||||
#define DWARF_RPCSRV_IOCTL_OK 0
|
||||
#define DWARF_RPCSRV_IOCTL_ERROR -1
|
||||
|
||||
enum rpcsrv_ioctl_t
|
||||
{
|
||||
// Get DWARF sections information.
|
||||
//
|
||||
// client->server
|
||||
// (unpacked) char * : file_path (on the server's disk.)
|
||||
// (packed) uint32 : processor ID (as in: ph.id)
|
||||
// server->client
|
||||
// (unpacked) byte : DWARF info found
|
||||
// (packed) uint32 : is_64 (0 - no, !=0 - yes)
|
||||
// (packed) uint32 : is_msb (0 - no, !=0 - yes)
|
||||
// (packed) uint64 : declared load address
|
||||
// (packed) uint32 : number of DWARF section infos.
|
||||
// (packed) sec info : DWARF section info, N times.
|
||||
// Returns: 0 - ok
|
||||
// !=0 - error (text in output buffer.)
|
||||
//
|
||||
// The structure of a "sec info" is:
|
||||
// (packed) uint64 address_in_memory
|
||||
// (packed) uint64 size (in bytes)
|
||||
// (packed) uint16 section_index
|
||||
// (unpacked) char * section_name
|
||||
rpcsrv_ioctl_dwarf_secinfo = MIN_SERVER_IOCTL + 1,
|
||||
|
||||
// Get DWARF section data.
|
||||
//
|
||||
// client->server
|
||||
// (unpacked) char * : file_path (on the server's disk.)
|
||||
// (packed) uint32 : processor ID (as in: ph.id)
|
||||
// (packed) uint16 : DWARF section index (as returned by 'rpcsrv_ioctl_dwarf_secinfo')
|
||||
// server->client
|
||||
// (unpacked) byte * : DWARF section data.
|
||||
// Returns: 0 - ok
|
||||
// !=0 - error
|
||||
rpcsrv_ioctl_dwarf_secdata,
|
||||
|
||||
#if defined(TESTABLE_BUILD)
|
||||
// Set path to look for ELF/DWARF companion files, per-PID
|
||||
//
|
||||
// This is strictly meant for testing, where tests can store
|
||||
// files in unusual places on the leasing debug server's volume.
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : the PID
|
||||
// (unpacked) char * : directory path (on the server's disk.)
|
||||
// server->client
|
||||
// Nothing
|
||||
// Returns: 0 - ok
|
||||
// != 0 - error
|
||||
rpcsrv_ioctl_set_elf_debug_file_directory_for_pid = 2 * MIN_SERVER_IOCTL + 1,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(TESTABLE_BUILD) && defined(__LINUX__)
|
||||
void set_elf_debug_file_directory_for_pid(int pid, const char *path);
|
||||
const char *get_elf_debug_file_directory_for_pid(int pid);
|
||||
#endif
|
||||
|
||||
#endif // __DBG_RPC_HANDLER_IOCTLS__
|
||||
367
idasdk75/dbg/dbg_rpc_hlp.cpp
Normal file
367
idasdk75/dbg/dbg_rpc_hlp.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
|
||||
#include <segment.hpp>
|
||||
#include <typeinf.hpp>
|
||||
|
||||
#include "dbg_rpc_hlp.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_memory_info(bytevec_t &s, const memory_info_t *meminf)
|
||||
{
|
||||
s.pack_ea64(meminf->sbase);
|
||||
s.pack_ea64(meminf->start_ea - (meminf->sbase << 4));
|
||||
s.pack_ea64(meminf->size());
|
||||
s.pack_dd(meminf->perm | (meminf->bitness<<4));
|
||||
s.pack_str(meminf->name.c_str());
|
||||
s.pack_str(meminf->sclass.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_memory_info(memory_info_t *meminf, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
meminf->sbase = mmdsr.unpack_ea64();
|
||||
meminf->start_ea = ea_t(meminf->sbase << 4) + mmdsr.unpack_ea64();
|
||||
meminf->end_ea = meminf->start_ea + mmdsr.unpack_ea64();
|
||||
int v = mmdsr.unpack_dd();
|
||||
meminf->perm = uchar(v) & SEGPERM_MAXVAL;
|
||||
meminf->bitness = uchar(v>>4);
|
||||
meminf->name = mmdsr.unpack_str();
|
||||
meminf->sclass = mmdsr.unpack_str();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_scattered_segm(bytevec_t &s, const scattered_segm_t *ss)
|
||||
{
|
||||
s.pack_ea64(ss->start_ea);
|
||||
s.pack_ea64(ss->end_ea);
|
||||
s.pack_str(ss->name.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_scattered_segm(scattered_segm_t *ss, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
ss->start_ea = mmdsr.unpack_ea64();
|
||||
ss->end_ea = mmdsr.unpack_ea64();
|
||||
ss->name = mmdsr.unpack_str();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_process_info_vec(bytevec_t &s, const procinfo_vec_t *procs)
|
||||
{
|
||||
size_t size = procs->size();
|
||||
s.pack_dd(size);
|
||||
for ( size_t i = 0; i < size; i++ )
|
||||
{
|
||||
const process_info_t &pi = procs->at(i);
|
||||
s.pack_dd(pi.pid);
|
||||
s.pack_str(pi.name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_process_info_vec(procinfo_vec_t *procs, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
size_t size = mmdsr.unpack_dd();
|
||||
for ( size_t i = 0; i < size; i++ )
|
||||
{
|
||||
process_info_t &pi = procs->push_back();
|
||||
pi.pid = mmdsr.unpack_dd();
|
||||
pi.name = mmdsr.unpack_str();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_module_info(bytevec_t &s, const modinfo_t *modinf)
|
||||
{
|
||||
s.pack_str(modinf->name);
|
||||
s.pack_ea64(modinf->base);
|
||||
s.pack_ea64(modinf->size);
|
||||
s.pack_ea64(modinf->rebase_to);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_module_info(modinfo_t *modinf, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
modinf->name = mmdsr.unpack_str();
|
||||
modinf->base = mmdsr.unpack_ea64();
|
||||
modinf->size = mmdsr.unpack_ea64();
|
||||
modinf->rebase_to = mmdsr.unpack_ea64();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_exception(bytevec_t &s, const excinfo_t *e)
|
||||
{
|
||||
s.pack_dd(e->code);
|
||||
s.pack_dd(e->can_cont);
|
||||
s.pack_ea64(e->ea);
|
||||
s.pack_str(e->info);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_exception(excinfo_t *exc, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
exc->code = mmdsr.unpack_dd();
|
||||
exc->can_cont = mmdsr.unpack_dd() != 0;
|
||||
exc->ea = mmdsr.unpack_ea64();
|
||||
exc->info = mmdsr.unpack_str();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_debug_event(debug_event_t *ev, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
ev->set_eid(event_id_t(mmdsr.unpack_dd()));
|
||||
ev->pid = mmdsr.unpack_dd();
|
||||
ev->tid = mmdsr.unpack_dd();
|
||||
ev->ea = mmdsr.unpack_ea64();
|
||||
ev->handled = mmdsr.unpack_dd() != 0;
|
||||
switch ( ev->eid() )
|
||||
{
|
||||
case NO_EVENT: // Not an interesting event
|
||||
case STEP: // One instruction executed
|
||||
case PROCESS_DETACHED: // Detached from process
|
||||
default:
|
||||
break;
|
||||
case PROCESS_STARTED: // New process started
|
||||
case PROCESS_ATTACHED: // Attached to running process
|
||||
case LIB_LOADED: // New library loaded
|
||||
extract_module_info(&ev->modinfo(), mmdsr);
|
||||
break;
|
||||
case PROCESS_EXITED: // Process stopped
|
||||
case THREAD_EXITED: // Thread stopped
|
||||
ev->exit_code() = mmdsr.unpack_dd();
|
||||
break;
|
||||
case BREAKPOINT: // Breakpoint reached
|
||||
extract_breakpoint(&ev->bpt(), mmdsr);
|
||||
break;
|
||||
case EXCEPTION: // Exception
|
||||
extract_exception(&ev->exc(), mmdsr);
|
||||
break;
|
||||
case THREAD_STARTED: // New thread started
|
||||
case LIB_UNLOADED: // Library unloaded
|
||||
case INFORMATION: // User-defined information
|
||||
ev->info() = mmdsr.unpack_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_debug_event(bytevec_t &s, const debug_event_t *ev)
|
||||
{
|
||||
s.pack_dd(ev->eid());
|
||||
s.pack_dd(ev->pid);
|
||||
s.pack_dd(ev->tid);
|
||||
s.pack_ea64(ev->ea);
|
||||
s.pack_dd(ev->handled);
|
||||
switch ( ev->eid() )
|
||||
{
|
||||
case NO_EVENT: // Not an interesting event
|
||||
case STEP: // One instruction executed
|
||||
case PROCESS_DETACHED: // Detached from process
|
||||
default:
|
||||
break;
|
||||
case PROCESS_STARTED: // New process started
|
||||
case PROCESS_ATTACHED: // Attached to running process
|
||||
case LIB_LOADED: // New library loaded
|
||||
append_module_info(s, &ev->modinfo());
|
||||
break;
|
||||
case PROCESS_EXITED: // Process stopped
|
||||
case THREAD_EXITED: // Thread stopped
|
||||
s.pack_dd(ev->exit_code());
|
||||
break;
|
||||
case BREAKPOINT: // Breakpoint reached
|
||||
append_breakpoint(s, &ev->bpt());
|
||||
break;
|
||||
case EXCEPTION: // Exception
|
||||
append_exception(s, &ev->exc());
|
||||
break;
|
||||
case THREAD_STARTED: // New thread started
|
||||
case LIB_UNLOADED: // Library unloaded
|
||||
case INFORMATION: // User-defined information
|
||||
s.pack_str(ev->info());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
exception_info_t *extract_exception_info(int qty, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
exception_info_t *extable = NULL;
|
||||
if ( qty > 0 )
|
||||
{
|
||||
extable = OPERATOR_NEW(exception_info_t, qty);
|
||||
for ( int i=0; i < qty; i++ )
|
||||
{
|
||||
extable[i].code = mmdsr.unpack_dd();
|
||||
extable[i].flags = mmdsr.unpack_dd();
|
||||
extable[i].name = mmdsr.unpack_str();
|
||||
extable[i].desc = mmdsr.unpack_str();
|
||||
}
|
||||
}
|
||||
return extable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_exception_info(bytevec_t &s, const exception_info_t *table, int qty)
|
||||
{
|
||||
for ( int i=0; i < qty; i++ )
|
||||
{
|
||||
s.pack_dd(table[i].code);
|
||||
s.pack_dd(table[i].flags);
|
||||
s.pack_str(table[i].name.c_str());
|
||||
s.pack_str(table[i].desc.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_call_stack(call_stack_t *trace, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
int n = mmdsr.unpack_dd();
|
||||
trace->resize(n);
|
||||
for ( int i=0; i < n; i++ )
|
||||
{
|
||||
call_stack_info_t &ci = (*trace)[i];
|
||||
ci.callea = mmdsr.unpack_ea64();
|
||||
ci.funcea = mmdsr.unpack_ea64();
|
||||
ci.fp = mmdsr.unpack_ea64();
|
||||
ci.funcok = mmdsr.unpack_dd() != 0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_call_stack(bytevec_t &s, const call_stack_t &trace)
|
||||
{
|
||||
int n = trace.size();
|
||||
s.pack_dd(n);
|
||||
for ( int i=0; i < n; i++ )
|
||||
{
|
||||
const call_stack_info_t &ci = trace[i];
|
||||
s.pack_ea64(ci.callea);
|
||||
s.pack_ea64(ci.funcea);
|
||||
s.pack_ea64(ci.fp);
|
||||
s.pack_dd(ci.funcok);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_regobjs(
|
||||
regobjs_t *regargs,
|
||||
bool with_values,
|
||||
memory_deserializer_t &mmdsr)
|
||||
{
|
||||
int n = mmdsr.unpack_dd();
|
||||
regargs->resize(n);
|
||||
for ( int i=0; i < n; i++ )
|
||||
{
|
||||
regobj_t &ro = (*regargs)[i];
|
||||
ro.regidx = mmdsr.unpack_dd();
|
||||
int size = mmdsr.unpack_dd();
|
||||
ro.value.resize(size);
|
||||
if ( with_values )
|
||||
{
|
||||
ro.relocate = mmdsr.unpack_dd();
|
||||
mmdsr.unpack_obj(ro.value.begin(), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void extract_relobj(relobj_t *stkargs, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
int n = mmdsr.unpack_dd();
|
||||
stkargs->resize(n);
|
||||
mmdsr.unpack_obj(stkargs->begin(), n);
|
||||
|
||||
stkargs->base = mmdsr.unpack_ea64();
|
||||
|
||||
n = mmdsr.unpack_dd();
|
||||
stkargs->ri.resize(n);
|
||||
mmdsr.unpack_obj(stkargs->ri.begin(), n);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_appcall(
|
||||
regobjs_t *regargs,
|
||||
relobj_t *stkargs,
|
||||
regobjs_t *retregs,
|
||||
memory_deserializer_t &mmdsr)
|
||||
{
|
||||
extract_regobjs(regargs, true, mmdsr);
|
||||
extract_relobj(stkargs, mmdsr);
|
||||
if ( retregs != NULL )
|
||||
extract_regobjs(retregs, false, mmdsr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_regobjs(bytevec_t &s, const regobjs_t ®args, bool with_values)
|
||||
{
|
||||
s.pack_dd(regargs.size());
|
||||
for ( size_t i=0; i < regargs.size(); i++ )
|
||||
{
|
||||
const regobj_t &ro = regargs[i];
|
||||
s.pack_dd(ro.regidx);
|
||||
s.pack_dd(ro.value.size());
|
||||
if ( with_values )
|
||||
{
|
||||
s.pack_dd(ro.relocate);
|
||||
s.append(ro.value.begin(), ro.value.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void append_relobj(bytevec_t &s, const relobj_t &stkargs)
|
||||
{
|
||||
s.pack_buf(stkargs.begin(), stkargs.size());
|
||||
s.pack_ea64(stkargs.base);
|
||||
s.pack_buf(stkargs.ri.begin(), stkargs.ri.size());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_appcall(
|
||||
bytevec_t &s,
|
||||
const regobjs_t ®args,
|
||||
const relobj_t &stkargs,
|
||||
const regobjs_t *retregs)
|
||||
{
|
||||
append_regobjs(s, regargs, true);
|
||||
append_relobj(s, stkargs);
|
||||
if ( retregs != NULL )
|
||||
append_regobjs(s, *retregs, false);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_regvals(bytevec_t &s, const regval_t *values, int n, const uchar *regmap)
|
||||
{
|
||||
for ( int i=0; i < n; i++ )
|
||||
if ( regmap == NULL || test_bit(regmap, i) )
|
||||
append_regval(s, values[i]);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_debapp_attrs(debapp_attrs_t *attrs, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
attrs->addrsize = mmdsr.unpack_dd();
|
||||
attrs->platform = mmdsr.unpack_str();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_debapp_attrs(bytevec_t &s, const debapp_attrs_t &attrs)
|
||||
{
|
||||
s.pack_dd(attrs.addrsize);
|
||||
s.pack_str(attrs.platform.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void extract_dynamic_register_set(
|
||||
dynamic_register_set_t *idaregs,
|
||||
memory_deserializer_t &mmdsr)
|
||||
{
|
||||
deserialize_dynamic_register_set(idaregs, mmdsr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void append_dynamic_register_set(
|
||||
bytevec_t &s,
|
||||
dynamic_register_set_t &idaregs)
|
||||
{
|
||||
serialize_dynamic_register_set(&s, idaregs);
|
||||
}
|
||||
80
idasdk75/dbg/dbg_rpc_hlp.h
Normal file
80
idasdk75/dbg/dbg_rpc_hlp.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef __DBG_RPC_HLP__
|
||||
#define __DBG_RPC_HLP__
|
||||
|
||||
#include <pro.h>
|
||||
#include <range.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
void append_regvals(bytevec_t &s, const regval_t *values, int n, const uchar *regmap);
|
||||
|
||||
void append_debug_event(bytevec_t &s, const debug_event_t *ev);
|
||||
void extract_debug_event(debug_event_t *ev, memory_deserializer_t &mmdsr);
|
||||
|
||||
void extract_exception(excinfo_t *exc, memory_deserializer_t &mmdsr);
|
||||
void append_exception(bytevec_t &s, const excinfo_t *e);
|
||||
|
||||
inline void append_breakpoint(bytevec_t &s, const bptaddr_t *info)
|
||||
{
|
||||
s.pack_ea64(info->hea);
|
||||
s.pack_ea64(info->kea);
|
||||
}
|
||||
inline void extract_breakpoint(bptaddr_t *info, memory_deserializer_t &mmdsr)
|
||||
{
|
||||
info->hea = mmdsr.unpack_ea64();
|
||||
info->kea = mmdsr.unpack_ea64();
|
||||
}
|
||||
void extract_module_info(modinfo_t *info, memory_deserializer_t &mmdsr);
|
||||
void append_module_info(bytevec_t &s, const modinfo_t *info);
|
||||
void extract_process_info_vec(procinfo_vec_t *procs, memory_deserializer_t &mmdsr);
|
||||
void append_process_info_vec(bytevec_t &s, const procinfo_vec_t *procs);
|
||||
|
||||
void extract_call_stack(call_stack_t *trace, memory_deserializer_t &mmdsr);
|
||||
void append_call_stack(bytevec_t &s, const call_stack_t &trace);
|
||||
|
||||
void extract_regobjs(regobjs_t *regargs, bool with_values, memory_deserializer_t &mmdsr);
|
||||
void append_regobjs(bytevec_t &s, const regobjs_t ®args, bool with_values);
|
||||
|
||||
void extract_appcall(
|
||||
regobjs_t *regargs,
|
||||
relobj_t *stkargs,
|
||||
regobjs_t *retregs,
|
||||
memory_deserializer_t &mmdsr);
|
||||
|
||||
void append_appcall(
|
||||
bytevec_t &s,
|
||||
const regobjs_t ®args,
|
||||
const relobj_t &stkargs,
|
||||
const regobjs_t *retregs);
|
||||
|
||||
void extract_debapp_attrs(
|
||||
debapp_attrs_t *attrs,
|
||||
memory_deserializer_t &mmdsr);
|
||||
void append_debapp_attrs(bytevec_t &s, const debapp_attrs_t &attrs);
|
||||
|
||||
void extract_dynamic_register_set(
|
||||
dynamic_register_set_t *idaregs,
|
||||
memory_deserializer_t &mmdsr);
|
||||
void append_dynamic_register_set(
|
||||
bytevec_t &s,
|
||||
dynamic_register_set_t &idaregs);
|
||||
|
||||
|
||||
inline void append_type(bytevec_t &s, const type_t *str)
|
||||
{
|
||||
s.pack_str((char *)str);
|
||||
}
|
||||
void append_type(bytevec_t &s, const tinfo_t &tif);
|
||||
void extract_type(tinfo_t *tif, memory_deserializer_t &mmdsr);
|
||||
|
||||
void extract_memory_info(memory_info_t *info, memory_deserializer_t &mmdsr);
|
||||
void append_memory_info(bytevec_t &s, const memory_info_t *info);
|
||||
|
||||
void extract_scattered_segm(scattered_segm_t *ss, memory_deserializer_t &mmdsr);
|
||||
void append_scattered_segm(bytevec_t &s, const scattered_segm_t *ss);
|
||||
|
||||
void append_exception_info(bytevec_t &s, const exception_info_t *table, int qty);
|
||||
exception_info_t *extract_exception_info(int qty, memory_deserializer_t &mmdsr);
|
||||
|
||||
|
||||
#endif // __DBG_RPC_HLP__
|
||||
19
idasdk75/dbg/deb_arm.hpp
Normal file
19
idasdk75/dbg/deb_arm.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef __DEB_ARM__
|
||||
#define __DEB_ARM__
|
||||
|
||||
#include <ua.hpp>
|
||||
#include <idd.hpp>
|
||||
|
||||
#define MEMORY_PAGE_SIZE 0x1000
|
||||
#define ARM_BPT_CODE { 0xF0, 0x01, 0xF0, 0xE7 } // und #10
|
||||
#define AARCH64_BPT_CODE { 0x00, 0x00, 0x20, 0xD4 } // brk #0
|
||||
|
||||
#define ARM_BPT_SIZE 4 // size of BPT instruction
|
||||
|
||||
#define ARM_T 20 // number of virtual T segment register in IDA
|
||||
// it controls thumb/arm mode.
|
||||
|
||||
int is_arm_valid_bpt(bpttype_t type, ea_t ea, int len);
|
||||
|
||||
#endif
|
||||
|
||||
47
idasdk75/dbg/deb_pc.hpp
Normal file
47
idasdk75/dbg/deb_pc.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef __DEB_PC__
|
||||
#define __DEB_PC__
|
||||
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <idd.hpp>
|
||||
|
||||
#define MEMORY_PAGE_SIZE 0x1000
|
||||
#define X86_BPT_CODE { 0xCC }
|
||||
#define MAX_BPT 4 // maximal number of hardware breakpoints
|
||||
#define X86_BPT_SIZE 1 // size of 0xCC instruction
|
||||
#define EFLAGS_TRAP_FLAG 0x00000100
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi x86_read_registers(thid_t thread_id, int clsmask, regval_t *values, qstring *errbuf);
|
||||
drc_t idaapi x86_write_register(thid_t thread_id, int regidx, const regval_t *value, qstring *errbuf);
|
||||
int is_x86_valid_bpt(bpttype_t type, ea_t ea, int len);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline int check_x86_hwbpt(bpttype_t type, ea_t ea, int len)
|
||||
{
|
||||
if ( type != BPT_RDWR // type is good?
|
||||
&& type != BPT_WRITE
|
||||
&& type != BPT_EXEC )
|
||||
{
|
||||
return BPT_BAD_TYPE;
|
||||
}
|
||||
|
||||
if ( len != 1 // is length good?
|
||||
&& (type == BPT_EXEC // instruction hardware breakpoint only accepts the len of one byte
|
||||
|| (len != 2 && len != 4
|
||||
#ifndef __X86__
|
||||
&& len != 8
|
||||
#endif
|
||||
)) )
|
||||
{
|
||||
return BPT_BAD_LEN;
|
||||
}
|
||||
|
||||
if ( (ea & (len-1)) != 0 ) // is alignment good?
|
||||
return BPT_BAD_ALIGN;
|
||||
|
||||
return BPT_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
1329
idasdk75/dbg/debmod.cpp
Normal file
1329
idasdk75/dbg/debmod.cpp
Normal file
File diff suppressed because it is too large
Load Diff
741
idasdk75/dbg/debmod.h
Normal file
741
idasdk75/dbg/debmod.h
Normal file
@@ -0,0 +1,741 @@
|
||||
#ifndef __DEBUGGER_MODULE__
|
||||
#define __DEBUGGER_MODULE__
|
||||
|
||||
//
|
||||
//
|
||||
// This is the base debmod_t class definition
|
||||
// From this class all debugger code must inherite and specialize
|
||||
//
|
||||
// Some OS specific functions must be implemented:
|
||||
// bool init_subsystem();
|
||||
// bool term_subsystem();
|
||||
// debmod_t *create_debug_session(void *);
|
||||
// int create_thread(thread_cb_t thread_cb, void *context);
|
||||
//
|
||||
|
||||
#include <map>
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <pro.h>
|
||||
#include <idd.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
extern debugger_t debugger;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct name_info_t
|
||||
{
|
||||
eavec_t addrs;
|
||||
qvector<char *> names;
|
||||
void clear(void)
|
||||
{
|
||||
addrs.clear();
|
||||
names.clear();
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Extended process info
|
||||
struct ext_process_info_t : public process_info_t
|
||||
{
|
||||
int addrsize; // process bitness 32bit - 4, 64bit - 8, 0 - unknown
|
||||
qstring ext_name; // human-readable name (e.g. with command line agrs)
|
||||
void copy_to(process_info_t *dst)
|
||||
{
|
||||
dst->pid = pid;
|
||||
dst->name = ext_name.empty() ? name : ext_name;
|
||||
}
|
||||
};
|
||||
typedef qvector<ext_process_info_t> procvec_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Very simple class to store pending events
|
||||
enum queue_pos_t
|
||||
{
|
||||
IN_FRONT,
|
||||
IN_BACK
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct pagebpt_data_t
|
||||
{
|
||||
ea_t ea; // address of the bpt as specified by the user
|
||||
ea_t page_ea; // real address of the bpt as written to the process
|
||||
int user_len; // breakpoint length as specified by the user
|
||||
int aligned_len; // breakpoint length aligned to the page size
|
||||
int real_len; // real length of the breakpoint as written to the process
|
||||
uint32 old_prot; // old page protections (before writing the bpt to the process)
|
||||
// if 0, the bpt has not been written to the process yet.
|
||||
uint32 new_prot; // new page protections (when the bpt is active)
|
||||
bpttype_t type; // breakpoint type
|
||||
};
|
||||
|
||||
// Information about page breakpoints is stored in this data structure.
|
||||
// The map is indexed by the page start address (not the address specified
|
||||
// by the user!)
|
||||
typedef std::map<ea_t, pagebpt_data_t> page_bpts_t; // page_ea -> bpt info
|
||||
typedef qvector<page_bpts_t::iterator> pbpt_iterators_t; // list of iterators into page_bpts_t
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// set of addresses
|
||||
typedef std::set<ea_t> easet_t;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
class idc_value_t;
|
||||
class rpc_engine_t;
|
||||
error_t idaapi idc_get_reg_value(idc_value_t *argv, idc_value_t *r);
|
||||
error_t idaapi idc_set_reg_value(idc_value_t *argv, idc_value_t *r);
|
||||
void report_idc_error(rpc_engine_t *rpc, ea_t ea, error_t code, ssize_t errval, const char *errprm);
|
||||
|
||||
// IDC function name that is exported by a debugger module
|
||||
// to allow scripts to send debugger commands
|
||||
#define IDC_SENDDBG_CMD "send_dbg_command"
|
||||
#define IDC_READ_MSR "read_msr"
|
||||
#define IDC_WRITE_MSR "write_msr"
|
||||
#define IDC_STEP_BACK "step_back"
|
||||
#define IDC_SET_TEV "set_current_tev"
|
||||
#define IDC_GET_TEV "get_current_tev"
|
||||
|
||||
// A macro to convert a pointer to ea_t without sign extension.
|
||||
#define EA_T(ptr) (ea_t)(size_t)(ptr)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-V:debmod_bpt_t:730 not all members of a class are initialized inside the constructor: saved
|
||||
struct debmod_bpt_t
|
||||
{
|
||||
ea_t ea;
|
||||
uchar saved[8]; // size of the biggest supported bpt size (PPC64)
|
||||
uchar nsaved;
|
||||
int bid; // (epoc) breakpoint id (from TRK)
|
||||
debmod_bpt_t() : ea(BADADDR), nsaved(0), bid(0) {}
|
||||
debmod_bpt_t(ea_t _ea, uchar _nsaved) : ea(_ea), nsaved(_nsaved), bid(0) { QASSERT(1796, nsaved < sizeof(saved)); }
|
||||
};
|
||||
typedef std::map<ea_t, debmod_bpt_t> debmodbpt_map_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct eventlist_t : public std::deque<debug_event_t>
|
||||
{
|
||||
public:
|
||||
// save a pending event
|
||||
void enqueue(const debug_event_t &ev, queue_pos_t pos)
|
||||
{
|
||||
if ( pos != IN_BACK )
|
||||
push_front(ev);
|
||||
else
|
||||
push_back(ev);
|
||||
}
|
||||
|
||||
// retrieve a pending event
|
||||
bool retrieve(debug_event_t *event)
|
||||
{
|
||||
if ( empty() )
|
||||
return false;
|
||||
// get the first event and return it
|
||||
*event = front();
|
||||
pop_front();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int send_ioctl(rpc_engine_t *rpc, int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize);
|
||||
int send_debug_names_to_ida(ea_t *addrs, const char *const *names, int qty);
|
||||
int send_debug_event_to_ida(const debug_event_t *ev, int rqflags);
|
||||
void set_arm_thumb_modes(ea_t *addrs, int qty);
|
||||
char *debug_event_str(const debug_event_t *ev, char *buf, size_t bufsize);
|
||||
char *debug_event_str(const debug_event_t *ev); // returns static buf
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// describes a dll to be imported
|
||||
struct import_request_t
|
||||
{
|
||||
ea_t base;
|
||||
qstring path;
|
||||
bytevec_t uuid;
|
||||
import_request_t(ea_t _base, const qstring &_path, const bytevec_t &_uuid)
|
||||
: base(_base), path(_path), uuid(_uuid) {}
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(import_request_t);
|
||||
typedef qvector<import_request_t> import_infos_t;
|
||||
int import_dll(const import_request_t &req);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct regctx_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct regctx_entry_t
|
||||
{
|
||||
enum type_t
|
||||
{
|
||||
IVAL = 0,
|
||||
FVAL = 1,
|
||||
DATA = 2,
|
||||
FUNC = 3,
|
||||
} type;
|
||||
int reg_class;
|
||||
int reg_idx;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
size_t offset_in_ctx;
|
||||
size_t size_in_ctx;
|
||||
size_t reg_size;
|
||||
};
|
||||
struct
|
||||
{
|
||||
void (*read_func)(const regctx_t *, regval_t *, void *);
|
||||
void (*write_func)(regctx_t *, const regval_t *, void *);
|
||||
void *user_data;
|
||||
};
|
||||
};
|
||||
|
||||
uint64_t truncate_ival(uint64_t ival) const
|
||||
{
|
||||
switch ( reg_size )
|
||||
{
|
||||
case 1: ival = uint8_t(ival); break;
|
||||
case 2: ival = uint16_t(ival); break;
|
||||
case 4: ival = uint32_t(ival); break;
|
||||
}
|
||||
return ival;
|
||||
}
|
||||
|
||||
void read(regval_t *value, const uint8_t *ptr) const
|
||||
{
|
||||
if ( type == regctx_entry_t::FUNC )
|
||||
{
|
||||
read_func((regctx_t *) ptr, value, user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint8_t *p = ptr + offset_in_ctx;
|
||||
switch ( type )
|
||||
{
|
||||
case regctx_entry_t::IVAL:
|
||||
{
|
||||
uint64_t ival = 0;
|
||||
switch ( size_in_ctx )
|
||||
{
|
||||
case 1: ival = *(uint8_t *)p; break;
|
||||
case 2: ival = *(uint16_t *)p; break;
|
||||
case 4: ival = *(uint32_t *)p; break;
|
||||
case 8: ival = *(uint64_t *)p; break;
|
||||
}
|
||||
ival = truncate_ival(ival);
|
||||
value->ival = ival;
|
||||
}
|
||||
break;
|
||||
case regctx_entry_t::FVAL:
|
||||
// TODO: for x86, the value is converted to IEEE format in
|
||||
// x86_read_registers(). clean this up somehow.
|
||||
memcpy(value->fval, p, size_in_ctx);
|
||||
value->rvtype = RVT_FLOAT;
|
||||
break;
|
||||
case regctx_entry_t::DATA:
|
||||
value->set_bytes(p, size_in_ctx);
|
||||
break;
|
||||
case regctx_entry_t::FUNC:
|
||||
// never happens; makes compiler happy.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool patch(uint8_t *ptr, const regval_t *value) const
|
||||
{
|
||||
if ( type == regctx_entry_t::FUNC )
|
||||
{
|
||||
write_func((regctx_t *) ptr, value, user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t *p = ptr + offset_in_ctx;
|
||||
switch ( type )
|
||||
{
|
||||
case regctx_entry_t::IVAL:
|
||||
{
|
||||
uint64_t ival = value->ival;
|
||||
ival = truncate_ival(ival);
|
||||
switch ( size_in_ctx )
|
||||
{
|
||||
case 1: *(uint8_t *)p = ival; break;
|
||||
case 2: *(uint16_t *)p = ival; break;
|
||||
case 4: *(uint32_t *)p = ival; break;
|
||||
case 8: *(uint64_t *)p = ival; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case regctx_entry_t::FVAL:
|
||||
// TODO: for x86, the value is converted from IEEE format in
|
||||
// x86_write_register(). clean this up somehow.
|
||||
memcpy(p, value->fval, size_in_ctx);
|
||||
break;
|
||||
case regctx_entry_t::DATA:
|
||||
if ( value->get_data_size() != size_in_ctx )
|
||||
return false;
|
||||
memcpy(p, value->get_data(), value->get_data_size());
|
||||
break;
|
||||
case regctx_entry_t::FUNC:
|
||||
// never happens; makes compiler happy.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(regctx_entry_t);
|
||||
typedef qvector<regctx_entry_t> reg_ctx_entries_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct regctx_base_t
|
||||
{
|
||||
dynamic_register_set_t &idaregs; // linked to debmod_t's variable of the same name
|
||||
thid_t tid;
|
||||
int clsmask;
|
||||
|
||||
reg_ctx_entries_t entries;
|
||||
|
||||
void setup(thid_t _tid, int _clsmask=0)
|
||||
{
|
||||
tid = _tid;
|
||||
clsmask = _clsmask;
|
||||
}
|
||||
|
||||
void setup_reg(int dyn_reg_idx)
|
||||
{
|
||||
clsmask |= entries[dyn_reg_idx].reg_class;
|
||||
}
|
||||
|
||||
regctx_base_t(dynamic_register_set_t &_idaregs)
|
||||
: idaregs(_idaregs)
|
||||
{
|
||||
setup(0, 0);
|
||||
}
|
||||
|
||||
void add_idareg(register_info_t &ri)
|
||||
{
|
||||
idaregs.add_register(ri.name,
|
||||
ri.flags,
|
||||
ri.dtype,
|
||||
ri.register_class,
|
||||
ri.bit_strings,
|
||||
ri.default_bit_strings_mask);
|
||||
}
|
||||
|
||||
size_t add_entry(
|
||||
regctx_entry_t::type_t type,
|
||||
register_info_t &ri,
|
||||
size_t offset_in_ctx,
|
||||
size_t size_in_ctx,
|
||||
size_t reg_size)
|
||||
{
|
||||
size_t dyn_reg_idx = entries.size();
|
||||
regctx_entry_t &entry = entries.push_back();
|
||||
entry.type = type;
|
||||
entry.reg_class = ri.register_class;
|
||||
entry.reg_idx = dyn_reg_idx;
|
||||
entry.offset_in_ctx = offset_in_ctx;
|
||||
entry.size_in_ctx = size_in_ctx;
|
||||
entry.reg_size = reg_size;
|
||||
add_idareg(ri);
|
||||
return dyn_reg_idx;
|
||||
}
|
||||
|
||||
size_t add_ival(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
|
||||
{
|
||||
QASSERT(1797, size_in_ctx <= sizeof(regval_t::ival));
|
||||
size_t reg_size = ri.dtype == dt_word ? 2
|
||||
: ri.dtype == dt_dword ? 4
|
||||
: ri.dtype == dt_qword ? 8
|
||||
: 0;
|
||||
QASSERT(1798, reg_size != 0);
|
||||
return add_entry(regctx_entry_t::IVAL, ri, offset_in_ctx, size_in_ctx, reg_size);
|
||||
}
|
||||
|
||||
size_t add_fval(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
|
||||
{
|
||||
QASSERT(1799, size_in_ctx <= sizeof(regval_t::fval));
|
||||
return add_entry(regctx_entry_t::FVAL, ri, offset_in_ctx, size_in_ctx, size_in_ctx);
|
||||
}
|
||||
|
||||
size_t add_data(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
|
||||
{
|
||||
return add_entry(regctx_entry_t::DATA, ri, offset_in_ctx, size_in_ctx, size_in_ctx);
|
||||
}
|
||||
|
||||
size_t add_func(
|
||||
register_info_t &ri,
|
||||
void (*read_func)(const regctx_t *, regval_t *, void *),
|
||||
void (*write_func)(regctx_t *, const regval_t *, void *),
|
||||
void *user_data=nullptr)
|
||||
{
|
||||
size_t dyn_reg_idx = entries.size();
|
||||
regctx_entry_t &entry = entries.push_back();
|
||||
entry.type = regctx_entry_t::FUNC;
|
||||
entry.reg_class = ri.register_class;
|
||||
entry.reg_idx = dyn_reg_idx;
|
||||
entry.read_func = read_func;
|
||||
entry.write_func = write_func;
|
||||
entry.user_data = user_data;
|
||||
add_idareg(ri);
|
||||
return dyn_reg_idx;
|
||||
}
|
||||
|
||||
void read_all(regval_t *values)
|
||||
{
|
||||
for ( const regctx_entry_t &entry: entries )
|
||||
if ( (clsmask & entry.reg_class) != 0 )
|
||||
entry.read(&values[entry.reg_idx], (const uint8_t *) this);
|
||||
}
|
||||
|
||||
bool patch(int dyn_reg_idx, const regval_t *value)
|
||||
{
|
||||
return entries[dyn_reg_idx].patch((uint8_t *) this, value);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Main class to represent a debugger module
|
||||
class debmod_t
|
||||
{
|
||||
protected:
|
||||
// processor_t &ph;
|
||||
typedef std::map<int, regval_t> regval_map_t;
|
||||
qvector<exception_info_t> exceptions;
|
||||
name_info_t dn_names;
|
||||
// Pending events. currently used only to store
|
||||
// exceptions that happen while attaching
|
||||
eventlist_t events;
|
||||
// The last event received via a successful get_debug_event()
|
||||
debug_event_t last_event;
|
||||
|
||||
// debugged process attributes (may be changed after process start/attach)
|
||||
debapp_attrs_t debapp_attrs;
|
||||
|
||||
procvec_t proclist;
|
||||
|
||||
// appcall contexts
|
||||
struct call_context_t
|
||||
{
|
||||
regvals_t saved_regs;
|
||||
ea_t sp;
|
||||
ea_t ctrl_ea;
|
||||
bool regs_spoiled;
|
||||
call_context_t() : sp(BADADDR), ctrl_ea(BADADDR), regs_spoiled(false) {}
|
||||
};
|
||||
typedef qstack<call_context_t> call_contexts_t;
|
||||
typedef std::map<thid_t, call_contexts_t> appcalls_t;
|
||||
appcalls_t appcalls;
|
||||
|
||||
int send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize)
|
||||
{
|
||||
return ::send_ioctl(rpc, fn, buf, size, poutbuf, poutsize);
|
||||
}
|
||||
// If an IDC error occurs: we cannot prepare an error message on the server
|
||||
// side because we do not have access to error strings (they are in ida.hlp).
|
||||
// We pass the error code to IDA (with eventual arguments) so it can prepare
|
||||
// a nice error message for the user
|
||||
void report_idc_error(ea_t ea, error_t code, ssize_t errval, const char *errprm)
|
||||
{
|
||||
return ::report_idc_error(rpc, ea, code, errval, errprm);
|
||||
}
|
||||
|
||||
typedef std::map<ea_t, lowcnd_t> lowcnds_t;
|
||||
lowcnds_t cndmap;
|
||||
eavec_t handling_lowcnds;
|
||||
bool evaluate_and_handle_lowcnd(debug_event_t *event, int elc_flags=0);
|
||||
bool handle_lowcnd(lowcnd_t *lc, debug_event_t *event, int elc_flags);
|
||||
#define ELC_KEEP_EIP 0x0001 // do not reset eip before stepping
|
||||
#define ELC_KEEP_SUSP 0x0002 // keep suspended state, do not resume after stepping
|
||||
|
||||
// helper functions for programmatical single stepping
|
||||
virtual drc_t dbg_perform_single_step(debug_event_t *event, const insn_t &ins);
|
||||
virtual int dbg_freeze_threads_except(thid_t) { return 0; }
|
||||
virtual int dbg_thaw_threads_except(thid_t) { return 0; }
|
||||
drc_t resume_app_and_get_event(debug_event_t *dev);
|
||||
void set_platform(const char *platform_name);
|
||||
|
||||
// return number of processes, -1 - not implemented
|
||||
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf);
|
||||
|
||||
public:
|
||||
// initialized by dbg_init()
|
||||
int debugger_flags;
|
||||
meminfo_vec_t old_ranges;
|
||||
rpc_engine_t *rpc;
|
||||
bool debug_debugger;
|
||||
// Is dynamic library?
|
||||
bool is_dll;
|
||||
|
||||
// indexes of sp and program counter registers.
|
||||
// Must be initialized by derived classes.
|
||||
int sp_idx;
|
||||
int pc_idx;
|
||||
|
||||
// index of frame pointer register
|
||||
int fp_idx;
|
||||
|
||||
// Total number of registers.
|
||||
// Must be initialized by derived classes.
|
||||
int nregs;
|
||||
|
||||
// Breakpoint code.
|
||||
// Must be initialized by derived classes.
|
||||
bytevec_t bpt_code;
|
||||
|
||||
qstring input_file_path;
|
||||
|
||||
page_bpts_t page_bpts;
|
||||
|
||||
// will either send as msg/warning/error through callui,
|
||||
// or through 'rpc' if it is present.
|
||||
DEFINE_ALL_NOTIFICATION_FUNCTIONS(rpc);
|
||||
AS_PRINTF(3,0) static ssize_t dvnotif(int code, rpc_engine_t *rpc, const char *format, va_list va);
|
||||
|
||||
bool broken_connection;
|
||||
pid_t pid;
|
||||
|
||||
debmodbpt_map_t bpts;
|
||||
update_bpt_vec_t deleted_bpts; // deleted bpts in the last update_bpts() call
|
||||
// if bpt EA was deleted then bpt raised in the same place for the
|
||||
// same thread does not belong to IDA
|
||||
bool is_ida_bpt(ea_t ea, thid_t tid)
|
||||
{
|
||||
if ( bpts.find(ea) != bpts.end() )
|
||||
return true;
|
||||
update_bpt_info_t b;
|
||||
b.ea = ea;
|
||||
return deleted_bpts.find(b) != deleted_bpts.end()
|
||||
&& (last_event.eid() != BREAKPOINT
|
||||
|| last_event.ea != ea
|
||||
|| last_event.tid != tid);
|
||||
}
|
||||
|
||||
static bool reuse_broken_connections;
|
||||
|
||||
//------------------------------------
|
||||
// Dynamic register set for debugger_t
|
||||
//------------------------------------
|
||||
dynamic_register_set_t idaregs;
|
||||
|
||||
//------------------------------------
|
||||
// Constructors and destructors
|
||||
//------------------------------------
|
||||
debmod_t();
|
||||
virtual ~debmod_t() { cleanup(); }
|
||||
|
||||
//------------------------------------
|
||||
// Debug names methods
|
||||
//------------------------------------
|
||||
void clear_debug_names();
|
||||
name_info_t *get_debug_names();
|
||||
void save_debug_name(ea_t ea, const char *name);
|
||||
int set_debug_names();
|
||||
int send_debug_names_to_ida(ea_t *addrs, const char *const *names, int qty);
|
||||
int send_debug_event_to_ida(const debug_event_t *ev, int rqflags);
|
||||
ea_t find_debug_name(const char *name) const;
|
||||
//------------------------------------
|
||||
// Utility methods
|
||||
//------------------------------------
|
||||
void cleanup(void);
|
||||
AS_PRINTF(2, 3) void debdeb(const char *format, ...);
|
||||
AS_PRINTF(2, 3) bool deberr(const char *format, ...);
|
||||
bool same_as_oldmemcfg(const meminfo_vec_t &ranges) const;
|
||||
void save_oldmemcfg(const meminfo_vec_t &ranges);
|
||||
bool continue_after_last_event(bool handled = true);
|
||||
lowcnd_t *get_failed_lowcnd(thid_t tid, ea_t ea);
|
||||
page_bpts_t::iterator find_page_bpt(ea_t ea, int size=1);
|
||||
bool del_page_bpt(ea_t ea, bpttype_t type);
|
||||
void enable_page_bpts(bool enable);
|
||||
ea_t calc_page_base(ea_t ea) { return align_down(ea, dbg_memory_page_size()); }
|
||||
void log_exception(const debug_event_t *ev, const exception_info_t *ei);
|
||||
uint64 probe_file_size(int fn, uint64 step);
|
||||
void set_input_path(const char *input_path);
|
||||
int read_bpt_orgbytes(bytevec_t *buf, ea_t ea, int len);
|
||||
|
||||
//------------------------------------
|
||||
// Shared methods
|
||||
//------------------------------------
|
||||
virtual bool check_input_file_crc32(uint32 orig_crc);
|
||||
virtual const exception_info_t *find_exception(int code);
|
||||
virtual bool get_exception_name(int code, char *buf, size_t bufsize);
|
||||
virtual drc_t idaapi dbg_get_processes(procinfo_vec_t *info, qstring *errbuf);
|
||||
|
||||
//------------------------------------
|
||||
// Methods to be implemented
|
||||
//------------------------------------
|
||||
virtual void idaapi dbg_set_debugging(bool _debug_debugger) = 0;
|
||||
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) = 0;
|
||||
virtual void idaapi dbg_term(void) = 0;
|
||||
virtual drc_t idaapi dbg_detach_process(void) = 0;
|
||||
virtual drc_t idaapi dbg_start_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
qstring *errbuf) = 0;
|
||||
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_msecs) = 0;
|
||||
virtual drc_t idaapi dbg_attach_process(pid_t process_id, int event_id, int flags, qstring *errbuf) = 0;
|
||||
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) = 0;
|
||||
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) = 0;
|
||||
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) = 0;
|
||||
virtual void idaapi dbg_set_exception_info(const exception_info_t *info, int qty);
|
||||
virtual void idaapi dbg_stopped_at_debug_event(import_infos_t *infos, bool dlls_added, thread_name_vec_t *thr_names) = 0;
|
||||
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) = 0;
|
||||
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) = 0;
|
||||
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) = 0;
|
||||
virtual drc_t idaapi dbg_read_registers(
|
||||
thid_t thread_id,
|
||||
int clsmask,
|
||||
regval_t *values,
|
||||
qstring *errbuf) = 0;
|
||||
virtual drc_t idaapi dbg_write_register(
|
||||
thid_t thread_id,
|
||||
int reg_idx,
|
||||
const regval_t *value,
|
||||
qstring *errbuf) = 0;
|
||||
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) = 0;
|
||||
virtual ea_t idaapi map_address(ea_t ea, const regval_t *, int /* regnum */) { return ea; }
|
||||
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &ranges, qstring *errbuf) = 0;
|
||||
virtual int idaapi dbg_get_scattered_image(scattered_image_t & /*si*/, ea_t /*base*/) { return -1; }
|
||||
virtual bool idaapi dbg_get_image_uuid(bytevec_t * /*uuid*/, ea_t /*base*/) { return false; }
|
||||
virtual ea_t idaapi dbg_get_segm_start(ea_t /*base*/, const qstring & /*segname*/) { return BADADDR; }
|
||||
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) = 0;
|
||||
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) = 0;
|
||||
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) = 0;
|
||||
// for swbpts, len may be -1 (unknown size, for example arm/thumb mode) or bpt opcode length
|
||||
// dbg_add_bpt returns 2 if it adds a page bpt
|
||||
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) = 0;
|
||||
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) = 0;
|
||||
virtual drc_t idaapi dbg_update_bpts(int *nbpts, update_bpt_info_t *bpts, int nadd, int ndel, qstring *errbuf);
|
||||
virtual int idaapi dbg_add_page_bpt(bpttype_t /*type*/, ea_t /*ea*/, int /*size*/) { return 0; }
|
||||
virtual bool idaapi dbg_enable_page_bpt(page_bpts_t::iterator /*p*/, bool /*enable*/) { return false; }
|
||||
virtual drc_t idaapi dbg_update_lowcnds(int *nupdated, const lowcnd_t *lowcnds, int nlowcnds, qstring *errbuf);
|
||||
virtual drc_t idaapi dbg_eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf);
|
||||
virtual int idaapi dbg_open_file(const char * /*file*/, uint64 * /*fsize*/, bool /*readonly*/) { return -1; }
|
||||
virtual void idaapi dbg_close_file(int /*fn*/) {}
|
||||
virtual ssize_t idaapi dbg_read_file(int /*fn*/, qoff64_t /*off*/, void * /*buf*/, size_t /*size*/) { return 0; }
|
||||
virtual ssize_t idaapi dbg_write_file(int /*fn*/, qoff64_t /*off*/, const void * /*buf*/, size_t /*size*/) { return 0; }
|
||||
virtual int idaapi handle_ioctl(
|
||||
int /*fn*/,
|
||||
const void * /*buf*/,
|
||||
size_t /*size*/,
|
||||
void ** /*outbuf*/,
|
||||
ssize_t * /*outsize*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int idaapi get_system_specific_errno(void) const; // this code must be acceptable by winerr()
|
||||
virtual drc_t idaapi dbg_update_call_stack(thid_t, call_stack_t *) { return DRC_NONE; }
|
||||
virtual ea_t idaapi dbg_appcall(
|
||||
ea_t /*func_ea*/,
|
||||
thid_t /*tid*/,
|
||||
int /*stkarg_nbytes*/,
|
||||
const struct regobjs_t * /*regargs*/,
|
||||
struct relobj_t * /*stkargs*/,
|
||||
struct regobjs_t * /*retregs*/,
|
||||
qstring *errbuf,
|
||||
debug_event_t * /*event*/,
|
||||
int /*flags*/);
|
||||
virtual drc_t idaapi dbg_cleanup_appcall(thid_t /*tid*/);
|
||||
virtual bool idaapi write_registers(
|
||||
thid_t /*tid*/,
|
||||
int /*start*/,
|
||||
int /*count*/,
|
||||
const regval_t * /*values*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// finalize appcall stack image
|
||||
// input: stack image contains the return address at the beginning
|
||||
virtual int finalize_appcall_stack(call_context_t &, regval_map_t &, bytevec_t &) { return 0; }
|
||||
virtual ea_t calc_appcall_stack(const regvals_t ®vals);
|
||||
virtual bool should_stop_appcall(thid_t tid, const debug_event_t *event, ea_t ea);
|
||||
virtual bool should_suspend_at_exception(const debug_event_t *event, const exception_info_t *ei);
|
||||
virtual bool preprocess_appcall_cleanup(thid_t, call_context_t &) { return true; }
|
||||
virtual int get_regidx(const char *regname, int *clsmask) = 0;
|
||||
virtual uint32 dbg_memory_page_size(void) { return 0x1000; }
|
||||
virtual bool idaapi dbg_prepare_broken_connection(void) { return false; }
|
||||
virtual bool idaapi dbg_continue_broken_connection(pid_t) { old_ranges.clear(); return true; }
|
||||
virtual bool idaapi dbg_enable_trace(thid_t, bool, int) { return false; }
|
||||
virtual bool idaapi dbg_is_tracing_enabled(thid_t, int) { return false; }
|
||||
virtual int idaapi dbg_rexec(const char *cmdline);
|
||||
virtual void adjust_swbpt(ea_t *, int *) {};
|
||||
virtual void dbg_get_debapp_attrs(debapp_attrs_t *out_pattrs) const;
|
||||
virtual bool idaapi dbg_get_srcinfo_path(qstring * /*path*/, ea_t /*base*/) const { return false; }
|
||||
virtual bool import_dll(const import_request_t & /*req*/) { return false; }
|
||||
virtual drc_t idaapi dbg_bin_search(
|
||||
ea_t *ea,
|
||||
ea_t start_ea,
|
||||
ea_t end_ea,
|
||||
const compiled_binpat_vec_t &ptns,
|
||||
int srch_flags,
|
||||
qstring *errbuf);
|
||||
|
||||
bool restore_broken_breakpoints(void);
|
||||
void set_addr_size(int size) { debapp_attrs.addrsize = size; }
|
||||
void set_endianness(bool is_be) { debapp_attrs.is_be = is_be; }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Some functions, per OS implemented
|
||||
//
|
||||
bool init_subsystem();
|
||||
bool term_subsystem();
|
||||
debmod_t *create_debug_session(void *params);
|
||||
|
||||
//
|
||||
// Processor specific init/term
|
||||
//
|
||||
void processor_specific_init(void);
|
||||
void processor_specific_term(void);
|
||||
|
||||
// Perform an action on all existing debugger modules
|
||||
struct debmod_visitor_t
|
||||
{
|
||||
virtual int visit(debmod_t *debmod) = 0;
|
||||
};
|
||||
int for_all_debuggers(debmod_visitor_t &v);
|
||||
|
||||
|
||||
//
|
||||
// Utility functions
|
||||
//
|
||||
|
||||
// Common method between MacOS and Linux to launch a process
|
||||
drc_t idaapi maclnx_launch_process(
|
||||
debmod_t *debmod,
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
void **child_pid,
|
||||
qstring *errbuf);
|
||||
|
||||
bool add_idc_funcs(const struct ext_idcfunc_t funcs[], size_t nfuncs, bool reg);
|
||||
|
||||
//
|
||||
// Externs
|
||||
//
|
||||
extern debmod_t *idc_debmod;
|
||||
extern thid_t idc_thread;
|
||||
extern bool ignore_sigint;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// server.cpp
|
||||
bool lock_begin();
|
||||
bool lock_end();
|
||||
|
||||
// bool srv_lock_begin(void);
|
||||
// bool srv_lock_end(void);
|
||||
|
||||
#endif
|
||||
292
idasdk75/dbg/exceptions.cfg
Normal file
292
idasdk75/dbg/exceptions.cfg
Normal file
@@ -0,0 +1,292 @@
|
||||
; This file describes the exception definitions.
|
||||
; The definitions will be used for new databases.
|
||||
|
||||
; for each exception:
|
||||
; code stop_at pass_to_app notification name description
|
||||
;
|
||||
; code is the exception code
|
||||
; stop_at is one of stop or nostop - should the debugger suspend
|
||||
; the process when the exception occurs
|
||||
; pass_to_app is one of app or mask - should the debugger pass
|
||||
; the exception to the application or not
|
||||
; notification is one of warn/log/silent
|
||||
; name is the exception short name
|
||||
; description is the exception description displayed to the user
|
||||
|
||||
; Windows exceptions
|
||||
.win32,bochs_win32
|
||||
0xC0000005 stop mask warn EXCEPTION_ACCESS_VIOLATION The instruction at 0x%a referenced memory at 0x%a. The memory could not be %s
|
||||
0x80000002 stop mask warn EXCEPTION_DATATYPE_MISALIGNMENT A datatype misalignment error was detected in a load or store instruction
|
||||
0x80000003 stop mask warn EXCEPTION_BREAKPOINT Software breakpoint exception
|
||||
0x80000004 stop mask warn EXCEPTION_SINGLE_STEP Single step exception
|
||||
0xC000008C stop mask warn EXCEPTION_ARRAY_BOUNDS_EXCEEDED Array bounds exceeded
|
||||
0xC000008D stop mask warn EXCEPTION_FLT_DENORMAL_OPERAND Floating point denormal operand
|
||||
0xC000008E stop mask warn EXCEPTION_FLT_DIVIDE_BY_ZERO Floating point divide by zero
|
||||
0xC000008F stop mask warn EXCEPTION_FLT_INEXACT_RESULT Floating point inexact result
|
||||
0xC0000090 stop mask warn EXCEPTION_FLT_INVALID_OPERATION Floating point invalid operation
|
||||
0xC0000091 stop mask warn EXCEPTION_FLT_OVERFLOW Floating point overflow
|
||||
0xC0000092 stop mask warn EXCEPTION_FLT_STACK_CHECK Floating point stack check
|
||||
0xC0000093 stop mask warn EXCEPTION_FLT_UNDERFLOW Floating point underflow
|
||||
0xC0000094 stop mask warn EXCEPTION_INT_DIVIDE_BY_ZERO Integer divide by zero
|
||||
0xC0000095 stop mask warn EXCEPTION_INT_OVERFLOW Integer overflow
|
||||
0xC0000096 stop mask warn EXCEPTION_PRIV_INSTRUCTION Priveleged instruction
|
||||
0xC0000006 stop mask warn EXCEPTION_IN_PAGE_ERROR The instruction at "0x%a" referenced memory at "0x%a". The required data was not placed into memory because of an I/O error status of "0x%a"
|
||||
0xC000001D stop mask warn EXCEPTION_ILLEGAL_INSTRUCTION An attempt was made to execute an illegal instruction
|
||||
0xC0000025 stop mask warn EXCEPTION_NONCONTINUABLE_EXCEPTION Windows cannot continue from this exception
|
||||
0xC00000FD stop mask warn EXCEPTION_STACK_OVERFLOW A new guard page for the stack cannot be created (stack overflow)
|
||||
0xC0000026 stop mask warn EXCEPTION_INVALID_DISPOSITION An invalid exception disposition was returned by an exception handler
|
||||
0x80000001 stop mask warn EXCEPTION_GUARD_PAGE A page of memory that marks the end of a data structure such as a stack or an array has been accessed
|
||||
0xC0000008 stop mask warn EXCEPTION_INVALID_HANDLE An invalid HANDLE was specified
|
||||
0xEEFFACE stop mask warn EXCEPTION_BCC_FATAL Fatal unhandled exception in the BCC compiled program
|
||||
0xEEDFAE6 stop mask warn EXCEPTION_BCC_NORMAL Unhandled exception in the BCC compiled program
|
||||
0x40010005 stop mask warn DBG_CONTROL_C CTRL+C was input to console process
|
||||
0x40010008 stop mask warn DBG_CONTROL_BREAK CTRL+BREAK was input to console process
|
||||
0xE06D7363 stop mask warn EXCEPTION_MSC_CPLUSPLUS Microsoft C++ exception
|
||||
0xE0434F4D stop mask warn EXCEPTION_MANAGED_NET Managed .NET exception
|
||||
0xE0434352 stop mask warn EXCEPTION_MANAGED_NET_V4 Managed .NET exception (V4+)
|
||||
0x4000001E stop mask warn EXCEPTION_WX86_SINGLE_STEP Single step exception (x86 emulation)
|
||||
0x4000001F stop mask warn EXCEPTION_WX86_BREAKPOINT Software breakpoint exception (x86 emulation)
|
||||
0x406D1388 nostop mask log MS_VC_EXCEPTION SetThreadName
|
||||
|
||||
; Linux exceptions
|
||||
.linux
|
||||
1 stop mask warn SIGHUP Hangup
|
||||
2 stop mask warn SIGINT Interrupt
|
||||
3 stop mask warn SIGQUIT Quit
|
||||
4 stop mask warn SIGILL Illegal instruction
|
||||
5 stop mask warn SIGTRAP Trace trap
|
||||
6 stop mask warn SIGABRT Abort
|
||||
7 stop mask warn SIGBUS BUS error
|
||||
8 stop mask warn SIGFPE Floating-point exception
|
||||
9 stop mask warn SIGKILL Kill unblockable
|
||||
10 stop mask warn SIGUSR1 User-defined signal 1
|
||||
11 stop mask warn SIGSEGV Segmentation violation
|
||||
12 stop mask warn SIGUSR2 User-defined signal 2
|
||||
13 stop mask warn SIGPIPE Broken pipe
|
||||
14 stop mask warn SIGALRM Alarm clock
|
||||
15 stop mask warn SIGTERM Termination
|
||||
16 stop mask warn SIGSTKFLT Stack fault
|
||||
17 stop mask warn SIGCHLD Child status has changed
|
||||
18 stop mask warn SIGCONT Continue
|
||||
19 stop mask warn SIGSTOP Stop unblockable
|
||||
20 stop mask warn SIGTSTP Keyboard stop
|
||||
21 stop mask warn SIGTTIN Background read from tty
|
||||
22 stop mask warn SIGTTOU Background write to tty
|
||||
23 stop mask warn SIGURG Urgent condition on socket
|
||||
24 stop mask warn SIGXCPU CPU limit exceeded
|
||||
25 stop mask warn SIGXFSZ File size limit exceeded
|
||||
26 stop mask warn SIGVTALRM Virtual alarm clock
|
||||
27 stop mask warn SIGPROF Profiling alarm clock
|
||||
28 stop mask warn SIGWINCH Window size change
|
||||
29 stop mask warn SIGIO I/O now possible
|
||||
30 stop mask warn SIGPWR Power failure restart
|
||||
31 stop mask warn SIGSYS Bad system call
|
||||
|
||||
; Mac OS X/iphone exceptions
|
||||
.macosx,ios,xnu
|
||||
1 stop mask warn SIGHUP terminal line hangup
|
||||
2 stop mask warn SIGINT interrupt program
|
||||
3 stop mask warn SIGQUIT quit program
|
||||
4 stop mask warn SIGILL illegal instruction
|
||||
5 stop mask warn SIGTRAP trace trap
|
||||
6 stop mask warn SIGABRT abort program
|
||||
7 stop mask warn SIGEMT emulate instruction executed
|
||||
8 stop mask warn SIGFPE floating-point exception
|
||||
9 stop mask warn SIGKILL kill program
|
||||
10 stop mask warn SIGBUS bus error
|
||||
11 stop mask warn SIGSEGV segmentation violation
|
||||
12 stop mask warn SIGSYS non-existent system call invoked
|
||||
13 stop mask warn SIGPIPE write on a pipe with no reader
|
||||
14 stop mask warn SIGALRM real-time timer expired
|
||||
15 stop mask warn SIGTERM software termination signal
|
||||
16 stop mask warn SIGURG urgent condition present on socket
|
||||
17 stop mask warn SIGSTOP stop
|
||||
18 stop mask warn SIGTSTP stop signal generated from keyboard
|
||||
19 stop mask warn SIGCONT continue after stop
|
||||
20 stop mask warn SIGCHLD child status has changed
|
||||
21 stop mask warn SIGTTIN background read attempted from control terminal
|
||||
22 stop mask warn SIGTTOU background write attempted to control terminal
|
||||
23 stop mask warn SIGIO I/O is possible on a descriptor
|
||||
24 stop mask warn SIGXCPU cpu time limit exceeded
|
||||
25 stop mask warn SIGXFSZ file size limit exceeded
|
||||
26 stop mask warn SIGVTALRM virtual time alarm
|
||||
27 stop mask warn SIGPROF profiling timer alarm
|
||||
28 stop mask warn SIGWINCH Window size change
|
||||
29 stop mask warn SIGINFO status request from keyboard
|
||||
30 stop mask warn SIGUSR1 User defined signal 1
|
||||
31 stop mask warn SIGUSR2 User defined signal 2
|
||||
;additional iphone exceptions
|
||||
145 stop mask warn EXC_BAD_ACCESS Bad memory access
|
||||
146 stop mask warn EXC_BAD_INSTRUCTION Bad instruction
|
||||
147 stop mask warn EXC_ARITHMETIC Arithmetic exception
|
||||
148 stop mask warn EXC_EMULATION Emulation exception
|
||||
149 stop mask warn EXC_SOFTWARE Software exception
|
||||
150 stop mask warn EXC_BREAKPOINT Breakpoint exception
|
||||
|
||||
; Bochs IA-32 emulator: raw exceptions
|
||||
; (in addition to MS Windows exceptions defined above)
|
||||
.bochs_win32
|
||||
0x00 stop mask warn DIVIDE_BY_ZERO Divide by zero
|
||||
0x01 stop mask warn SINGLE_STEP Single step
|
||||
0x03 stop mask warn BREAKPOINT Breakpoint
|
||||
0x04 stop mask warn INTO Interrupt on overflow
|
||||
0x06 stop mask warn INVALID_OPCODE Invalid opcode
|
||||
0x0C stop mask warn STACK_EXCEPTION Stack exception
|
||||
0x0D stop mask warn GENERAL_PROTECTION_FAULT General protection fault
|
||||
0x0E stop mask warn PAGE_FAULT Page fault at 0x%a, error code %a
|
||||
0x10 stop mask warn FLOATING_POINT_ERROR Floating point error
|
||||
|
||||
.gdb
|
||||
; gdb signals
|
||||
1 stop mask warn SIGHUP Hangup
|
||||
2 stop mask warn SIGINT Interrupt
|
||||
3 stop mask warn SIGQUIT Quit
|
||||
4 stop mask warn SIGILL Illegal instruction
|
||||
5 stop mask warn SIGTRAP Trace/breakpoint trap
|
||||
6 stop mask warn SIGABRT Aborted
|
||||
7 stop mask warn SIGEMT Emulation trap
|
||||
8 stop mask warn SIGFPE Arithmetic exception
|
||||
9 stop mask warn SIGKILL Killed
|
||||
10 stop mask warn SIGBUS Bus error
|
||||
11 stop mask warn SIGSEGV Segmentation fault
|
||||
12 stop mask warn SIGSYS Bad system call
|
||||
13 stop mask warn SIGPIPE Broken pipe
|
||||
14 stop mask warn SIGALRM Alarm clock
|
||||
15 stop mask warn SIGTERM Terminated
|
||||
16 stop mask warn SIGURG Urgent I/O condition
|
||||
17 stop mask warn SIGSTOP Stopped (signal)
|
||||
18 stop mask warn SIGTSTP Stopped (user)
|
||||
19 stop mask warn SIGCONT Continued
|
||||
20 stop mask warn SIGCHLD Child status changed
|
||||
21 stop mask warn SIGTTIN Stopped (tty input)
|
||||
22 stop mask warn SIGTTOU Stopped (tty output)
|
||||
23 stop mask warn SIGIO I/O possible
|
||||
24 stop mask warn SIGXCPU CPU time limit exceeded
|
||||
25 stop mask warn SIGXFSZ File size limit exceeded
|
||||
26 stop mask warn SIGVTALRM Virtual timer expired
|
||||
27 stop mask warn SIGPROF Profiling timer expired
|
||||
28 stop mask warn SIGWINCH Window size changed
|
||||
29 stop mask warn SIGLOST Resource lost
|
||||
30 stop mask warn SIGUSR1 User defined signal 1
|
||||
31 stop mask warn SIGUSR2 User defined signal 2
|
||||
32 stop mask warn SIGPWR Power fail/restart
|
||||
33 stop mask warn SIGPOLL Pollable event occurred
|
||||
34 stop mask warn SIGWIND SIGWIND
|
||||
35 stop mask warn SIGPHONE SIGPHONE
|
||||
36 stop mask warn SIGWAITING Process's LWPs are blocked
|
||||
37 stop mask warn SIGLWP Signal LWP
|
||||
38 stop mask warn SIGDANGER Swap space dangerously low
|
||||
39 stop mask warn SIGGRANT Monitor mode granted
|
||||
40 stop mask warn SIGRETRACT Need to relinquish monitor mode
|
||||
41 stop mask warn SIGMSG Monitor mode data available
|
||||
42 stop mask warn SIGSOUND Sound completed
|
||||
43 stop mask warn SIGSAK Secure attention
|
||||
44 stop mask warn SIGPRIO SIGPRIO
|
||||
45 stop mask warn SIG33 Real-time event 33
|
||||
46 stop mask warn SIG34 Real-time event 34
|
||||
47 stop mask warn SIG35 Real-time event 35
|
||||
48 stop mask warn SIG36 Real-time event 36
|
||||
49 stop mask warn SIG37 Real-time event 37
|
||||
50 stop mask warn SIG38 Real-time event 38
|
||||
51 stop mask warn SIG39 Real-time event 39
|
||||
52 stop mask warn SIG40 Real-time event 40
|
||||
53 stop mask warn SIG41 Real-time event 41
|
||||
54 stop mask warn SIG42 Real-time event 42
|
||||
55 stop mask warn SIG43 Real-time event 43
|
||||
56 stop mask warn SIG44 Real-time event 44
|
||||
57 stop mask warn SIG45 Real-time event 45
|
||||
58 stop mask warn SIG46 Real-time event 46
|
||||
59 stop mask warn SIG47 Real-time event 47
|
||||
60 stop mask warn SIG48 Real-time event 48
|
||||
61 stop mask warn SIG49 Real-time event 49
|
||||
62 stop mask warn SIG50 Real-time event 50
|
||||
63 stop mask warn SIG51 Real-time event 51
|
||||
64 stop mask warn SIG52 Real-time event 52
|
||||
65 stop mask warn SIG53 Real-time event 53
|
||||
66 stop mask warn SIG54 Real-time event 54
|
||||
67 stop mask warn SIG55 Real-time event 55
|
||||
68 stop mask warn SIG56 Real-time event 56
|
||||
69 stop mask warn SIG57 Real-time event 57
|
||||
70 stop mask warn SIG58 Real-time event 58
|
||||
71 stop mask warn SIG59 Real-time event 59
|
||||
72 stop mask warn SIG60 Real-time event 60
|
||||
73 stop mask warn SIG61 Real-time event 61
|
||||
74 stop mask warn SIG62 Real-time event 62
|
||||
75 stop mask warn SIG63 Real-time event 63
|
||||
76 stop mask warn SIGCANCEL LWP internal signal
|
||||
77 stop mask warn SIG32 Real-time event 32
|
||||
78 stop mask warn SIG64 Real-time event 64
|
||||
79 stop mask warn SIG65 Real-time event 65
|
||||
80 stop mask warn SIG66 Real-time event 66
|
||||
81 stop mask warn SIG67 Real-time event 67
|
||||
82 stop mask warn SIG68 Real-time event 68
|
||||
83 stop mask warn SIG69 Real-time event 69
|
||||
84 stop mask warn SIG70 Real-time event 70
|
||||
85 stop mask warn SIG71 Real-time event 71
|
||||
86 stop mask warn SIG72 Real-time event 72
|
||||
87 stop mask warn SIG73 Real-time event 73
|
||||
88 stop mask warn SIG74 Real-time event 74
|
||||
89 stop mask warn SIG75 Real-time event 75
|
||||
90 stop mask warn SIG76 Real-time event 76
|
||||
91 stop mask warn SIG77 Real-time event 77
|
||||
92 stop mask warn SIG78 Real-time event 78
|
||||
93 stop mask warn SIG79 Real-time event 79
|
||||
94 stop mask warn SIG80 Real-time event 80
|
||||
95 stop mask warn SIG81 Real-time event 81
|
||||
96 stop mask warn SIG82 Real-time event 82
|
||||
97 stop mask warn SIG83 Real-time event 83
|
||||
98 stop mask warn SIG84 Real-time event 84
|
||||
99 stop mask warn SIG85 Real-time event 85
|
||||
100 stop mask warn SIG86 Real-time event 86
|
||||
101 stop mask warn SIG87 Real-time event 87
|
||||
102 stop mask warn SIG88 Real-time event 88
|
||||
103 stop mask warn SIG89 Real-time event 89
|
||||
104 stop mask warn SIG90 Real-time event 90
|
||||
105 stop mask warn SIG91 Real-time event 91
|
||||
106 stop mask warn SIG92 Real-time event 92
|
||||
107 stop mask warn SIG93 Real-time event 93
|
||||
108 stop mask warn SIG94 Real-time event 94
|
||||
109 stop mask warn SIG95 Real-time event 95
|
||||
110 stop mask warn SIG96 Real-time event 96
|
||||
111 stop mask warn SIG97 Real-time event 97
|
||||
112 stop mask warn SIG98 Real-time event 98
|
||||
113 stop mask warn SIG99 Real-time event 99
|
||||
114 stop mask warn SIG100 Real-time event 100
|
||||
115 stop mask warn SIG101 Real-time event 101
|
||||
116 stop mask warn SIG102 Real-time event 102
|
||||
117 stop mask warn SIG103 Real-time event 103
|
||||
118 stop mask warn SIG104 Real-time event 104
|
||||
119 stop mask warn SIG105 Real-time event 105
|
||||
120 stop mask warn SIG106 Real-time event 106
|
||||
121 stop mask warn SIG107 Real-time event 107
|
||||
122 stop mask warn SIG108 Real-time event 108
|
||||
123 stop mask warn SIG109 Real-time event 109
|
||||
124 stop mask warn SIG110 Real-time event 110
|
||||
125 stop mask warn SIG111 Real-time event 111
|
||||
126 stop mask warn SIG112 Real-time event 112
|
||||
127 stop mask warn SIG113 Real-time event 113
|
||||
128 stop mask warn SIG114 Real-time event 114
|
||||
129 stop mask warn SIG115 Real-time event 115
|
||||
130 stop mask warn SIG116 Real-time event 116
|
||||
131 stop mask warn SIG117 Real-time event 117
|
||||
132 stop mask warn SIG118 Real-time event 118
|
||||
133 stop mask warn SIG119 Real-time event 119
|
||||
134 stop mask warn SIG120 Real-time event 120
|
||||
135 stop mask warn SIG121 Real-time event 121
|
||||
136 stop mask warn SIG122 Real-time event 122
|
||||
137 stop mask warn SIG123 Real-time event 123
|
||||
138 stop mask warn SIG124 Real-time event 124
|
||||
139 stop mask warn SIG125 Real-time event 125
|
||||
140 stop mask warn SIG126 Real-time event 126
|
||||
141 stop mask warn SIG127 Real-time event 127
|
||||
142 stop mask warn SIGINFO Information request
|
||||
145 stop mask warn EXC_BAD_ACCESS Could not access memory
|
||||
146 stop mask warn EXC_BAD_INSTRUCTION Illegal instruction/operand
|
||||
147 stop mask warn EXC_ARITHMETIC Arithmetic exception
|
||||
148 stop mask warn EXC_EMULATION Emulation instruction
|
||||
149 stop mask warn EXC_SOFTWARE Software generated exception
|
||||
150 stop mask warn EXC_BREAKPOINT Breakpoint
|
||||
151 stop mask warn SIGLIBRT librt internal signal
|
||||
|
||||
.dalvik
|
||||
1 nostop mask warn java.lang.Throwable The superclass of all errors and exceptions in the Java language
|
||||
88
idasdk75/dbg/linux/android.cpp
Normal file
88
idasdk75/dbg/linux/android.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Android specific functions.
|
||||
*/
|
||||
|
||||
// r_brk():
|
||||
// B0003050 70 47 BX LR
|
||||
static const uchar bxlr_thumb[] = { 0x70, 0x47 };
|
||||
|
||||
#define LINKER "/system/bin/linker"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// on android /system/bin/linker comes without any symbols.
|
||||
// Since there is no other way, we scan the data segment for
|
||||
// dcd 1, ?, r_brk, 0, 0
|
||||
// r_debug is located very close to the beginning of the data segment,
|
||||
// we should find it fine. In any case, we check only the first 4KB.
|
||||
bool linux_debmod_t::add_android_shlib_bpt(const meminfo_vec_t &miv, bool attaching)
|
||||
{
|
||||
// find read/writable linker memory range
|
||||
meminfo_vec_t::const_iterator p;
|
||||
ea_t linker_base = BADADDR;
|
||||
for ( p=miv.begin(); p != miv.end(); ++p )
|
||||
{
|
||||
if ( p->name == LINKER )
|
||||
{
|
||||
if ( linker_base == BADADDR )
|
||||
linker_base = p->start_ea;
|
||||
// assume the data segment to be readable and writable
|
||||
if ( (p->perm & 6) == 6 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( p == miv.end() )
|
||||
{
|
||||
msg("Failed to find data segment of " LINKER "\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// read max 2KB
|
||||
uint32 buf[2048];
|
||||
int nbytes = qmin(p->size(), sizeof(buf));
|
||||
ea_t dataseg = p->start_ea;
|
||||
nbytes = dbg_read_memory(dataseg, buf, nbytes, NULL);
|
||||
|
||||
uint32 *ptr = buf;
|
||||
for ( int i=0; i < nbytes/4-5; i++, ptr++ )
|
||||
{
|
||||
if ( ptr[0] == 1 // version
|
||||
&& (attaching || ptr[1] == 0) // r_map, 0 at the beginning
|
||||
&& (ptr[2] & 1) != 0 && ptr[2] < dataseg // r_brk (Thumb pointer)
|
||||
&& (attaching || ptr[3] == 0) // r_state: RT_CONSISTENT
|
||||
&& ptr[4] == 0 ) // linker baseaddr: always zero?
|
||||
{
|
||||
ea_t r_brk = ptr[2] & ~1;
|
||||
// check if linker is not relocated yet
|
||||
if ( r_brk < linker_base )
|
||||
r_brk += linker_base; // adjust address
|
||||
uchar opcode[2];
|
||||
if ( dbg_read_memory(r_brk, opcode, 2, NULL) == 2
|
||||
&& memcmp(opcode, bxlr_thumb, 2) == 0 )
|
||||
{
|
||||
// found it!
|
||||
if ( add_internal_bp(shlib_bpt, r_brk+1) )
|
||||
{
|
||||
dmsg("found r_debug (r_brk=%a)\n", r_brk);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
msg("Failed to find r_debug in " LINKER "\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Android reports shared objects without any path. Try to find full path.
|
||||
void linux_debmod_t::make_android_abspath(qstring *in_out_path)
|
||||
{
|
||||
if ( qisabspath(in_out_path->c_str()) )
|
||||
return;
|
||||
|
||||
// Apparently /proc didn't return an absolute path. Check /system/lib.
|
||||
// Normally we should not arrive here, this is just for safety.
|
||||
char path[QMAXPATH];
|
||||
qmakepath(path, sizeof(path), "/system/lib", in_out_path->c_str(), NULL);
|
||||
if ( qfileexist(path) )
|
||||
*in_out_path = path;
|
||||
}
|
||||
63
idasdk75/dbg/linux/android.hpp
Normal file
63
idasdk75/dbg/linux/android.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
|
||||
Android specific definitions
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __ANDROID_HPP
|
||||
#define __ANDROID_HPP
|
||||
|
||||
// Android NDK lacks link.h, so we have to use our own definitions
|
||||
|
||||
#include <android/api-level.h>
|
||||
#include "dbg_rpc_handler.h"
|
||||
|
||||
struct link_map
|
||||
{
|
||||
uintptr_t l_addr;
|
||||
char * l_name;
|
||||
uintptr_t l_ld;
|
||||
struct link_map * l_next;
|
||||
struct link_map * l_prev;
|
||||
};
|
||||
|
||||
struct r_debug
|
||||
{
|
||||
int32_t r_version;
|
||||
struct link_map * r_map;
|
||||
int32_t r_brk;
|
||||
// Values for r_state
|
||||
enum
|
||||
{
|
||||
RT_CONSISTENT,
|
||||
RT_ADD,
|
||||
RT_DELETE
|
||||
};
|
||||
int32_t r_state;
|
||||
uintptr_t r_ldbase;
|
||||
};
|
||||
|
||||
// pread64 is missing
|
||||
#define pread64 pread
|
||||
|
||||
// thread_db.h lacks many definitions as well:
|
||||
|
||||
#define TD_MIN_EVENT_NUM 0
|
||||
#define TD_MAX_EVENT_NUM 16
|
||||
#define td_eventismember(set, n) (((set)->events & (1 << (n))) != 0)
|
||||
typedef void *prgregset_t;
|
||||
typedef void *prfpregset_t;
|
||||
typedef int td_thr_type_e;
|
||||
extern "C"
|
||||
{
|
||||
inline td_err_e td_init(void) { return TD_OK; }
|
||||
inline td_err_e td_thr_set_event(const td_thrhandle_t *, td_thr_events_t *) { return TD_OK; }
|
||||
inline td_err_e td_thr_setsigpending(const td_thrhandle_t *, unsigned char, const sigset_t *) { return TD_OK; }
|
||||
}
|
||||
|
||||
// Other missing definitions:
|
||||
typedef int32 __ptrace_request;
|
||||
|
||||
#define user_regs pt_regs
|
||||
|
||||
#endif // define __ANDROID_HPP
|
||||
35
idasdk75/dbg/linux/armlinux_stub.cpp
Normal file
35
idasdk75/dbg/linux/armlinux_stub.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#define REMOTE_DEBUGGER
|
||||
#define RPC_CLIENT
|
||||
|
||||
static const char wanted_name[] = "Remote ARM Linux/Android debugger";
|
||||
#define DEBUGGER_NAME "armlinux"
|
||||
#define PROCESSOR_NAME "arm"
|
||||
#define DEFAULT_PLATFORM_NAME "linux"
|
||||
#define TARGET_PROCESSOR PLFM_ARM
|
||||
#define DEBUGGER_ID DEBUGGER_ID_ARM_LINUX_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
|
||||
| DBG_FLAG_SMALLBLKS \
|
||||
| DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD \
|
||||
| DBG_FLAG_PREFER_SWBPTS)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_ELF
|
||||
|
||||
#include <pro.h>
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
#include "dbg_rpc_client.h"
|
||||
#include "rpc_debmod.h"
|
||||
|
||||
rpc_debmod_t g_dbgmod(DEFAULT_PLATFORM_NAME);
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "arm_local_impl.cpp"
|
||||
#include "linux_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
3690
idasdk75/dbg/linux/linux_debmod.cpp
Normal file
3690
idasdk75/dbg/linux/linux_debmod.cpp
Normal file
File diff suppressed because it is too large
Load Diff
349
idasdk75/dbg/linux/linux_debmod.h
Normal file
349
idasdk75/dbg/linux/linux_debmod.h
Normal file
@@ -0,0 +1,349 @@
|
||||
#ifndef __LINUX_DEBUGGER_MODULE__
|
||||
#define __LINUX_DEBUGGER_MODULE__
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "linuxbase_debmod.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <thread_db.h>
|
||||
}
|
||||
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
typedef int HANDLE;
|
||||
typedef uint32 DWORD;
|
||||
#define INVALID_HANDLE_VALUE (-1)
|
||||
|
||||
using std::pair;
|
||||
using std::make_pair;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef std::map<ea_t, qstring> ea2name_t;
|
||||
typedef std::map<qstring, ea_t> name2ea_t;
|
||||
|
||||
#ifndef WCONTINUED
|
||||
#define WCONTINUED 8
|
||||
#endif
|
||||
|
||||
#ifndef __WALL
|
||||
#define __WALL 0x40000000
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// image information
|
||||
struct image_info_t
|
||||
{
|
||||
image_info_t() : base(BADADDR), size(0), dl_crc(0) {}
|
||||
image_info_t(
|
||||
ea_t _base,
|
||||
asize_t _size,
|
||||
const qstring &_fname,
|
||||
const qstring &_soname)
|
||||
: base(_base), size(_size), fname(_fname), soname(_soname), dl_crc(0) {}
|
||||
ea_t base;
|
||||
asize_t size; // image size, currently 0
|
||||
qstring fname;
|
||||
qstring soname;
|
||||
ea2name_t names;
|
||||
qstring buildid;
|
||||
qstring debuglink;
|
||||
uint32 dl_crc;
|
||||
};
|
||||
typedef std::map<ea_t, image_info_t> images_t; // key: image base address
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum thstate_t
|
||||
{
|
||||
RUNNING, // running
|
||||
STOPPED, // waiting to be resumed after qwait
|
||||
DYING, // we got a notification that the thread is about to die
|
||||
DEAD, // dead thread; ignore any signals from it
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// thread information
|
||||
struct thread_info_t
|
||||
{
|
||||
thread_info_t(int t)
|
||||
: tid(t), suspend_count(0), user_suspend(0), child_signum(0), single_step(false),
|
||||
state(STOPPED), waiting_sigstop(false), got_pending_status(false), pending_status(0) {}
|
||||
int tid;
|
||||
int suspend_count;
|
||||
int user_suspend;
|
||||
int child_signum;
|
||||
bool single_step;
|
||||
thstate_t state;
|
||||
bool waiting_sigstop;
|
||||
bool got_pending_status;
|
||||
int pending_status;
|
||||
qstring name; // thread name
|
||||
bool is_running(void) const
|
||||
{
|
||||
return state == RUNNING && !waiting_sigstop && !got_pending_status;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef std::map<HANDLE, thread_info_t> threads_t; // (tid -> info)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum ps_err_e
|
||||
{
|
||||
PS_OK, /* Success. */
|
||||
PS_ERR, /* Generic error. */
|
||||
PS_BADPID, /* Bad process handle. */
|
||||
PS_BADLID, /* Bad LWP id. */
|
||||
PS_BADADDR, /* Bad address. */
|
||||
PS_NOSYM, /* Symbol not found. */
|
||||
PS_NOFREGS /* FPU register set not available. */
|
||||
};
|
||||
struct ps_prochandle
|
||||
{
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
#ifndef UINT32_C
|
||||
# define UINT32_C uint32
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct internal_bpt
|
||||
{
|
||||
ea_t bpt_addr;
|
||||
uchar saved[BPT_CODE_SIZE];
|
||||
uchar nsaved;
|
||||
internal_bpt(): bpt_addr(0), nsaved(0) {} //-V730 Not all members of a class are initialized
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct mapfp_entry_t
|
||||
{
|
||||
ea_t ea1;
|
||||
ea_t ea2;
|
||||
ea_t offset;
|
||||
uint64 inode;
|
||||
char perm[8];
|
||||
char device[8];
|
||||
uint8 bitness; // Number of bits in segment addresses (0-16bit, 1-32bit, 2-64bit)
|
||||
qstring fname;
|
||||
bool empty(void) const { return ea1 >= ea2; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct chk_signal_info_t
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
int timeout_ms;
|
||||
|
||||
chk_signal_info_t(int _timeout_ms)
|
||||
{
|
||||
timeout_ms = _timeout_ms;
|
||||
pid = 0;
|
||||
status = 0;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum attach_mode_t
|
||||
{
|
||||
AMT_NO_ATTACH,
|
||||
AMT_ATTACH_NORMAL,
|
||||
AMT_ATTACH_BROKEN
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class linux_debmod_t: public linuxbase_debmod_t
|
||||
{
|
||||
typedef linuxbase_debmod_t inherited;
|
||||
|
||||
// thread_db related data and functions:
|
||||
struct ps_prochandle prochandle;
|
||||
td_thragent_t *ta;
|
||||
|
||||
internal_bpt birth_bpt; //thread created
|
||||
internal_bpt death_bpt; //thread exited
|
||||
internal_bpt shlib_bpt; //shared lib list changed
|
||||
bool complained_shlib_bpt;
|
||||
|
||||
void make_android_abspath(qstring *in_out_path);
|
||||
bool add_android_shlib_bpt(const meminfo_vec_t &miv, bool attaching);
|
||||
|
||||
bool add_internal_bp(internal_bpt &bp, ea_t addr);
|
||||
bool erase_internal_bp(internal_bpt &bp);
|
||||
|
||||
bool tdb_enable_event(td_event_e event, internal_bpt *bp);
|
||||
void tdb_update_threads(void);
|
||||
bool tdb_new(void);
|
||||
void tdb_delete(void);
|
||||
void tdb_handle_messages(int pid);
|
||||
void dead_thread(int tid, thstate_t state);
|
||||
void store_pending_signal(int pid, int status);
|
||||
|
||||
// procfs
|
||||
void procfs_collect_threads(void);
|
||||
bool attach_collected_thread(unsigned long lwp);
|
||||
bool get_thread_name(qstring *thr_name, thid_t tid);
|
||||
void update_thread_names(thread_name_vec_t *thr_names);
|
||||
|
||||
// list of debug names not yet sent to IDA
|
||||
name_info_t pending_names;
|
||||
name_info_t nptl_names;
|
||||
|
||||
pid_t check_for_signal(int *status, int pid, int timeout_ms) const;
|
||||
|
||||
int find_largest_addrsize(const meminfo_vec_t &miv);
|
||||
void _import_dll(image_info_t &ii);
|
||||
void _import_symbols_from_file(name_info_t *out, image_info_t &ii);
|
||||
|
||||
public:
|
||||
easet_t dlls_to_import; // list of dlls to import information from
|
||||
images_t dlls; // list of loaded DLLs
|
||||
threads_t threads;
|
||||
qvector<thid_t> deleted_threads;
|
||||
qvector<thid_t> seen_threads; // thread was born and appeared too early
|
||||
|
||||
// debugged process information
|
||||
HANDLE process_handle;
|
||||
HANDLE thread_handle;
|
||||
|
||||
bool exited; // Did the process exit?
|
||||
|
||||
easet_t removed_bpts; // removed breakpoints
|
||||
|
||||
FILE *mapfp; // map file handle
|
||||
|
||||
int npending_signals; // number of pending signals
|
||||
bool may_run;
|
||||
bool requested_to_suspend;
|
||||
bool in_event; // IDA kernel is handling a debugger event
|
||||
|
||||
qstring interp;
|
||||
|
||||
qstring exe_path; // name of the executable file
|
||||
|
||||
ea_t nptl_base; // base of 'libpthread.so'
|
||||
|
||||
regctx_t *reg_ctx;
|
||||
|
||||
linux_debmod_t();
|
||||
~linux_debmod_t();
|
||||
|
||||
void init_reg_ctx(void);
|
||||
void term_reg_ctx(void);
|
||||
|
||||
thread_info_t &add_thread(int tid);
|
||||
void del_thread(int tid);
|
||||
thread_info_t *get_thread(thid_t tid);
|
||||
bool retrieve_pending_signal(pid_t *pid, int *status);
|
||||
int get_debug_event(debug_event_t *event, int timeout_ms);
|
||||
bool del_pending_event(event_id_t id, const char *module_name);
|
||||
void enqueue_event(const debug_event_t &ev, queue_pos_t pos);
|
||||
bool suspend_all_threads(void);
|
||||
bool resume_all_threads(void);
|
||||
int dbg_freeze_threads(thid_t tid, bool exclude=true);
|
||||
int dbg_thaw_threads(thid_t tid, bool exclude=true);
|
||||
void set_thread_state(thread_info_t &ti, thstate_t state) const;
|
||||
bool resume_app(thid_t tid);
|
||||
bool has_pending_events(void);
|
||||
bool read_asciiz(tid_t tid, ea_t ea, char *buf, size_t bufsize, bool suspend=false);
|
||||
int _read_memory(int tid, ea_t ea, void *buffer, int size, bool suspend=false);
|
||||
int _write_memory(int tid, ea_t ea, const void *buffer, int size, bool suspend=false);
|
||||
void add_dll(ea_t base, asize_t size, const char *modname, const char *soname);
|
||||
asize_t calc_module_size(const meminfo_vec_t &miv, const memory_info_t *mi) const;
|
||||
void enum_names(const char *libpath=NULL);
|
||||
bool add_shlib_bpt(const meminfo_vec_t &miv, bool attaching);
|
||||
bool gen_library_events(int tid);
|
||||
bool emulate_retn(int tid);
|
||||
void cleanup(void);
|
||||
bool handle_process_start(pid_t pid, attach_mode_t attaching);
|
||||
drc_t get_memory_info(meminfo_vec_t &areas, bool suspend);
|
||||
bool set_hwbpts(HANDLE hThread) const;
|
||||
virtual bool refresh_hwbpts() override;
|
||||
void handle_dll_movements(const meminfo_vec_t &miv);
|
||||
bool idaapi thread_get_fs_base(thid_t tid, int reg_idx, ea_t *pea) const;
|
||||
bool read_mapping(mapfp_entry_t *me);
|
||||
bool get_soname(const char *fname, qstring *soname) const;
|
||||
ea_t find_pending_name(const char *name);
|
||||
bool handle_hwbpt(debug_event_t *event);
|
||||
bool thread_is_known(const td_thrinfo_t &info) const;
|
||||
bool listen_thread_events(const td_thrinfo_t &info, const td_thrhandle_t *th_p);
|
||||
void attach_to_thread(const td_thrinfo_t &info);
|
||||
void attach_to_thread(int tid, ea_t ea);
|
||||
bool check_for_new_events(chk_signal_info_t *csi, bool *event_prepared);
|
||||
void handle_extended_wait(bool *handled, const chk_signal_info_t &csi);
|
||||
|
||||
//
|
||||
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
|
||||
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
|
||||
virtual void idaapi dbg_term(void) override;
|
||||
virtual drc_t idaapi dbg_detach_process(void) override;
|
||||
virtual drc_t idaapi dbg_start_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
qstring *errbuf) override;
|
||||
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
|
||||
virtual drc_t idaapi dbg_attach_process(pid_t process_id, int event_id, int flags, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
|
||||
virtual void idaapi dbg_stopped_at_debug_event(import_infos_t *infos, bool dlls_added, thread_name_vec_t *thr_names) override;
|
||||
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
|
||||
virtual drc_t idaapi dbg_read_registers(
|
||||
thid_t thread_id,
|
||||
int clsmask,
|
||||
regval_t *values,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_write_register(
|
||||
thid_t thread_id,
|
||||
int reg_idx,
|
||||
const regval_t *value,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &areas, qstring *errbuf) override;
|
||||
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
|
||||
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
|
||||
virtual int idaapi handle_ioctl(int fn, const void *buf, size_t size, void **outbuf, ssize_t *outsize) override;
|
||||
virtual bool idaapi write_registers(
|
||||
thid_t tid,
|
||||
int start,
|
||||
int count,
|
||||
const regval_t *values) override;
|
||||
virtual int dbg_freeze_threads_except(thid_t tid) override { return dbg_freeze_threads(tid); }
|
||||
virtual int dbg_thaw_threads_except(thid_t tid) override { return dbg_thaw_threads(tid); }
|
||||
|
||||
virtual bool idaapi dbg_continue_broken_connection(pid_t pid) override;
|
||||
virtual bool idaapi dbg_prepare_broken_connection(void) override;
|
||||
|
||||
// thread_db
|
||||
void display_thrinfo(thid_t tid);
|
||||
void display_all_threads();
|
||||
|
||||
void cleanup_breakpoints(void);
|
||||
void cleanup_signals(void);
|
||||
|
||||
bool fix_instruction_pointer(void) const;
|
||||
#ifdef __ARM__
|
||||
virtual void adjust_swbpt(ea_t *p_ea, int *p_len) override;
|
||||
#endif
|
||||
|
||||
#ifdef LDEB
|
||||
void log(thid_t tid, const char *format, ...);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
15
idasdk75/dbg/linux/linux_debmod.script
Normal file
15
idasdk75/dbg/linux/linux_debmod.script
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
global:
|
||||
PLUGIN;
|
||||
ps_pglobal_lookup;
|
||||
ps_pdread;
|
||||
ps_pdwrite;
|
||||
ps_lgetregs;
|
||||
ps_lsetregs;
|
||||
ps_lgetfpregs;
|
||||
ps_lsetfpregs;
|
||||
ps_getpid;
|
||||
ps_get_thread_area;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
66
idasdk75/dbg/linux/linux_local_impl.cpp
Normal file
66
idasdk75/dbg/linux/linux_local_impl.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include <loader.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// installs or uninstalls debugger specific idc functions
|
||||
inline bool register_idc_funcs(bool)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rebase_if_required_to(ea_t new_base)
|
||||
{
|
||||
ea_t base = get_imagebase();
|
||||
if ( base != BADADDR && new_base != BADADDR && base != new_base )
|
||||
rebase_or_warn(base, new_base);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool init_plugin(void)
|
||||
{
|
||||
#ifndef RPC_CLIENT
|
||||
if ( !init_subsystem() )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool ok = false;
|
||||
do
|
||||
{
|
||||
if ( !netnode::inited() || is_miniidb() || inf_is_snapshot() )
|
||||
{
|
||||
#ifdef __LINUX__
|
||||
// local debugger is available if we are running under Linux
|
||||
return true;
|
||||
#else
|
||||
// for other systems only the remote debugger is available
|
||||
if ( debugger.is_remote() )
|
||||
return true;
|
||||
break; // failed
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( inf_get_filetype() != f_ELF )
|
||||
break;
|
||||
processor_t &ph = PH;
|
||||
if ( ph.id != TARGET_PROCESSOR && ph.id != -1 )
|
||||
break;
|
||||
|
||||
ok = true;
|
||||
} while ( false );
|
||||
#ifndef RPC_CLIENT
|
||||
if ( !ok )
|
||||
term_subsystem();
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void term_plugin(void)
|
||||
{
|
||||
#ifndef RPC_CLIENT
|
||||
term_subsystem();
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "Userland linux debugger plugin.";
|
||||
34
idasdk75/dbg/linux/linux_stub.cpp
Normal file
34
idasdk75/dbg/linux/linux_stub.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#define REMOTE_DEBUGGER
|
||||
#define RPC_CLIENT
|
||||
|
||||
static const char wanted_name[] = "Remote Linux debugger";
|
||||
#define DEBUGGER_NAME "linux"
|
||||
#define PROCESSOR_NAME "metapc"
|
||||
#define DEFAULT_PLATFORM_NAME "linux"
|
||||
#define TARGET_PROCESSOR PLFM_386
|
||||
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_LINUX_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
|
||||
| DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD)
|
||||
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_ELF
|
||||
|
||||
#include <pro.h>
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
#include "dbg_rpc_client.h"
|
||||
#include "rpc_debmod.h"
|
||||
|
||||
rpc_debmod_t g_dbgmod(DEFAULT_PLATFORM_NAME);
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "pc_local_impl.cpp"
|
||||
#include "linux_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
1275
idasdk75/dbg/linux/linux_threads.cpp
Normal file
1275
idasdk75/dbg/linux/linux_threads.cpp
Normal file
File diff suppressed because it is too large
Load Diff
26
idasdk75/dbg/linux/linux_user.cpp
Normal file
26
idasdk75/dbg/linux/linux_user.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
static const char wanted_name[] = "Local Linux debugger";
|
||||
#define DEBUGGER_NAME "linux"
|
||||
#define PROCESSOR_NAME "metapc"
|
||||
#define TARGET_PROCESSOR PLFM_386
|
||||
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_LINUX_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD)
|
||||
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_ELF
|
||||
|
||||
#include <fpro.h>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include "linux_debmod.h"
|
||||
|
||||
linux_debmod_t g_dbgmod;
|
||||
bool ignore_sigint = false;
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "pc_local_impl.cpp"
|
||||
#include "linux_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
8
idasdk75/dbg/linux/linux_wait.cpp
Normal file
8
idasdk75/dbg/linux/linux_wait.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#include <pro.h>
|
||||
#include "linux_debmod.h"
|
||||
//--------------------------------------------------------------------------
|
||||
pid_t linux_debmod_t::check_for_signal(int *status, int _pid, int timeout_ms) const
|
||||
{
|
||||
return qwait_timed(status, _pid, __WALL | WCONTINUED, timeout_ms);
|
||||
}
|
||||
138
idasdk75/dbg/linux/linuxbase_debmod.cpp
Normal file
138
idasdk75/dbg/linux/linuxbase_debmod.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <fpro.h>
|
||||
#include <prodir.h>
|
||||
#include <diskio.hpp>
|
||||
#include "linuxbase_debmod.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static inline const char *str_bitness(int bitness)
|
||||
{
|
||||
switch ( bitness )
|
||||
{
|
||||
case 8:
|
||||
return "[64]";
|
||||
case 4:
|
||||
return "[32]";
|
||||
default:
|
||||
return "[x]";
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void build_process_ext_name(ext_process_info_t *pinfo)
|
||||
{
|
||||
pinfo->ext_name = str_bitness(pinfo->addrsize);
|
||||
|
||||
char buf[QMAXPATH];
|
||||
qsnprintf(buf, sizeof(buf), "/proc/%u/cmdline", pinfo->pid);
|
||||
|
||||
FILE *cmdfp = qfopen(buf, "r");
|
||||
if ( cmdfp == nullptr )
|
||||
return;
|
||||
|
||||
int size = qfread(cmdfp, buf, sizeof(buf));
|
||||
qfclose(cmdfp);
|
||||
|
||||
for ( int i=0; i < size; )
|
||||
{
|
||||
const char *in = &buf[i];
|
||||
qstring arg = in;
|
||||
quote_cmdline_arg(&arg);
|
||||
pinfo->ext_name.append(" ");
|
||||
pinfo->ext_name.append(arg);
|
||||
|
||||
i += strlen(in) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Returns the file name assciated with pid
|
||||
bool idaapi linuxbase_debmod_t::get_exec_fname(
|
||||
int _pid,
|
||||
char *buf,
|
||||
size_t bufsize)
|
||||
{
|
||||
char path[QMAXPATH];
|
||||
qsnprintf(path, sizeof(path), "/proc/%u/exe", _pid);
|
||||
int len = readlink(path, buf, bufsize-1);
|
||||
if ( len > 0 )
|
||||
{
|
||||
buf[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESXi keeps the real file name inside /proc/PID/exe (which is not a link)
|
||||
FILE *fp = qfopen(path, "r");
|
||||
if ( fp != NULL )
|
||||
{
|
||||
len = qfread(fp, buf, bufsize);
|
||||
qfclose(fp);
|
||||
if ( len > 1 && len < bufsize && buf[0] == '/' ) // sanity check
|
||||
{
|
||||
buf[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
buf[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
|
||||
int idaapi linuxbase_debmod_t::get_process_bitness(int _pid)
|
||||
{
|
||||
char fname[QMAXPATH];
|
||||
qsnprintf(fname, sizeof(fname), "/proc/%u/maps", _pid);
|
||||
FILE *mapfp = fopenRT(fname);
|
||||
if ( mapfp == NULL )
|
||||
return 0;
|
||||
|
||||
int bitness = 4;
|
||||
qstring line;
|
||||
while ( qgetline(&line, mapfp) >= 0 )
|
||||
{
|
||||
if ( line.empty() )
|
||||
continue;
|
||||
ea_t ea1;
|
||||
ea_t ea2;
|
||||
if ( qsscanf(line.begin(), "%a-%a ", &ea1, &ea2) == 2 )
|
||||
{
|
||||
size_t pos = line.find('-');
|
||||
if ( pos != qstring::npos && pos > 8 )
|
||||
{
|
||||
bitness = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
qfclose(mapfp);
|
||||
return bitness;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi linuxbase_debmod_t::get_process_list(procvec_t *list, qstring *)
|
||||
{
|
||||
int mypid = getpid();
|
||||
list->clear();
|
||||
qffblk64_t fb;
|
||||
for ( int code = qfindfirst("/proc/*", &fb, FA_DIREC);
|
||||
code == 0;
|
||||
code = qfindnext(&fb) )
|
||||
{
|
||||
if ( !qisdigit(fb.ff_name[0]) )
|
||||
continue;
|
||||
ext_process_info_t pinfo;
|
||||
pinfo.pid = atoi(fb.ff_name);
|
||||
if ( pinfo.pid == mypid )
|
||||
continue;
|
||||
char buf[MAXSTR];
|
||||
if ( !get_exec_fname(pinfo.pid, buf, sizeof(buf)) )
|
||||
continue; // we skip the process because we cannot debug it anyway
|
||||
pinfo.name = buf;
|
||||
pinfo.addrsize = get_process_bitness(pinfo.pid);
|
||||
build_process_ext_name(&pinfo);
|
||||
list->push_back(pinfo);
|
||||
}
|
||||
return list->size();
|
||||
}
|
||||
30
idasdk75/dbg/linux/linuxbase_debmod.h
Normal file
30
idasdk75/dbg/linux/linuxbase_debmod.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef __LINUXBASE_HPP__
|
||||
#define __LINUXBASE_HPP__
|
||||
|
||||
#include "debmod.h"
|
||||
|
||||
// Base class for linux modules
|
||||
|
||||
#ifdef __ARM__
|
||||
# define BASE_DEBUGGER_MODULE arm_debmod_t
|
||||
# include "arm_debmod.h"
|
||||
# define BPT_CODE_SIZE ARM_BPT_SIZE
|
||||
#else
|
||||
# define BASE_DEBUGGER_MODULE pc_debmod_t
|
||||
# include "pc_debmod.h"
|
||||
# define BPT_CODE_SIZE X86_BPT_SIZE
|
||||
#endif
|
||||
|
||||
class linuxbase_debmod_t: public BASE_DEBUGGER_MODULE
|
||||
{
|
||||
typedef BASE_DEBUGGER_MODULE inherited;
|
||||
protected:
|
||||
// return number of processes, -1 - not implemented
|
||||
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf) override;
|
||||
// return the file name assciated with pid
|
||||
virtual bool idaapi get_exec_fname(int pid, char *buf, size_t bufsize) newapi;
|
||||
// get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
|
||||
virtual int idaapi get_process_bitness(int pid) newapi;
|
||||
};
|
||||
|
||||
#endif
|
||||
149
idasdk75/dbg/linux/makefile
Normal file
149
idasdk75/dbg/linux/makefile
Normal file
@@ -0,0 +1,149 @@
|
||||
include ../../allmake.mak
|
||||
|
||||
GOALS-$(BUILD_IDA) += modules # target in $(IDA)module.mak
|
||||
GOALS-$(BUILD_DBGSRV) += server # target in $(IDA)dbg/server.mak
|
||||
.PHONY: $(GOALS-1)
|
||||
all: $(GOALS-1)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
ifdef __LINUX__
|
||||
SERVER = linux_server$(SUFF64)
|
||||
endif
|
||||
ifdef SERVER
|
||||
SERVERS += $(call server_exe,$(SERVER))
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
USER = $(call module_dll,linux_user)
|
||||
ifeq ($(and $(BUILD_IDA),$(__LINUX__)),1)
|
||||
MODULES += $(USER)
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# we explicitly added our module targets
|
||||
NO_DEFAULT_TARGETS = 1
|
||||
|
||||
# NOTE: all MODULES must be defined before including plugin.mak.
|
||||
include ../plugin.mak
|
||||
# NOTE: target-specific rules and dependencies that use variable
|
||||
# expansion to name the target (such as "$(MODULE): [...]") must
|
||||
# come after including plugin.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# select OBJS common to user plugin and debugger server
|
||||
ifeq ($(or $(__LINUX__),$(__ANDROID__),$(__ANDROID_X86__),$(__ARMLINUX__)),1)
|
||||
BUILD_LINUX:=1
|
||||
endif
|
||||
|
||||
BASE_OBJS-$(BUILD_LINUX) += $(F)linuxbase_debmod$(O)
|
||||
BASE_OBJS-$(BUILD_LINUX) += $(F)linux_debmod$(O)
|
||||
BASE_OBJS-$(BUILD_LINUX) += $(F)linux_wait$(O)
|
||||
|
||||
BASE_OBJS += $(BASE_OBJS-1) $(F)symelf$(O)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
ifdef __LINUX__
|
||||
SERVER_LDFLAGS += -Wl,--version-script=linux_debmod.script
|
||||
SERVER_LDFLAGS += $(OUTMAP)$(F)$(@F).map
|
||||
SERVER_STDLIBS += -lthread_db -lrt -lc -lpthread -ldl
|
||||
endif
|
||||
SERVER_OBJS += $(BASE_OBJS)
|
||||
|
||||
# suppress warnings for libthread_db.c
|
||||
$(F)libthread_db$(O): WARNS = $(NOWARNS)
|
||||
|
||||
include ../server.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
STUB_OBJS += $(F)linux_stub$(O)
|
||||
$(STUB): MODULE_OBJS += $(STUB_OBJS)
|
||||
$(STUB): $(STUB_OBJS)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
USER_OBJS += $(F)linux_user$(O)
|
||||
USER_OBJS += $(BASE_OBJS)
|
||||
$(USER): MODULE_OBJS += $(USER_OBJS)
|
||||
$(USER): $(USER_OBJS)
|
||||
$(USER): DEFFILE = linux_debmod.script
|
||||
$(USER): STDLIBS += -ldl
|
||||
$(USER): STDLIBS += -lthread_db
|
||||
|
||||
ifeq ($(COMPILER_NAME),gcc)
|
||||
$(USER): LDFLAGS += -Wl,--export-dynamic
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
include $(IDA)objdir.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)armlinux_stub$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../arm_local_impl.cpp ../arm_regs.cpp ../arm_regs.hpp \
|
||||
../common_local_impl.cpp ../common_stub_impl.cpp \
|
||||
../dbg_rpc_client.h ../dbg_rpc_engine.h ../deb_arm.hpp \
|
||||
../debmod.h ../rpc_debmod.h armlinux_stub.cpp \
|
||||
linux_local_impl.cpp
|
||||
$(F)libthread_db$(O): libthread_db.c
|
||||
$(F)linux_debmod$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)diskio.hpp $(I)err.h $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp $(I)pro.h \
|
||||
$(I)prodir.h $(I)range.hpp $(I)segment.hpp $(I)ua.hpp \
|
||||
$(I)xref.hpp ../../plugins/dwarf/look_for_debug_file.cpp \
|
||||
../arm_debmod.h ../arm_regs.hpp ../dbg_rpc_engine.h \
|
||||
../dbg_rpc_handler.h ../dbg_rpc_handler_ioctls.h \
|
||||
../deb_arm.hpp ../deb_pc.hpp ../debmod.h ../pc_debmod.h \
|
||||
../pc_regs.hpp android.cpp android.hpp linux_debmod.cpp \
|
||||
linux_debmod.h linux_threads.cpp linuxbase_debmod.h \
|
||||
symelf.hpp
|
||||
$(F)linux_stub$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../common_local_impl.cpp ../common_stub_impl.cpp \
|
||||
../dbg_rpc_client.h ../dbg_rpc_engine.h ../deb_pc.hpp \
|
||||
../debmod.h ../pc_local_impl.cpp ../pc_regs.hpp \
|
||||
../rpc_debmod.h linux_local_impl.cpp linux_stub.cpp
|
||||
$(F)linux_user$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../arm_debmod.h ../common_local_impl.cpp \
|
||||
../common_stub_impl.cpp ../deb_arm.hpp ../deb_pc.hpp \
|
||||
../debmod.h ../pc_debmod.h ../pc_local_impl.cpp \
|
||||
../pc_regs.hpp linux_debmod.h linux_local_impl.cpp \
|
||||
linux_user.cpp linuxbase_debmod.h
|
||||
$(F)linux_wait$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)ua.hpp \
|
||||
$(I)xref.hpp ../arm_debmod.h ../deb_arm.hpp \
|
||||
../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \
|
||||
linux_debmod.h linux_wait.cpp linuxbase_debmod.h
|
||||
$(F)linuxbase_debmod$(O): $(I)bytes.hpp $(I)diskio.hpp $(I)fpro.h \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)prodir.h $(I)range.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../arm_debmod.h ../deb_arm.hpp \
|
||||
../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \
|
||||
linuxbase_debmod.cpp linuxbase_debmod.h
|
||||
$(F)symelf$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
|
||||
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
symelf.hpp
|
||||
239
idasdk75/dbg/linux/symelf.cpp
Normal file
239
idasdk75/dbg/linux/symelf.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
|
||||
// read elf symbols
|
||||
|
||||
#include <fpro.h>
|
||||
#include <kernwin.hpp>
|
||||
#include <diskio.hpp>
|
||||
#include "../../ldr/elf/elfbase.h"
|
||||
#include "../../ldr/elf/elf.h"
|
||||
#include "debmod.h"
|
||||
#include "symelf.hpp"
|
||||
|
||||
#include "../../ldr/elf/common.cpp"
|
||||
#include "../../ldr/elf/reader.cpp"
|
||||
|
||||
inline uint32 low(uint32 x) { return x; }
|
||||
|
||||
uval_t imagebase;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{1764} could be declared const ref
|
||||
static int handle_symbol(
|
||||
reader_t &reader,
|
||||
int shndx,
|
||||
int _info,
|
||||
uint32 st_name,
|
||||
uval_t st_value,
|
||||
slice_type_t slice_type,
|
||||
symbol_visitor_t &sv)
|
||||
{
|
||||
if ( shndx == SHN_UNDEF
|
||||
|| shndx == SHN_LOPROC
|
||||
|| shndx == SHN_HIPROC
|
||||
|| shndx == SHN_ABS )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int type = ELF_ST_TYPE(_info);
|
||||
if ( type != STT_OBJECT && type != STT_FUNC )
|
||||
return 0;
|
||||
|
||||
if ( st_name == 0 )
|
||||
return 0;
|
||||
|
||||
if ( imagebase != uval_t(-1) )
|
||||
st_value -= imagebase;
|
||||
|
||||
qstring name;
|
||||
reader.get_name(&name, slice_type, st_name);
|
||||
return sv.visit_symbol(st_value, name.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int load_symbols(
|
||||
reader_t &reader,
|
||||
const elf_shdr_t §ion,
|
||||
slice_type_t slice_type,
|
||||
symbol_visitor_t &sv)
|
||||
{
|
||||
int code = 0;
|
||||
sym_rel *sym;
|
||||
buffered_input_t<sym_rel> symbols_input(reader, section);
|
||||
for ( elf_sym_idx_t i = 0; code == 0 && symbols_input.next(sym); ++i )
|
||||
{
|
||||
if ( i == 0 ) // skip _UNDEF
|
||||
continue;
|
||||
|
||||
code = handle_symbol(reader,
|
||||
sym->original.st_shndx,
|
||||
sym->original.st_info,
|
||||
sym->original.st_name,
|
||||
sym->original.st_value,
|
||||
slice_type,
|
||||
sv);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool map_pht(reader_t &reader)
|
||||
{
|
||||
if ( !reader.read_program_headers() )
|
||||
return false;
|
||||
|
||||
imagebase = reader.pheaders.get_image_base();
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool silent_handler(const reader_t &reader, reader_t::errcode_t code, ...)
|
||||
{
|
||||
return reader.is_warning(code); // resume after warnings
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int _load_elf_symbols(linput_t *li, symbol_visitor_t &sv)
|
||||
{
|
||||
reader_t reader(li);
|
||||
reader.set_handler(silent_handler);
|
||||
if ( !reader.read_ident() || !reader.read_header() )
|
||||
return -1;
|
||||
|
||||
const elf_ident_t &ident = reader.get_ident();
|
||||
uint8 elf_class = ident.elf_class;
|
||||
if ( elf_class != ELFCLASS32 && elf_class != ELFCLASS64 )
|
||||
return -1;
|
||||
|
||||
uint8 elf_data_ord = ident.bytesex;
|
||||
if ( elf_data_ord != ELFDATA2LSB && elf_data_ord != ELFDATA2MSB )
|
||||
return -1;
|
||||
|
||||
section_headers_t §ions = reader.sections;
|
||||
dynamic_linking_tables_t dlt;
|
||||
|
||||
int code = 0;
|
||||
elf_ehdr_t &header = reader.get_header();
|
||||
if ( header.has_pht() && !map_pht(reader) )
|
||||
return -1;
|
||||
|
||||
reader.read_section_headers();
|
||||
|
||||
// Try and acquire dynamic linking tables info.
|
||||
dlt = reader.sections.get_dynamic_linking_tables_info();
|
||||
if ( !dlt.is_valid() )
|
||||
dlt = reader.pheaders.get_dynamic_linking_tables_info();
|
||||
|
||||
// Parse dynamic info if available
|
||||
dynamic_info_t di;
|
||||
if ( dlt.is_valid() )
|
||||
{
|
||||
reader_t::dyninfo_tags_t dyninfo_tags;
|
||||
dyninfo_tags.reserve(10);
|
||||
if ( reader.read_dynamic_info_tags(&dyninfo_tags, dlt)
|
||||
&& reader.parse_dynamic_info(&di, dyninfo_tags)
|
||||
&& (sv.velf & VISIT_DYNINFO) != 0 )
|
||||
{
|
||||
reader.set_di_strtab(reader.dyn_strtab, di.strtab());
|
||||
typedef reader_t::dyninfo_tags_t::const_iterator const_it;
|
||||
for ( const_it dyn = dyninfo_tags.begin();
|
||||
dyn != dyninfo_tags.end();
|
||||
++dyn )
|
||||
{
|
||||
qstring name;
|
||||
switch ( dyn->d_tag )
|
||||
{
|
||||
case DT_SONAME:
|
||||
case DT_RPATH:
|
||||
case DT_RUNPATH:
|
||||
case DT_NEEDED:
|
||||
reader.get_name(&name, reader.dyn_strtab, uint32(dyn->d_un));
|
||||
break;
|
||||
}
|
||||
if ( sv.visit_dyninfo(dyn->d_tag, name.c_str(), dyn->d_un) != 0 )
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if ( (sv.velf & VISIT_INTERP) != 0 )
|
||||
{
|
||||
elf_shdr_t *interp_sh = reader.sections.get_wks(WKS_INTERP);
|
||||
if ( interp_sh != NULL )
|
||||
{
|
||||
qstring name;
|
||||
reader.get_string_at(&name, interp_sh->sh_offset);
|
||||
code = sv.visit_interp(name.c_str());
|
||||
if ( code != 0 )
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (sv.velf & VISIT_SYMBOLS) != 0 )
|
||||
{
|
||||
elf_shndx_t symtab = sections.get_index(WKS_SYMTAB);
|
||||
elf_shndx_t dynsym = sections.get_index(WKS_DYNSYM);
|
||||
elf_shdr_t fake_section;
|
||||
if ( symtab != 0 || dynsym != 0 )
|
||||
{
|
||||
// Loading symbols
|
||||
if ( symtab != 0 )
|
||||
code = load_symbols(reader, *sections.getn(symtab), SLT_SYMTAB, sv);
|
||||
if ( code == 0 && dynsym != 0 )
|
||||
code = load_symbols(reader, *sections.getn(dynsym), SLT_DYNSYM, sv);
|
||||
}
|
||||
else if ( di.fill_section_header(&fake_section, DIT_SYMTAB) )
|
||||
{
|
||||
code = load_symbols(reader, fake_section, SLT_DYNSYM, sv);
|
||||
}
|
||||
}
|
||||
|
||||
notes_t notes(&reader);
|
||||
if ( (sv.velf & VISIT_BUILDID) != 0 && reader.read_notes(¬es) )
|
||||
{
|
||||
qstring id;
|
||||
if ( notes.get_build_id(&id) )
|
||||
{
|
||||
code = sv.visit_buildid(id.c_str());
|
||||
if ( code != 0 )
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (sv.velf & VISIT_DBGLINK ) != 0 )
|
||||
{
|
||||
uint32 crc;
|
||||
qstring debuglink;
|
||||
if ( sections.is_initialized()
|
||||
&& sections.read_gnu_debuglink(&debuglink, &crc) )
|
||||
{
|
||||
code = sv.visit_debuglink(debuglink.c_str(), crc);
|
||||
if ( code != 0 )
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int load_linput_elf_symbols(linput_t *li, symbol_visitor_t &sv)
|
||||
{
|
||||
if ( li == NULL )
|
||||
return -1;
|
||||
int code;
|
||||
// there is thread unsafe code in elf handling, so use locks
|
||||
lock_begin();
|
||||
{
|
||||
code = _load_elf_symbols(li, sv);
|
||||
}
|
||||
lock_end();
|
||||
close_linput(li);
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int load_elf_symbols(const char *fname, symbol_visitor_t &sv, bool remote)
|
||||
{
|
||||
return load_linput_elf_symbols(open_linput(fname, remote), sv);
|
||||
}
|
||||
30
idasdk75/dbg/linux/symelf.hpp
Normal file
30
idasdk75/dbg/linux/symelf.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// read symbols from an elf file
|
||||
#ifndef __SYMELF__
|
||||
#define __SYMELF__
|
||||
|
||||
struct symbol_visitor_t
|
||||
{
|
||||
symbol_visitor_t(int visit_flags) : velf(visit_flags) {}
|
||||
|
||||
int velf;
|
||||
#define VISIT_SYMBOLS 0x0001
|
||||
#define VISIT_INTERP 0x0002
|
||||
#define VISIT_DYNINFO 0x0004
|
||||
#define VISIT_SEGMENTS 0x0008
|
||||
#define VISIT_BUILDID 0x0010
|
||||
#define VISIT_DBGLINK 0x0020
|
||||
|
||||
// any callback returns nonzero - stop enumeration
|
||||
virtual int visit_symbol(ea_t /*ea*/, const char * /*name*/) { return 0; }
|
||||
virtual int visit_interp(const char * /*name*/) { return 0; }
|
||||
virtual int visit_segment(ea_t /*start*/, size_t /*size*/, const char * /*name*/) { return 0; }
|
||||
virtual int visit_dyninfo(uint64 /*tag*/, const char * /*name*/, uint64 /*value*/) { return 0; }
|
||||
virtual int visit_buildid(const char * /*Build ID*/) { return 0; }
|
||||
virtual int visit_debuglink(const char * /*debug*/, uint32 /*crc*/) { return 0; }
|
||||
};
|
||||
|
||||
// returns -1 on errors
|
||||
// otherwise returns the non-zero code returned by the visitor or 0
|
||||
int load_elf_symbols(const char *fname, symbol_visitor_t &sv, bool remote=false);
|
||||
|
||||
#endif
|
||||
23
idasdk75/dbg/mac/dbg_macosx.cfg
Normal file
23
idasdk75/dbg/mac/dbg_macosx.cfg
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
// This option is ideal when working with the Remote Mac OSX Debugger.
|
||||
// It allows IDA to parse symbol data for dyld_shared_cache libs locally, rather than
|
||||
// transferring symbol names over the wire, which can save a significant amount of time.
|
||||
//
|
||||
// Here's an example of how to use it:
|
||||
//
|
||||
// First download the ios_deploy utility at: https://www.hex-rays.com/products/ida/support/ida/ios_deploy.zip.
|
||||
// Then run the following commands on the remote OSX machine:
|
||||
//
|
||||
// $ mkdir ~/Symbols
|
||||
// $ ios_deploy symbols -c /var/db/dyld/dyld_shared_cache_x86_64h -d ~/Symbols
|
||||
// $ ios_deploy symbols -c /var/db/dyld/dyld_shared_cache_i386 -d ~/Symbols
|
||||
//
|
||||
// Then, on the client machine running IDA:
|
||||
//
|
||||
// $ scp -r user@mac:Symbols ~/
|
||||
// set SYMBOL_PATH = "~/Symbols" in dbg_macosx.cfg
|
||||
// start IDA and run the debugger, symbol loading should now be much faster
|
||||
//
|
||||
// Any errors will be printed to the console.
|
||||
|
||||
SYMBOL_PATH = "";
|
||||
3139
idasdk75/dbg/mac/mac_debmod.cpp
Normal file
3139
idasdk75/dbg/mac/mac_debmod.cpp
Normal file
File diff suppressed because it is too large
Load Diff
546
idasdk75/dbg/mac/mac_debmod.h
Normal file
546
idasdk75/dbg/mac/mac_debmod.h
Normal file
@@ -0,0 +1,546 @@
|
||||
#ifndef __MAC_DEBUGGER_MODULE__
|
||||
#define __MAC_DEBUGGER_MODULE__
|
||||
|
||||
/*
|
||||
* This is the mach (MAC OS X) debugger module
|
||||
*
|
||||
* Functions unique for Mach (MAC OS X)
|
||||
*
|
||||
*/
|
||||
#include <map>
|
||||
|
||||
#include <pro.h>
|
||||
#include <fpro.h>
|
||||
#include <err.h>
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <name.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <diskio.hpp>
|
||||
#include <ua.hpp>
|
||||
|
||||
#define MD msg("at line %d\n", __LINE__);
|
||||
|
||||
#define processor_t mach_processor_t
|
||||
|
||||
#include <grp.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <mach-o/reloc.h>
|
||||
#include <mach-o/nlist.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/shared_region.h>
|
||||
#include <Security/Security.h>
|
||||
#include <Security/SecCode.h> // needed for SDK versions <= 10.7
|
||||
#undef processor_t
|
||||
|
||||
#include "macbase_debmod.h"
|
||||
|
||||
typedef int HANDLE;
|
||||
class mac_debmod_t;
|
||||
|
||||
#define INVALID_HANDLE_VALUE (-1)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// DEBUGGER INTERNAL DATA
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
enum run_state_t
|
||||
{
|
||||
rs_running,
|
||||
rs_pausing,
|
||||
rs_suspended, // used by iphone
|
||||
rs_exiting,
|
||||
rs_exited
|
||||
};
|
||||
|
||||
// image information
|
||||
struct image_info_t
|
||||
{
|
||||
ea_t base;
|
||||
asize_t size;
|
||||
qstring name;
|
||||
bytevec_t uuid;
|
||||
|
||||
image_info_t() { clear(); }
|
||||
image_info_t(ea_t _base, uint32 _size, const qstring &_name, const bytevec_t &_uuid)
|
||||
: base(_base), size(_size), name(_name), uuid(_uuid) {}
|
||||
|
||||
void clear()
|
||||
{
|
||||
base = BADADDR;
|
||||
size = 0;
|
||||
name.clear();
|
||||
uuid.clear();
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<ea_t, image_info_t> images_t; // key: image base address
|
||||
|
||||
union my_mach_msg_t
|
||||
{
|
||||
mach_msg_header_t hdr;
|
||||
char data[1024];
|
||||
void display(const char *header);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum block_type_t
|
||||
{
|
||||
bl_none, // process is running
|
||||
bl_signal, // blocked due to a signal (must say PTRACE_CONT)
|
||||
bl_exception, // blocked due to an exception (must say task_resume())
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// thread information
|
||||
//-V:ida_thread_info_t:730 Not all members of a class are initialized inside the constructor. Consider inspecting: excmsg.
|
||||
struct ida_thread_info_t
|
||||
{
|
||||
ida_thread_info_t(thid_t t, mach_port_t p)
|
||||
: tid(t), port(p), child_signum(0), asked_step(false), single_step(false),
|
||||
pending_sigstop(false), block(bl_none), run_handled(false) {}
|
||||
int tid;
|
||||
mach_port_t port;
|
||||
int child_signum;
|
||||
bool asked_step;
|
||||
bool single_step;
|
||||
bool pending_sigstop;
|
||||
block_type_t block;
|
||||
my_mach_msg_t excmsg;
|
||||
bool run_handled;
|
||||
bool blocked(void) const { return block != bl_none; }
|
||||
};
|
||||
|
||||
typedef std::map<int, ida_thread_info_t> threads_t; // (tid -> info)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct mach_exception_port_info_t
|
||||
{
|
||||
exception_mask_t masks[EXC_TYPES_COUNT];
|
||||
mach_port_t ports[EXC_TYPES_COUNT];
|
||||
exception_behavior_t behaviors[EXC_TYPES_COUNT];
|
||||
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
|
||||
mach_msg_type_number_t count;
|
||||
};
|
||||
|
||||
typedef qvector<struct nlist_64> nlists_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct mach_exception_info_t
|
||||
{
|
||||
task_t task_port;
|
||||
thread_t thread_port;
|
||||
exception_type_t exception_type;
|
||||
exception_data_t exception_data;
|
||||
mach_msg_type_number_t data_count;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef janitor_t<AuthorizationRef> auth_ref_janitor_t;
|
||||
template <> inline auth_ref_janitor_t::~janitor_t()
|
||||
{
|
||||
if ( resource != NULL )
|
||||
AuthorizationFree(resource, kAuthorizationFlagDefaults);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef janitor_t<AuthorizationRights *> auth_rights_janitor_t;
|
||||
template <> inline auth_rights_janitor_t::~janitor_t()
|
||||
{
|
||||
if ( resource != NULL )
|
||||
AuthorizationFreeItemSet(resource);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef janitor_t<SecCodeRef> sec_code_janitor_t;
|
||||
template <> inline sec_code_janitor_t::~janitor_t()
|
||||
{
|
||||
if ( resource != NULL )
|
||||
CFRelease(resource);
|
||||
}
|
||||
|
||||
struct vm_region_visitor_t
|
||||
{
|
||||
virtual int visit_region(memory_info_t &mi) = 0;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct machine_thread_state_t
|
||||
{
|
||||
ea_t __eax;
|
||||
ea_t __ebx;
|
||||
ea_t __ecx;
|
||||
ea_t __edx;
|
||||
ea_t __edi;
|
||||
ea_t __esi;
|
||||
ea_t __ebp;
|
||||
ea_t __esp;
|
||||
ea_t __eip;
|
||||
ea_t __r8;
|
||||
ea_t __r9;
|
||||
ea_t __r10;
|
||||
ea_t __r11;
|
||||
ea_t __r12;
|
||||
ea_t __r13;
|
||||
ea_t __r14;
|
||||
ea_t __r15;
|
||||
ea_t __eflags;
|
||||
ea_t __ss;
|
||||
ea_t __cs;
|
||||
ea_t __ds;
|
||||
ea_t __es;
|
||||
ea_t __fs;
|
||||
ea_t __gs;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct machine_float_state_t
|
||||
{
|
||||
uint16 __fpu_fcw;
|
||||
uint16 __fpu_fsw;
|
||||
uint8 __fpu_ftw;
|
||||
uint16 __fpu_fop;
|
||||
uint32 __fpu_ip;
|
||||
uint16 __fpu_cs;
|
||||
uint32 __fpu_dp;
|
||||
uint16 __fpu_ds;
|
||||
uint32 __fpu_mxcsr;
|
||||
uint32 __fpu_mxcsrmask;
|
||||
|
||||
_STRUCT_MMST_REG __fpu_stmm0;
|
||||
_STRUCT_MMST_REG __fpu_stmm1;
|
||||
_STRUCT_MMST_REG __fpu_stmm2;
|
||||
_STRUCT_MMST_REG __fpu_stmm3;
|
||||
_STRUCT_MMST_REG __fpu_stmm4;
|
||||
_STRUCT_MMST_REG __fpu_stmm5;
|
||||
_STRUCT_MMST_REG __fpu_stmm6;
|
||||
_STRUCT_MMST_REG __fpu_stmm7;
|
||||
|
||||
_STRUCT_XMM_REG __fpu_xmm0;
|
||||
_STRUCT_XMM_REG __fpu_xmm1;
|
||||
_STRUCT_XMM_REG __fpu_xmm2;
|
||||
_STRUCT_XMM_REG __fpu_xmm3;
|
||||
_STRUCT_XMM_REG __fpu_xmm4;
|
||||
_STRUCT_XMM_REG __fpu_xmm5;
|
||||
_STRUCT_XMM_REG __fpu_xmm6;
|
||||
_STRUCT_XMM_REG __fpu_xmm7;
|
||||
_STRUCT_XMM_REG __fpu_xmm8;
|
||||
_STRUCT_XMM_REG __fpu_xmm9;
|
||||
_STRUCT_XMM_REG __fpu_xmm10;
|
||||
_STRUCT_XMM_REG __fpu_xmm11;
|
||||
_STRUCT_XMM_REG __fpu_xmm12;
|
||||
_STRUCT_XMM_REG __fpu_xmm13;
|
||||
_STRUCT_XMM_REG __fpu_xmm14;
|
||||
_STRUCT_XMM_REG __fpu_xmm15;
|
||||
|
||||
_STRUCT_XMM_REG __fpu_ymmh0;
|
||||
_STRUCT_XMM_REG __fpu_ymmh1;
|
||||
_STRUCT_XMM_REG __fpu_ymmh2;
|
||||
_STRUCT_XMM_REG __fpu_ymmh3;
|
||||
_STRUCT_XMM_REG __fpu_ymmh4;
|
||||
_STRUCT_XMM_REG __fpu_ymmh5;
|
||||
_STRUCT_XMM_REG __fpu_ymmh6;
|
||||
_STRUCT_XMM_REG __fpu_ymmh7;
|
||||
_STRUCT_XMM_REG __fpu_ymmh8;
|
||||
_STRUCT_XMM_REG __fpu_ymmh9;
|
||||
_STRUCT_XMM_REG __fpu_ymmh10;
|
||||
_STRUCT_XMM_REG __fpu_ymmh11;
|
||||
_STRUCT_XMM_REG __fpu_ymmh12;
|
||||
_STRUCT_XMM_REG __fpu_ymmh13;
|
||||
_STRUCT_XMM_REG __fpu_ymmh14;
|
||||
_STRUCT_XMM_REG __fpu_ymmh15;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct machine_debug_state_t
|
||||
{
|
||||
ea_t __dr0;
|
||||
ea_t __dr1;
|
||||
ea_t __dr2;
|
||||
ea_t __dr3;
|
||||
ea_t __dr4;
|
||||
ea_t __dr5;
|
||||
ea_t __dr6;
|
||||
ea_t __dr7;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class mac_debmod_t: public macbase_debmod_t
|
||||
{
|
||||
typedef macbase_debmod_t inherited;
|
||||
public:
|
||||
procinfo_vec_t processes;
|
||||
|
||||
// debugged process information
|
||||
mach_port_t task; // debugged application's task port
|
||||
|
||||
cpu_type_t cputype; // process' CPU type (e.g. CPU_TYPE_I386 or CPU_TYPE_X86_64)
|
||||
|
||||
bool in_ptrace; // We use ptrace to start the debugging session
|
||||
// but since it is badly broken, we detach and
|
||||
// revert to low-level mach api immediately after that
|
||||
|
||||
run_state_t run_state;
|
||||
|
||||
dyld_utils_t dyld;
|
||||
|
||||
image_info_t exeimg; // image info for the exe module
|
||||
|
||||
images_t dlls; // list of loaded dynamic libraries
|
||||
|
||||
easet_t dlls_to_import; // list of dlls to import information from
|
||||
|
||||
inline bool exited(void)
|
||||
{
|
||||
return run_state == rs_exited;
|
||||
}
|
||||
|
||||
threads_t threads;
|
||||
|
||||
struct stored_signal_t
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
};
|
||||
typedef qvector<stored_signal_t> stored_signals_t;
|
||||
static stored_signals_t pending_signals; // signals retrieved by other threads
|
||||
|
||||
bool attaching; // Handling events linked to PTRACE_ATTACH, don't run the program yet
|
||||
bool is64; // is target 64-bit?
|
||||
|
||||
mach_port_t exc_port;
|
||||
mach_exception_port_info_t saved_exceptions;
|
||||
|
||||
regctx_t *reg_ctx;
|
||||
|
||||
mac_debmod_t();
|
||||
~mac_debmod_t();
|
||||
|
||||
void init_reg_ctx(void);
|
||||
void term_reg_ctx(void);
|
||||
|
||||
void handle_dyld_bpt(const debug_event_t *event);
|
||||
bool retrieve_pending_signal(int *status);
|
||||
kern_return_t read_mem(ea_t ea, void *buffer, int size, int *read_size);
|
||||
void unblock_all_threads();
|
||||
void resume_all_threads();
|
||||
bool suspend_all_threads();
|
||||
bool my_resume_thread(ida_thread_info_t &ti);
|
||||
pid_t qwait(int *status, bool hang);
|
||||
void get_debug_events(int timeout_ms);
|
||||
kern_return_t
|
||||
catch_exception_raise(mach_port_t exception_port,
|
||||
mach_port_t thread,
|
||||
mach_port_t task,
|
||||
exception_type_t exception,
|
||||
exception_data_t code_vector,
|
||||
mach_msg_type_number_t code_count);
|
||||
ea_t get_ip(thid_t tid);
|
||||
uval_t get_dr(thid_t tid, int idx);
|
||||
bool set_dr(thid_t tid, int idx, uval_t value);
|
||||
bool idaapi thread_get_fs_base(thid_t tid, int reg_idx, ea_t *pea);
|
||||
bool parse_macho_image(macho_visitor_t &mv, const image_info_t &ii);
|
||||
void clean_stack_regions(meminfo_vec_t &miv) const;
|
||||
drc_t get_memory_info(meminfo_vec_t &miv, bool suspend);
|
||||
void init_dyld(void);
|
||||
void init_exeimg(pid_t _pid, thid_t tid);
|
||||
void update_dyld(void);
|
||||
bool exist_dll(const images_t &images, ea_t base);
|
||||
virtual bool refresh_hwbpts() override;
|
||||
virtual bool set_hwbpts(int hThread) newapi;
|
||||
bool handle_process_start(pid_t _pid);
|
||||
void term_exception_ports(void);
|
||||
void init_exception_ports(void);
|
||||
thid_t init_main_thread(bool reattaching);
|
||||
bool update_threads(void);
|
||||
bool thread_exit_event_planned(thid_t tid);
|
||||
void cleanup(void);
|
||||
bool xfer_memory(ea_t ea, void *buffer, int size, bool write);
|
||||
void add_dll(const image_info_t &ii);
|
||||
int _write_memory(ea_t ea, const void *buffer, int size, bool suspend=false);
|
||||
int _read_memory(ea_t ea, void *buffer, int size, bool suspend=false);
|
||||
bool xfer_page(ea_t ea, void *buffer, int size, bool write);
|
||||
kern_return_t write_mem(ea_t ea, void *buffer, int size);
|
||||
int exception_to_signal(const mach_exception_info_t *exinf);
|
||||
bool check_for_exception(int timeout, mach_exception_info_t *exinf);
|
||||
bool handle_signal(
|
||||
int code,
|
||||
debug_event_t *event,
|
||||
block_type_t block,
|
||||
const my_mach_msg_t *excmsg);
|
||||
bool check_for_exception(
|
||||
int timeout,
|
||||
mach_exception_info_t *exinf,
|
||||
my_mach_msg_t *excmsg);
|
||||
bool is_task_valid(task_t task);
|
||||
int32 qptrace(int request, pid_t pid, caddr_t addr, int data);
|
||||
ida_thread_info_t *get_thread(thid_t tid);
|
||||
int handle_bpts(debug_event_t *event, bool asked_step);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#define DEFINE_GET_STATE_FUNC(name, type, flavor, flavor_count) \
|
||||
bool name(thid_t tid, type *state) \
|
||||
{ \
|
||||
ida_thread_info_t *ti = get_thread(tid); \
|
||||
if ( ti == NULL ) \
|
||||
return false; \
|
||||
mach_port_t port = ti->port; \
|
||||
mach_msg_type_number_t stateCount = flavor_count; \
|
||||
kern_return_t err; \
|
||||
err = thread_get_state(port, \
|
||||
flavor, \
|
||||
(thread_state_t)state, \
|
||||
&stateCount); \
|
||||
QASSERT(30105, stateCount == flavor_count); \
|
||||
if ( err != KERN_SUCCESS ) \
|
||||
{ \
|
||||
debdeb("tid=%d port=%d: " #name ": %s\n", tid, port, mach_error_string(err)); \
|
||||
return false; \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define DEFINE_SET_STATE_FUNC(name, type, flavor, flavor_count) \
|
||||
bool name(thid_t tid, const type *state) \
|
||||
{ \
|
||||
ida_thread_info_t *ti = get_thread(tid); \
|
||||
if ( ti == NULL ) \
|
||||
return false; \
|
||||
mach_port_t port = ti->port; \
|
||||
mach_msg_type_number_t stateCount = flavor_count; \
|
||||
kern_return_t err; \
|
||||
err = thread_set_state(port, \
|
||||
flavor, \
|
||||
(thread_state_t)state, \
|
||||
stateCount); \
|
||||
QASSERT(30106, stateCount == flavor_count); \
|
||||
return err == KERN_SUCCESS; \
|
||||
}
|
||||
|
||||
DEFINE_GET_STATE_FUNC(get_thread_state64, x86_thread_state64_t, x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT)
|
||||
DEFINE_SET_STATE_FUNC(set_thread_state64, x86_thread_state64_t, x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT)
|
||||
DEFINE_GET_STATE_FUNC(get_thread_state32, x86_thread_state32_t, x86_THREAD_STATE32, x86_THREAD_STATE32_COUNT)
|
||||
DEFINE_SET_STATE_FUNC(set_thread_state32, x86_thread_state32_t, x86_THREAD_STATE32, x86_THREAD_STATE32_COUNT)
|
||||
DEFINE_GET_STATE_FUNC(get_float_state64, x86_avx_state64_t, x86_AVX_STATE64, x86_AVX_STATE64_COUNT)
|
||||
DEFINE_SET_STATE_FUNC(set_float_state64, x86_avx_state64_t, x86_AVX_STATE64, x86_AVX_STATE64_COUNT)
|
||||
DEFINE_GET_STATE_FUNC(get_float_state32, x86_avx_state32_t, x86_AVX_STATE32, x86_AVX_STATE32_COUNT)
|
||||
DEFINE_SET_STATE_FUNC(set_float_state32, x86_avx_state32_t, x86_AVX_STATE32, x86_AVX_STATE32_COUNT)
|
||||
DEFINE_GET_STATE_FUNC(get_debug_state64, x86_debug_state64_t, x86_DEBUG_STATE64, x86_DEBUG_STATE64_COUNT)
|
||||
DEFINE_SET_STATE_FUNC(set_debug_state64, x86_debug_state64_t, x86_DEBUG_STATE64, x86_DEBUG_STATE64_COUNT)
|
||||
DEFINE_GET_STATE_FUNC(get_debug_state32, x86_debug_state32_t, x86_DEBUG_STATE32, x86_DEBUG_STATE32_COUNT)
|
||||
DEFINE_SET_STATE_FUNC(set_debug_state32, x86_debug_state32_t, x86_DEBUG_STATE32, x86_DEBUG_STATE32_COUNT)
|
||||
|
||||
bool get_thread_state(thid_t tid, machine_thread_state_t *state);
|
||||
bool set_thread_state(thid_t tid, const machine_thread_state_t *state);
|
||||
bool get_float_state(thid_t tid, machine_float_state_t *state);
|
||||
bool set_float_state(thid_t tid, const machine_float_state_t *state);
|
||||
bool get_debug_state(thid_t tid, machine_debug_state_t *state);
|
||||
bool set_debug_state(thid_t tid, const machine_debug_state_t *state);
|
||||
|
||||
bool qthread_setsinglestep(ida_thread_info_t &ti);
|
||||
|
||||
bool patch_reg_context(
|
||||
machine_thread_state_t *cpu,
|
||||
machine_float_state_t *fpu,
|
||||
int reg_idx,
|
||||
const regval_t *value) const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline thid_t maintid(void)
|
||||
{
|
||||
return threads.begin()->first;
|
||||
}
|
||||
|
||||
void create_process_start_event(pid_t pid, thid_t tid);
|
||||
void create_process_attach_event(pid_t pid);
|
||||
|
||||
//
|
||||
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
|
||||
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
|
||||
virtual void idaapi dbg_term(void) override;
|
||||
virtual drc_t idaapi dbg_detach_process(void) override;
|
||||
virtual drc_t idaapi dbg_start_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
qstring *errbuf) override;
|
||||
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
|
||||
virtual drc_t idaapi dbg_attach_process(
|
||||
pid_t process_id,
|
||||
int event_id,
|
||||
int flags,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
|
||||
virtual void idaapi dbg_stopped_at_debug_event(
|
||||
import_infos_t *infos,
|
||||
bool dlls_added,
|
||||
thread_name_vec_t *thr_names) override;
|
||||
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
|
||||
virtual drc_t idaapi dbg_read_registers(
|
||||
thid_t thread_id,
|
||||
int clsmask,
|
||||
regval_t *values,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_write_register(
|
||||
thid_t thread_id,
|
||||
int reg_idx,
|
||||
const regval_t *value,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_thread_get_sreg_base(
|
||||
ea_t *ea,
|
||||
thid_t thread_id,
|
||||
int sreg_value,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &miv, qstring *errbuf) override;
|
||||
virtual int idaapi dbg_get_scattered_image(scattered_image_t &sci, ea_t base) override;
|
||||
virtual bool idaapi dbg_get_image_uuid(bytevec_t *uuid, ea_t base) override;
|
||||
virtual ea_t idaapi dbg_get_segm_start(ea_t base, const qstring &segname) override;
|
||||
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
|
||||
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
|
||||
virtual bool idaapi write_registers(
|
||||
thid_t tid,
|
||||
int start,
|
||||
int count,
|
||||
const regval_t *values) override;
|
||||
|
||||
virtual int dbg_freeze_threads_except(thid_t tid) override;
|
||||
virtual int dbg_thaw_threads_except(thid_t tid) override;
|
||||
|
||||
virtual bool idaapi dbg_continue_broken_connection(pid_t pid) override;
|
||||
virtual bool idaapi dbg_prepare_broken_connection(void) override;
|
||||
|
||||
void get_image_meminfo(meminfo_vec_t &out, const image_info_t &ii);
|
||||
|
||||
int get_task_suspend_count(void);
|
||||
|
||||
int visit_vm_regions(vm_region_visitor_t &rv);
|
||||
|
||||
static bool acquire_taskport_right();
|
||||
static bool verify_code_signature();
|
||||
static bool verify_user_privilege();
|
||||
|
||||
bool import_symbols(const image_info_t &ii);
|
||||
|
||||
virtual bool import_dll(const import_request_t &req) override;
|
||||
|
||||
bool get_image_info(image_info_t *ii, ea_t base) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
26
idasdk75/dbg/mac/mac_debug.plist
Normal file
26
idasdk75/dbg/mac/mac_debug.plist
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>OS X Remote Debug Server (32-bit) for IDA, Copyright (c) 2015 Hex-Rays SA</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>mac_server</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.hexrays.mac_server</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>mac_server</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>SecTaskAccess</key>
|
||||
<array>
|
||||
<string>allowed</string>
|
||||
<string>debug</string>
|
||||
<string>safe</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
25
idasdk75/dbg/mac/mac_debug64.plist
Normal file
25
idasdk75/dbg/mac/mac_debug64.plist
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>OS X Remote Debug Server (64-bit) for IDA, Copyright (c) 2015 Hex-Rays SA</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>mac_server64</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.hexrays.mac_serverx64</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>mac_serverx64</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>SecTaskAccess</key>
|
||||
<array>
|
||||
<string>allowed</string>
|
||||
<string>debug</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
203
idasdk75/dbg/mac/mac_local_impl.cpp
Normal file
203
idasdk75/dbg/mac/mac_local_impl.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
#include <loader.hpp>
|
||||
|
||||
#include "macho_rebase.cpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// installs or uninstalls debugger specific idc functions
|
||||
inline bool register_idc_funcs(bool)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rebase_if_required_to(ea_t new_base)
|
||||
{
|
||||
// not a shared cache lib: it's safe to just use the imagebase
|
||||
ea_t base = get_imagebase();
|
||||
if ( base == 0 )
|
||||
{
|
||||
// old databases don't have it set; use info from netnode
|
||||
netnode n(MACHO_NODE);
|
||||
if ( exist(n) )
|
||||
base = n.altval(MACHO_ALT_IMAGEBASE);
|
||||
}
|
||||
|
||||
if ( base != BADADDR
|
||||
&& new_base != BADADDR
|
||||
&& base != new_base
|
||||
&& !rebase_scattered_segments(new_base) )
|
||||
{
|
||||
rebase_or_warn(base, new_base);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum macopt_idx_t
|
||||
{
|
||||
MAC_OPT_SYMBOL_PATH // path to symbols extracted from dyld shared cache
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct mac_cfgopt_t
|
||||
{
|
||||
const char *name;
|
||||
char type;
|
||||
char index;
|
||||
void *var;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
//lint -esym(843, g_must_save_cfg) could be declared as const
|
||||
static bool g_must_save_cfg = false;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const mac_cfgopt_t g_cfgopts[] =
|
||||
{
|
||||
{ "SYMBOL_PATH", IDPOPT_STR, MAC_OPT_SYMBOL_PATH, &g_dbgmod.dyld.symbol_path, 0 },
|
||||
};
|
||||
CASSERT(IS_QSTRING(g_dbgmod.dyld.symbol_path));
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const mac_cfgopt_t *find_option(const char *name)
|
||||
{
|
||||
for ( int i=0; i < qnumber(g_cfgopts); i++ )
|
||||
if ( strcmp(g_cfgopts[i].name, name) == 0 )
|
||||
return &g_cfgopts[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void load_mac_options()
|
||||
{
|
||||
if ( !netnode::inited() )
|
||||
return;
|
||||
|
||||
netnode node(MAC_NODE);
|
||||
if ( !exist(node) )
|
||||
return;
|
||||
|
||||
for ( int i = 0; i < qnumber(g_cfgopts); i++ )
|
||||
{
|
||||
const mac_cfgopt_t &opt = g_cfgopts[i];
|
||||
if ( opt.type == IDPOPT_STR )
|
||||
node.supstr((qstring *)opt.var, opt.index);
|
||||
else
|
||||
node.supval(opt.index, opt.var, opt.size);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void save_mac_options()
|
||||
{
|
||||
if ( !g_must_save_cfg || !netnode::inited() )
|
||||
return;
|
||||
|
||||
netnode node;
|
||||
node.create(MAC_NODE);
|
||||
if ( node != BADNODE )
|
||||
{
|
||||
for ( int i = 0; i < qnumber(g_cfgopts); i++ )
|
||||
{
|
||||
const mac_cfgopt_t &opt = g_cfgopts[i];
|
||||
if ( opt.type == IDPOPT_STR )
|
||||
node.supset(opt.index, ((qstring *)opt.var)->c_str(), 0);
|
||||
else
|
||||
node.supset(opt.index, opt.var, opt.size);
|
||||
}
|
||||
}
|
||||
|
||||
g_must_save_cfg = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *idaapi set_mac_options(const char *keyword, int pri, int value_type, const void *value)
|
||||
{
|
||||
if ( keyword == NULL )
|
||||
{
|
||||
static const char form[] =
|
||||
"Mac OSX Debugger Options\n%/"
|
||||
"<#Path to symbol files extracted from dyld_shared_cache#~S~ymbol path:q:1023:60::>\n";
|
||||
|
||||
qstring path = g_dbgmod.dyld.symbol_path;
|
||||
if ( !ask_form(form, NULL, &path) )
|
||||
return IDPOPT_OK;
|
||||
|
||||
g_dbgmod.dyld.symbol_path = path;
|
||||
g_must_save_cfg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( *keyword == '\0' )
|
||||
{
|
||||
load_mac_options();
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
const mac_cfgopt_t *opt = find_option(keyword);
|
||||
if ( opt == NULL )
|
||||
return IDPOPT_BADKEY;
|
||||
if ( opt->type != value_type )
|
||||
return IDPOPT_BADTYPE;
|
||||
|
||||
if ( opt->type == IDPOPT_STR )
|
||||
{
|
||||
qstring *pvar = (qstring *)opt->var;
|
||||
*pvar = (char *)value;
|
||||
}
|
||||
|
||||
if ( pri == IDPOPT_PRI_HIGH )
|
||||
g_must_save_cfg = true;
|
||||
}
|
||||
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static ssize_t idaapi ui_callback(void *, int notification_code, va_list)
|
||||
{
|
||||
if ( notification_code == ui_saving )
|
||||
save_mac_options();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool init_plugin(void)
|
||||
{
|
||||
#ifndef RPC_CLIENT
|
||||
if ( !init_subsystem() )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if ( !netnode::inited() || is_miniidb() || inf_is_snapshot() )
|
||||
{
|
||||
#ifdef __MAC__
|
||||
// local debugger is available if we are running under MAC OS X
|
||||
return true;
|
||||
#else
|
||||
// for other systems only the remote debugger is available
|
||||
return debugger.is_remote();
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( inf_get_filetype() != S_FILETYPE ) // only Mach-O files
|
||||
return false;
|
||||
processor_t &ph = PH;
|
||||
if ( ph.id != TARGET_PROCESSOR && ph.id != -1 )
|
||||
return false;
|
||||
|
||||
hook_to_notification_point(HT_UI, ui_callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void term_plugin(void)
|
||||
{
|
||||
#ifndef RPC_CLIENT
|
||||
term_subsystem();
|
||||
#endif
|
||||
unhook_from_notification_point(HT_UI, ui_callback);
|
||||
save_mac_options();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "Userland Mac OS X debugger plugin.";
|
||||
72
idasdk75/dbg/mac/mac_stub.cpp
Normal file
72
idasdk75/dbg/mac/mac_stub.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
This is the MAC OS X x86 user land debugger entry point file
|
||||
*/
|
||||
#ifndef __GNUC__
|
||||
//lint -esym(750, __LITTLE_ENDIAN__) not referenced
|
||||
#define __LITTLE_ENDIAN__
|
||||
#endif
|
||||
//#define __inline__ inline
|
||||
#define REMOTE_DEBUGGER
|
||||
#define RPC_CLIENT
|
||||
|
||||
static const char wanted_name[] = "Remote Mac OS X debugger";
|
||||
#define DEBUGGER_NAME "macosx"
|
||||
#define PROCESSOR_NAME "metapc"
|
||||
#define DEFAULT_PLATFORM_NAME "macosx"
|
||||
#define TARGET_PROCESSOR PLFM_386
|
||||
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_MACOSX_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
|
||||
| DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD)
|
||||
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_MACHO
|
||||
#define SET_DBG_OPTIONS set_mac_options
|
||||
#define MAC_NODE "$ remote mac options"
|
||||
|
||||
#include <pro.h>
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <name.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
#include "dbg_rpc_client.h"
|
||||
#include "rpc_debmod.h"
|
||||
#include "symmacho.hpp"
|
||||
|
||||
class rstub_debmod_t : public rpc_debmod_t
|
||||
{
|
||||
typedef rpc_debmod_t inherited;
|
||||
|
||||
public:
|
||||
dyld_utils_t dyld;
|
||||
|
||||
rstub_debmod_t() : inherited(DEFAULT_PLATFORM_NAME), dyld(this, TARGET_PROCESSOR) {}
|
||||
|
||||
// handle an RPC_IMPORT_DLL request from the server. see SYMBOL_PATH in dbg_macosx.cfg.
|
||||
virtual bool import_dll(const import_request_t &req) override
|
||||
{
|
||||
dyld.update_bitness();
|
||||
struct ida_local dll_importer_t : public macho_visitor_t
|
||||
{
|
||||
dll_importer_t() : macho_visitor_t(MV_SYMBOLS) {}
|
||||
void visit_symbol(ea_t ea, const char *name) override
|
||||
{
|
||||
set_debug_name(ea, name);
|
||||
}
|
||||
};
|
||||
dll_importer_t di;
|
||||
return dyld.parse_local_symbol_file(req.base, req.path.c_str(), req.uuid, di);
|
||||
}
|
||||
};
|
||||
|
||||
rstub_debmod_t g_dbgmod;
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "pc_local_impl.cpp"
|
||||
#include "mac_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
31
idasdk75/dbg/mac/mac_user.cpp
Normal file
31
idasdk75/dbg/mac/mac_user.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
This is the MAC user land local debugger entry point file
|
||||
It declares a MAC debugger module and uses the common plugin functions to build the debugger
|
||||
*/
|
||||
|
||||
static const char wanted_name[] = "Local Mac OS X debugger";
|
||||
#define DEBUGGER_NAME "macosx"
|
||||
#define PROCESSOR_NAME "metapc"
|
||||
#define TARGET_PROCESSOR PLFM_386
|
||||
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_MACOSX_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD)
|
||||
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_MACHO
|
||||
#define SET_DBG_OPTIONS set_mac_options
|
||||
#define MAC_NODE "$ local mac options"
|
||||
|
||||
#include <pro.h>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include "mac_debmod.h"
|
||||
|
||||
mac_debmod_t g_dbgmod;
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "pc_local_impl.cpp"
|
||||
#include "mac_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
164
idasdk75/dbg/mac/macbase_debmod.cpp
Normal file
164
idasdk75/dbg/mac/macbase_debmod.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#undef processor_t
|
||||
#define processor_t mach_processor_t
|
||||
#include <sys/sysctl.h>
|
||||
#include <mach/mach.h>
|
||||
#undef processor_t
|
||||
|
||||
#include <fpro.h>
|
||||
#include <prodir.h>
|
||||
#include <diskio.hpp>
|
||||
#include "macbase_debmod.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline const char *str_bitness(int bitness)
|
||||
{
|
||||
switch ( bitness )
|
||||
{
|
||||
case 8:
|
||||
return "[64]";
|
||||
case 4:
|
||||
return "[32]";
|
||||
default:
|
||||
return "[?]";
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
cpu_type_t macbase_debmod_t::get_process_cpu(pid_t _pid) const
|
||||
{
|
||||
int mib[CTL_MAXNAME];
|
||||
size_t mibLen = CTL_MAXNAME;
|
||||
int err = sysctlnametomib("sysctl.proc_cputype", mib, &mibLen);
|
||||
if ( err == 0 )
|
||||
{
|
||||
QASSERT(895, mibLen < CTL_MAXNAME);
|
||||
mib[mibLen] = _pid;
|
||||
mibLen += 1;
|
||||
cpu_type_t cpu_type;
|
||||
size_t cpuTypeSize = sizeof(cpu_type);
|
||||
err = sysctl(mib, mibLen, &cpu_type, &cpuTypeSize, 0, 0);
|
||||
if ( err == 0 )
|
||||
return cpu_type;
|
||||
}
|
||||
msg("error from sysctl: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void build_process_ext_name(ext_process_info_t *pinfo)
|
||||
{
|
||||
pinfo->ext_name = str_bitness(pinfo->addrsize);
|
||||
pinfo->ext_name.append(' ');
|
||||
pinfo->ext_name.append(pinfo->name);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Returns the file name assciated with pid
|
||||
bool idaapi macbase_debmod_t::get_exec_fname(
|
||||
int _pid,
|
||||
char *buf,
|
||||
size_t bufsize)
|
||||
{
|
||||
int mib[3];
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_ARGMAX;
|
||||
|
||||
int argmax = 0;
|
||||
size_t size = sizeof(argmax);
|
||||
|
||||
sysctl(mib, 2, &argmax, &size, NULL, 0);
|
||||
if ( argmax <= 0 )
|
||||
argmax = QMAXPATH;
|
||||
|
||||
char *args = (char *)qalloc(argmax);
|
||||
if ( args == NULL )
|
||||
nomem("get_exec_fname");
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = _pid;
|
||||
|
||||
// obtain the arguments for the target process. this will
|
||||
// only work for processes that belong to the current uid,
|
||||
// so if you want it to work universally, you need to run
|
||||
// as root.
|
||||
size = argmax;
|
||||
buf[0] = '\0';
|
||||
if ( sysctl(mib, 3, args, &size, NULL, 0) != -1 )
|
||||
{
|
||||
char *ptr = args + sizeof(int);
|
||||
// show_hex(ptr, size, "procargs2\n");
|
||||
|
||||
qstrncpy(buf, ptr, bufsize);
|
||||
}
|
||||
qfree(args);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
|
||||
int idaapi macbase_debmod_t::get_process_bitness(int _pid)
|
||||
{
|
||||
return get_cpu_bitness(get_process_cpu(_pid));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi macbase_debmod_t::get_process_list(procvec_t *list, qstring *)
|
||||
{
|
||||
list->clear();
|
||||
int mypid = getpid();
|
||||
int sysControl[4];
|
||||
sysControl[0] = CTL_KERN;
|
||||
sysControl[1] = KERN_PROC;
|
||||
sysControl[2] = KERN_PROC_ALL;
|
||||
|
||||
qvector<struct kinfo_proc> info;
|
||||
size_t length;
|
||||
int count = 0;
|
||||
int rc = -1;
|
||||
for ( int tries=0; rc != 0 && tries < 5; ++tries )
|
||||
{
|
||||
// the first call of sysctl() is used to determine the size of the buffer
|
||||
// will be passed to the second call
|
||||
length = 0;
|
||||
sysctl(sysControl, 3, NULL, &length, NULL, 0);
|
||||
|
||||
// If the number of processes is greater than the size of the buffer
|
||||
// sysctl() supplies as much data as fits in the buffer and returns ENOMEM.
|
||||
// We reserve 100 extra elements for processes started after 1st sysctl
|
||||
// In case even this number is not sufficient we turn to the next attempt
|
||||
count = (length / sizeof (info[0])) + 100;
|
||||
if ( count <= 0 ) //-V547 is always false.
|
||||
return 0;
|
||||
if ( info.size() < count )
|
||||
info.resize(count);
|
||||
length = sizeof(info[0]) * info.size();
|
||||
rc = sysctl(sysControl, 3, info.begin(), &length, NULL, 0);
|
||||
if ( rc != 0 && errno != ENOMEM )
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = (length / sizeof (info[0])); // exact number of processes
|
||||
for ( int i=0; i < count; i++ )
|
||||
{
|
||||
extern_proc &ep = info[i].kp_proc;
|
||||
pid_t _pid = ep.p_pid;
|
||||
if ( _pid == mypid )
|
||||
continue;
|
||||
mach_port_t port;
|
||||
kern_return_t result = task_for_pid(mach_task_self(), _pid, &port);
|
||||
if ( result == KERN_SUCCESS )
|
||||
{
|
||||
ext_process_info_t &pi = list->push_back();
|
||||
pi.name = ep.p_comm;
|
||||
pi.pid = _pid;
|
||||
pi.addrsize = get_process_bitness(_pid);
|
||||
build_process_ext_name(&pi);
|
||||
}
|
||||
else
|
||||
{
|
||||
debdeb("%d: %s is unavailable for debugging\n", _pid, info[i].kp_proc.p_comm);
|
||||
}
|
||||
}
|
||||
return list->size();
|
||||
}
|
||||
41
idasdk75/dbg/mac/macbase_debmod.h
Normal file
41
idasdk75/dbg/mac/macbase_debmod.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef __MACBASE_HPP__
|
||||
#define __MACBASE_HPP__
|
||||
|
||||
#include "debmod.h"
|
||||
|
||||
#include "pc_debmod.h"
|
||||
#define BASE_DEBUGGER_MODULE pc_debmod_t
|
||||
|
||||
#ifndef __LINUX__ // linux gcc cannot compile macho-o headers
|
||||
#include "symmacho.hpp"
|
||||
#endif
|
||||
|
||||
// avoid conflicts with audit.h:
|
||||
#define token_t __mac_token_t
|
||||
#include <sys/sysctl.h>
|
||||
#include <mach-o/fat.h>
|
||||
#undef token_t
|
||||
|
||||
class macbase_debmod_t: public BASE_DEBUGGER_MODULE
|
||||
{
|
||||
typedef BASE_DEBUGGER_MODULE inherited;
|
||||
|
||||
protected:
|
||||
// return number of processes, -1 - not implemented
|
||||
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf) override;
|
||||
// return the file name assciated with pid
|
||||
virtual bool idaapi get_exec_fname(int pid, char *buf, size_t bufsize) newapi;
|
||||
// get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
|
||||
virtual int idaapi get_process_bitness(int pid) newapi;
|
||||
|
||||
cpu_type_t get_process_cpu(pid_t pid) const;
|
||||
inline int idaapi get_cpu_bitness(cpu_type_t cpu);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline int idaapi macbase_debmod_t::get_cpu_bitness(cpu_type_t cpu)
|
||||
{
|
||||
return (cpu & CPU_ARCH_ABI64) != 0 ? 8 : 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
350
idasdk75/dbg/mac/makefile
Normal file
350
idasdk75/dbg/mac/makefile
Normal file
@@ -0,0 +1,350 @@
|
||||
include ../../allmake.mak
|
||||
|
||||
GOALS-$(BUILD_IDA) += configs # target in $(IDA)module.mak
|
||||
GOALS-$(BUILD_IDA) += modules # target in $(IDA)module.mak
|
||||
GOALS-$(BUILD_DBGSRV) += server # target in $(IDA)dbg/server.mak
|
||||
.PHONY: $(GOALS-1)
|
||||
all: $(GOALS-1)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
ifdef __MAC__
|
||||
SERVER = mac_server$(B)
|
||||
endif
|
||||
ifdef SERVER
|
||||
SERVERS += $(call server_exe,$(SERVER))
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
STUB = $(call module_dll,mac_stub)
|
||||
ifdef BUILD_IDA
|
||||
MODULES += $(STUB)
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
USER = $(call module_dll,mac_user)
|
||||
ifeq ($(and $(BUILD_IDA),$(__MAC__)),1)
|
||||
MODULES += $(USER)
|
||||
CONFIGS += dbg_macosx.cfg
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# we explicitly added our module targets
|
||||
NO_DEFAULT_TARGETS = 1
|
||||
|
||||
# NOTE: all MODULES must be defined before including plugin.mak.
|
||||
include ../plugin.mak
|
||||
# NOTE: target-specific rules and dependencies that use variable
|
||||
# expansion to name the target (such as "$(MODULE): [...]") must
|
||||
# come after including plugin.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# select OBJS common to user plugin and debugger server
|
||||
BASE_OBJS-$(__MAC__) += $(F)macbase_debmod$(O)
|
||||
BASE_OBJS-$(__MAC__) += $(F)mac_debmod$(O)
|
||||
BASE_OBJS-$(__MAC__) += $(F)excServer$(O)
|
||||
|
||||
BASE_OBJS += $(BASE_OBJS-1) $(F)symmacho$(O)
|
||||
|
||||
$(F)symmacho$(O): CC_INCP += ../../ldr/mach-o/h $(IRRXML)
|
||||
$(F)mac_debmod$(O): CC_INCP += ../../ldr/mach-o/h
|
||||
|
||||
excServer.c:
|
||||
mig $(MACSDK)/usr/include/mach/exc.defs
|
||||
ifdef __LINT__
|
||||
$(F)excServer$(O):
|
||||
touch $@
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
SERVER_LDFLAGS += $(OUTMAP)$(F)$(@F).map
|
||||
SERVER_LDFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,mac_debug$(B).plist
|
||||
|
||||
SERVER_STDLIBS += -framework CoreFoundation
|
||||
SERVER_STDLIBS += -framework Security
|
||||
|
||||
# NOTE: perform the steps in mac_server_certificate.txt before using CODESIGN_MAC_SERVER!
|
||||
ifdef CODESIGN_MAC_SERVER
|
||||
CODESIGN_IDENTITY ?= mac_server
|
||||
ifdef MAC_KEYCHAIN
|
||||
CODESIGN_OPTS = --keychain $(MAC_KEYCHAIN).keychain
|
||||
endif
|
||||
ifdef MAC_TIMESTAMP
|
||||
CODESIGN_OPTS += --timestamp=$(MAC_TIMESTAMP)
|
||||
endif
|
||||
ifndef __CODE_CHECKER__
|
||||
SERVER_POSTACTION = $(strip codesign $(CODESIGN_OPTS) -s "$(CODESIGN_IDENTITY)" $@)
|
||||
endif
|
||||
endif
|
||||
SERVER_OBJS += $(BASE_OBJS)
|
||||
|
||||
include ../server.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
STUB_OBJS += $(F)mac_stub$(O)
|
||||
STUB_OBJS += $(F)symmacho$(O)
|
||||
$(STUB): MODULE_OBJS += $(STUB_OBJS)
|
||||
$(STUB): $(STUB_OBJS)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
USER_OBJS += $(F)mac_user$(O)
|
||||
USER_OBJS += $(BASE_OBJS)
|
||||
$(USER): MODULE_OBJS += $(USER_OBJS)
|
||||
$(USER): $(USER_OBJS)
|
||||
$(USER): STDLIBS += -framework Security
|
||||
$(USER): STDLIBS += -framework CoreFoundation
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
include $(IDA)objdir.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)excServer$(O): ../../ldr/mach-o/h/arm/_types.h \
|
||||
../../ldr/mach-o/h/i386/_types.h \
|
||||
../../ldr/mach-o/h/mach/arm/boolean.h \
|
||||
../../ldr/mach-o/h/mach/arm/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/machine/boolean.h \
|
||||
../../ldr/mach-o/h/mach/machine/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/machine/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/message.h \
|
||||
../../ldr/mach-o/h/mach/port.h \
|
||||
../../ldr/mach-o/h/mach/ppc/boolean.h \
|
||||
../../ldr/mach-o/h/mach/ppc/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_types.h \
|
||||
../../ldr/mach-o/h/ppc/_types.h \
|
||||
../../ldr/mach-o/h/sys/_posix_availability.h \
|
||||
../../ldr/mach-o/h/sys/_symbol_aliasing.h \
|
||||
../../ldr/mach-o/h/sys/cdefs.h excServer.c
|
||||
$(F)mac_debmod$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)diskio.hpp $(I)err.h $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/mach-o/common.h \
|
||||
../../ldr/mach-o/h/architecture/byte_order.h \
|
||||
../../ldr/mach-o/h/arm/_types.h \
|
||||
../../ldr/mach-o/h/i386/_types.h \
|
||||
../../ldr/mach-o/h/i386/eflags.h \
|
||||
../../ldr/mach-o/h/libkern/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/i386/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/i386/_OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/machine/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/mach-o/arm/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/arm64/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/fat.h \
|
||||
../../ldr/mach-o/h/mach-o/hppa/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/i860/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/loader.h \
|
||||
../../ldr/mach-o/h/mach-o/m88k/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/nlist.h \
|
||||
../../ldr/mach-o/h/mach-o/ppc/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/sparc/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/stab.h \
|
||||
../../ldr/mach-o/h/mach-o/x86_64/reloc.h \
|
||||
../../ldr/mach-o/h/mach/arm/_structs.h \
|
||||
../../ldr/mach-o/h/mach/arm/boolean.h \
|
||||
../../ldr/mach-o/h/mach/arm/thread_state.h \
|
||||
../../ldr/mach-o/h/mach/arm/thread_status.h \
|
||||
../../ldr/mach-o/h/mach/arm/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/_structs.h \
|
||||
../../ldr/mach-o/h/mach/i386/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/fp_reg.h \
|
||||
../../ldr/mach-o/h/mach/i386/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/i386/thread_state.h \
|
||||
../../ldr/mach-o/h/mach/i386/thread_status.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/machine.h \
|
||||
../../ldr/mach-o/h/mach/machine/boolean.h \
|
||||
../../ldr/mach-o/h/mach/machine/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/machine/thread_status.h \
|
||||
../../ldr/mach-o/h/mach/machine/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/message.h \
|
||||
../../ldr/mach-o/h/mach/port.h \
|
||||
../../ldr/mach-o/h/mach/ppc/_structs.h \
|
||||
../../ldr/mach-o/h/mach/ppc/boolean.h \
|
||||
../../ldr/mach-o/h/mach/ppc/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/ppc/thread_status.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/shared_region.h \
|
||||
../../ldr/mach-o/h/mach/vm_prot.h \
|
||||
../../ldr/mach-o/h/mach/vm_types.h \
|
||||
../../ldr/mach-o/h/ppc/_types.h \
|
||||
../../ldr/mach-o/h/sys/_posix_availability.h \
|
||||
../../ldr/mach-o/h/sys/_symbol_aliasing.h \
|
||||
../../ldr/mach-o/h/sys/appleapiopts.h \
|
||||
../../ldr/mach-o/h/sys/cdefs.h \
|
||||
../../ldr/mach-o/h/sys/ptrace.h \
|
||||
../../ldr/mach-o/macho_node.h ../deb_pc.hpp ../debmod.h \
|
||||
../pc_debmod.h ../pc_regs.hpp mac_debmod.cpp \
|
||||
mac_debmod.h macbase_debmod.h symmacho.hpp
|
||||
$(F)mac_stub$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/mach-o/macho_node.h ../common_local_impl.cpp \
|
||||
../common_stub_impl.cpp ../dbg_rpc_client.h \
|
||||
../dbg_rpc_engine.h ../deb_pc.hpp ../debmod.h \
|
||||
../macho_rebase.cpp ../pc_local_impl.cpp ../pc_regs.hpp \
|
||||
../rpc_debmod.h mac_local_impl.cpp mac_stub.cpp \
|
||||
symmacho.hpp
|
||||
$(F)mac_user$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)diskio.hpp $(I)err.h $(I)expr.hpp \
|
||||
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \
|
||||
$(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/mach-o/h/architecture/byte_order.h \
|
||||
../../ldr/mach-o/h/arm/_types.h \
|
||||
../../ldr/mach-o/h/i386/_types.h \
|
||||
../../ldr/mach-o/h/libkern/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/i386/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/i386/_OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/machine/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/mach-o/fat.h \
|
||||
../../ldr/mach-o/h/mach-o/nlist.h \
|
||||
../../ldr/mach-o/h/mach-o/reloc.h \
|
||||
../../ldr/mach-o/h/mach/arm/boolean.h \
|
||||
../../ldr/mach-o/h/mach/arm/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/machine.h \
|
||||
../../ldr/mach-o/h/mach/machine/boolean.h \
|
||||
../../ldr/mach-o/h/mach/machine/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/port.h \
|
||||
../../ldr/mach-o/h/mach/ppc/boolean.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/shared_region.h \
|
||||
../../ldr/mach-o/h/mach/vm_prot.h \
|
||||
../../ldr/mach-o/h/mach/vm_types.h \
|
||||
../../ldr/mach-o/h/ppc/_types.h \
|
||||
../../ldr/mach-o/h/sys/_posix_availability.h \
|
||||
../../ldr/mach-o/h/sys/_symbol_aliasing.h \
|
||||
../../ldr/mach-o/h/sys/appleapiopts.h \
|
||||
../../ldr/mach-o/h/sys/cdefs.h \
|
||||
../../ldr/mach-o/h/sys/ptrace.h \
|
||||
../../ldr/mach-o/macho_node.h ../common_local_impl.cpp \
|
||||
../common_stub_impl.cpp ../deb_pc.hpp ../debmod.h \
|
||||
../macho_rebase.cpp ../pc_debmod.h ../pc_local_impl.cpp \
|
||||
../pc_regs.hpp mac_debmod.h mac_local_impl.cpp \
|
||||
mac_user.cpp macbase_debmod.h symmacho.hpp
|
||||
$(F)macbase_debmod$(O): $(I)bytes.hpp $(I)diskio.hpp $(I)fpro.h \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)prodir.h $(I)range.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/mach-o/h/architecture/byte_order.h \
|
||||
../../ldr/mach-o/h/arm/_types.h \
|
||||
../../ldr/mach-o/h/i386/_types.h \
|
||||
../../ldr/mach-o/h/libkern/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/i386/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/i386/_OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/machine/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/mach-o/fat.h \
|
||||
../../ldr/mach-o/h/mach/arm/boolean.h \
|
||||
../../ldr/mach-o/h/mach/arm/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/machine.h \
|
||||
../../ldr/mach-o/h/mach/machine/boolean.h \
|
||||
../../ldr/mach-o/h/mach/machine/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/ppc/boolean.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_types.h \
|
||||
../../ldr/mach-o/h/ppc/_types.h ../deb_pc.hpp \
|
||||
../debmod.h ../pc_debmod.h ../pc_regs.hpp \
|
||||
macbase_debmod.cpp macbase_debmod.h symmacho.hpp
|
||||
$(F)symmacho$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)err.h \
|
||||
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)network.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)prodir.h $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
$(IRRXML)CXMLReaderImpl.h $(IRRXML)fast_atof.h \
|
||||
$(IRRXML)heapsort.h $(IRRXML)irrArray.h \
|
||||
$(IRRXML)irrString.h $(IRRXML)irrTypes.h \
|
||||
$(IRRXML)irrXML.h ../../ldr/ar/aixar.hpp \
|
||||
../../ldr/ar/ar.hpp ../../ldr/ar/arcmn.cpp \
|
||||
../../ldr/mach-o/../ar/ar.hpp \
|
||||
../../ldr/mach-o/../idaldr.h ../../ldr/mach-o/base.cpp \
|
||||
../../ldr/mach-o/common.cpp ../../ldr/mach-o/common.h \
|
||||
../../ldr/mach-o/dsym.cpp ../../ldr/mach-o/dsym.h \
|
||||
../../ldr/mach-o/h/architecture/byte_order.h \
|
||||
../../ldr/mach-o/h/arm/_types.h \
|
||||
../../ldr/mach-o/h/i386/_types.h \
|
||||
../../ldr/mach-o/h/i386/eflags.h \
|
||||
../../ldr/mach-o/h/libkern/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/i386/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/i386/_OSByteOrder.h \
|
||||
../../ldr/mach-o/h/libkern/machine/OSByteOrder.h \
|
||||
../../ldr/mach-o/h/mach-o/arm/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/arm64/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/fat.h \
|
||||
../../ldr/mach-o/h/mach-o/hppa/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/i860/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/loader.h \
|
||||
../../ldr/mach-o/h/mach-o/m88k/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/nlist.h \
|
||||
../../ldr/mach-o/h/mach-o/ppc/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/sparc/reloc.h \
|
||||
../../ldr/mach-o/h/mach-o/stab.h \
|
||||
../../ldr/mach-o/h/mach-o/x86_64/reloc.h \
|
||||
../../ldr/mach-o/h/mach/arm/_structs.h \
|
||||
../../ldr/mach-o/h/mach/arm/boolean.h \
|
||||
../../ldr/mach-o/h/mach/arm/thread_state.h \
|
||||
../../ldr/mach-o/h/mach/arm/thread_status.h \
|
||||
../../ldr/mach-o/h/mach/arm/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/_structs.h \
|
||||
../../ldr/mach-o/h/mach/i386/boolean.h \
|
||||
../../ldr/mach-o/h/mach/i386/fp_reg.h \
|
||||
../../ldr/mach-o/h/mach/i386/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/i386/thread_state.h \
|
||||
../../ldr/mach-o/h/mach/i386/thread_status.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/i386/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/kmod.h \
|
||||
../../ldr/mach-o/h/mach/machine.h \
|
||||
../../ldr/mach-o/h/mach/machine/boolean.h \
|
||||
../../ldr/mach-o/h/mach/machine/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/machine/thread_status.h \
|
||||
../../ldr/mach-o/h/mach/machine/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/message.h \
|
||||
../../ldr/mach-o/h/mach/port.h \
|
||||
../../ldr/mach-o/h/mach/ppc/_structs.h \
|
||||
../../ldr/mach-o/h/mach/ppc/boolean.h \
|
||||
../../ldr/mach-o/h/mach/ppc/kern_return.h \
|
||||
../../ldr/mach-o/h/mach/ppc/thread_status.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_param.h \
|
||||
../../ldr/mach-o/h/mach/ppc/vm_types.h \
|
||||
../../ldr/mach-o/h/mach/vm_prot.h \
|
||||
../../ldr/mach-o/h/mach/vm_types.h \
|
||||
../../ldr/mach-o/h/ppc/_types.h \
|
||||
../../ldr/mach-o/h/sys/_posix_availability.h \
|
||||
../../ldr/mach-o/h/sys/_symbol_aliasing.h \
|
||||
../../ldr/mach-o/h/sys/cdefs.h \
|
||||
../../ldr/mach-o/macho_node.h ../debmod.h symmacho.cpp \
|
||||
symmacho.hpp
|
||||
1142
idasdk75/dbg/mac/symmacho.cpp
Normal file
1142
idasdk75/dbg/mac/symmacho.cpp
Normal file
File diff suppressed because it is too large
Load Diff
249
idasdk75/dbg/mac/symmacho.hpp
Normal file
249
idasdk75/dbg/mac/symmacho.hpp
Normal file
@@ -0,0 +1,249 @@
|
||||
#ifndef SYMMACHO_H
|
||||
#define SYMMACHO_H
|
||||
|
||||
// manage the mach-o images in a darwin process
|
||||
|
||||
#include <pro.h>
|
||||
#include <idd.hpp>
|
||||
#include <map>
|
||||
|
||||
class debmod_t;
|
||||
class linput_t;
|
||||
|
||||
typedef std::map<ea_t, qstring> strings_cache_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct macho_visitor_t
|
||||
{
|
||||
int flags;
|
||||
#define MV_UUID 0x0001 // visit uuid
|
||||
#define MV_FUNCTION_STARTS 0x0002 // visit function start eas
|
||||
#define MV_SYMBOLS 0x0004 // visit symbols
|
||||
#define MV_SEGMENTS 0x0008 // visit segments
|
||||
#define MV_SECTIONS 0x0010 // visit sections
|
||||
#define MV_PLATFORM_INFO 0x0020 // visit build version info
|
||||
|
||||
uint32 subtype; // mh.filetype
|
||||
asize_t size; // image size
|
||||
sval_t slide; // ASLR slide
|
||||
bytevec_t uuid; // filled if MV_UUID is set
|
||||
uint32 version; // platform version
|
||||
|
||||
macho_visitor_t(int _flags = 0)
|
||||
: flags(_flags), subtype(0), size(0), slide(0), version(0) {}
|
||||
|
||||
virtual void visit_function_start(ea_t /*ea*/) {}
|
||||
virtual void visit_symbol(ea_t /*ea*/, const char * /*name*/) {}
|
||||
virtual void visit_segment(ea_t /*start*/, ea_t /*end*/, const qstring & /*name*/, bool /*is_code*/) {}
|
||||
virtual void visit_section(ea_t /*start*/, ea_t /*end*/, const qstring & /*sect*/, const qstring & /*seg*/, bool /*is_code*/) {}
|
||||
|
||||
// called when function start info could not be found/loaded
|
||||
virtual void handle_function_start_error() {}
|
||||
// called just before a symbol is visited when cpu is CPU_TYPE_ARM
|
||||
virtual void handle_thumb(ea_t /*ea*/, const char * /*name*/, bool /*is_thumb*/) {}
|
||||
|
||||
DEFINE_VIRTUAL_DTOR(macho_visitor_t)
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class macho_utils_t
|
||||
{
|
||||
public:
|
||||
debmod_t *dbgmod;
|
||||
|
||||
int arch; // PLFM_386 or PLFM_ARM
|
||||
int addrsize; // size of an address in the target process
|
||||
bool is64; // is target process 64-bit?
|
||||
bool warned; // warned the user about using SYMBOL_PATH when remote debugging
|
||||
|
||||
// sometimes macho images might share a common string table. ensure the same string table isn't loaded twice.
|
||||
strings_cache_t strcache;
|
||||
|
||||
macho_utils_t(debmod_t *_dbgmod, int _arch);
|
||||
DEFINE_VIRTUAL_DTOR(macho_utils_t)
|
||||
|
||||
virtual void clear(void);
|
||||
|
||||
int get_cputype(void) const;
|
||||
void update_bitness(void);
|
||||
|
||||
size_t read_mem(ea_t ea, void *buf, size_t size);
|
||||
bool read(ea_t ea, void *buf, size_t size) { return read_mem(ea, buf, size) == size; }
|
||||
void get_ptr_value(ea_t *val, const uchar *buf) const;
|
||||
|
||||
bool is_exe_header(ea_t base);
|
||||
|
||||
virtual bool parse_macho_file(const char *path, ea_t base, macho_visitor_t &mv, const bytevec_t &uuid) const;
|
||||
virtual bool parse_macho_input(linput_t *li, ea_t base, macho_visitor_t &mv) const;
|
||||
virtual bool parse_macho_mem(ea_t base, macho_visitor_t &mv, uint32 hints = 0);
|
||||
|
||||
linput_t *create_mem_input(ea_t base);
|
||||
|
||||
bool calc_macho_uuid(bytevec_t *uuid, linput_t *li) const;
|
||||
bool match_macho_uuid(linput_t *li, const bytevec_t &uuid) const;
|
||||
|
||||
bool calc_image_info(uint32 *subtype, asize_t *size, bytevec_t *uuid, ea_t base);
|
||||
bool calc_image_info(uint32 *subtype, asize_t *size, bytevec_t *uuid, const char *path) const;
|
||||
bool calc_image_info(uint32 *subtype, asize_t *size, bytevec_t *uuid, linput_t *li, ea_t base) const;
|
||||
|
||||
static qstring expand_home_dir(const char *path);
|
||||
|
||||
static void merge(
|
||||
meminfo_vec_t &res,
|
||||
const meminfo_vec_t &low,
|
||||
const meminfo_vec_t &high);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct dyld_all_image_infos_t
|
||||
{
|
||||
uint32 version;
|
||||
uint32 num_info;
|
||||
ea_t info_array;
|
||||
ea_t dyld_notify;
|
||||
ea_t dyld_image_load_address;
|
||||
ea_t dyld_image_infos_address;
|
||||
ea_t shared_cache_slide;
|
||||
ea_t shared_cache_base_address;
|
||||
|
||||
dyld_all_image_infos_t() { clear(); }
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum dyld_image_mode_t
|
||||
{
|
||||
DYLD_IMAGE_ERROR = -1,
|
||||
DYLD_IMAGE_ADDING = 0,
|
||||
DYLD_IMAGE_REMOVING = 1,
|
||||
DYLD_IMAGE_INFO_CHANGE = 2,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct dll_visitor_t
|
||||
{
|
||||
virtual void visit_dll(
|
||||
ea_t base,
|
||||
asize_t size,
|
||||
const char *name,
|
||||
const bytevec_t &uuid) = 0;
|
||||
|
||||
DEFINE_VIRTUAL_DTOR(dll_visitor_t)
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct dyld_cache_visitor_t
|
||||
{
|
||||
int flags;
|
||||
#define DCV_MAPPINGS 0x1 // visit shared region mappings
|
||||
|
||||
dyld_cache_visitor_t(int _flags) : flags(_flags) {}
|
||||
|
||||
virtual void visit_mapping(ea_t /*start_ea*/, ea_t /*end_ea*/) {}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class dyld_utils_t : public macho_utils_t
|
||||
{
|
||||
typedef macho_utils_t inherited;
|
||||
|
||||
template<typename H> bool is_dyld_header(ea_t base, char *filename, size_t namesize, uint32 magic);
|
||||
|
||||
bool is_dyld_header_64(ea_t base, char *filename, size_t namesize);
|
||||
bool is_dyld_header_32(ea_t base, char *filename, size_t namesize);
|
||||
|
||||
public:
|
||||
ea_t base_ea; // base address of dyld ifself
|
||||
ea_t entry_ea; // dyld's entry point
|
||||
ea_t infos_ea; // address of _dyld_all_image_infos
|
||||
ea_t ranges_ea; // address of _dyld_shared_cache_ranges
|
||||
|
||||
dyld_all_image_infos_t infos;
|
||||
|
||||
rangeset_t shared_cache_ranges;
|
||||
|
||||
qstring symbol_path;
|
||||
|
||||
dyld_utils_t(debmod_t *_dbgmod, int _arch);
|
||||
DEFINE_VIRTUAL_DTOR(dyld_utils_t)
|
||||
|
||||
virtual void clear(void) override;
|
||||
|
||||
bool is_shared_cache_lib(ea_t base) const { return shared_cache_ranges.contains(base); }
|
||||
bool is_system_lib(ea_t base) const { return base == base_ea || is_shared_cache_lib(base); }
|
||||
|
||||
bool is_dyld_header(ea_t base, char *filename, size_t namesize);
|
||||
|
||||
bool update_infos(void);
|
||||
bool update_ranges(void);
|
||||
|
||||
virtual bool parse_macho_mem(ea_t base, macho_visitor_t &mv, uint32 hints = 0) override;
|
||||
|
||||
bool parse_info_array(uint32 count, ea_t info_array, dll_visitor_t &dv);
|
||||
bool parse_dyld_cache_header(dyld_cache_visitor_t &dcv);
|
||||
|
||||
bool untag(ea_t *ea) const;
|
||||
|
||||
bool get_symbol_file_path(qstring *path, const char *module) const;
|
||||
bool parse_local_symbol_file(
|
||||
ea_t base,
|
||||
const char *module,
|
||||
const bytevec_t &uuid,
|
||||
macho_visitor_t &mv);
|
||||
};
|
||||
|
||||
struct kext_info_t
|
||||
{
|
||||
uint64 off;
|
||||
bytevec_t uuid;
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(kext_info_t);
|
||||
typedef qvector<kext_info_t> kext_info_vec_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class kernel_utils_t : public macho_utils_t
|
||||
{
|
||||
typedef macho_utils_t inherited;
|
||||
|
||||
qstring kdk_path; // path to a Kernel Development Kit
|
||||
linput_t *kcache_li; // if a kernelcache is present in the KDK, we can use it to parse kexts
|
||||
uint64 prelink_data_off; // offset of __PRELINK_DATA, required for parsing prelinked kexts
|
||||
kext_info_vec_t prelinked_kexts; // associate each kext's UUID with its offset in the kernelcache
|
||||
|
||||
uint64 find_kext_offset(const bytevec_t &uuid) const;
|
||||
|
||||
public:
|
||||
kernel_utils_t(debmod_t *_dbgmod, int _arch)
|
||||
: inherited(_dbgmod, _arch), kcache_li(NULL), prelink_data_off(0) {}
|
||||
|
||||
virtual ~kernel_utils_t(void) { kernel_utils_t::clear(); }
|
||||
|
||||
virtual void clear(void) override;
|
||||
|
||||
void set_kdk_path(const qstring &path);
|
||||
|
||||
// detect if a kernelcache is present and collect the prelinked kext info
|
||||
bool parse_kcache(const bytevec_t &kernel_uuid);
|
||||
|
||||
// apply the given visitor to a matching kext in the kernelcache
|
||||
bool parse_prelinked_kext(macho_visitor_t &mv, ea_t base, const bytevec_t &uuid);
|
||||
|
||||
#define KDK_SEARCH_DEFAULT 0x0 // look for any matching binary
|
||||
#define KDK_SEARCH_DSYM 0x1 // look for a binary with a companion dSYM
|
||||
#define KDK_SEARCH_KCACHE 0x2 // look for a kernelcache
|
||||
|
||||
// get the path to a matching binary in the KDK
|
||||
bool find_kdk_file(
|
||||
qstring *path,
|
||||
int cpu_subtype,
|
||||
const bytevec_t &uuid,
|
||||
const char *name,
|
||||
uint32 flags = KDK_SEARCH_DEFAULT) const;
|
||||
|
||||
// check if the given kext appears in the KDK, either as a standalone binary
|
||||
// or as a prelinked kext in a kernelcache
|
||||
bool find_kext(const bytevec_t &uuid, const char *kext_name) const;
|
||||
};
|
||||
|
||||
#endif // SYMMACHO_H
|
||||
197
idasdk75/dbg/macho_rebase.cpp
Normal file
197
idasdk75/dbg/macho_rebase.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
|
||||
#include "../ldr/mach-o/macho_node.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool rebase_scattered_segments(ea_t base)
|
||||
{
|
||||
netnode node;
|
||||
node.create(MACHO_NODE);
|
||||
|
||||
// detect if the code and data segments have moved relative to each other.
|
||||
// if so, we cannot simply apply a uniform delta to the entire database.
|
||||
// we must rebase one segment at a time.
|
||||
ea_t ldr_data = 0;
|
||||
ea_t ldr_text = 0;
|
||||
|
||||
if ( node.hashval("__DATA", &ldr_data, sizeof(ldr_data), SEGM_TAG) == -1
|
||||
|| node.hashval("__TEXT", &ldr_text, sizeof(ldr_text), SEGM_TAG) == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ea_t dbg_data = g_dbgmod.dbg_get_segm_start(base, "__DATA");
|
||||
ea_t dbg_text = g_dbgmod.dbg_get_segm_start(base, "__TEXT");
|
||||
|
||||
if ( dbg_data == BADADDR || dbg_text == BADADDR )
|
||||
return false;
|
||||
|
||||
adiff_t slide = (dbg_data - dbg_text) - (ldr_data - ldr_text);
|
||||
|
||||
if ( slide == 0 )
|
||||
return false;
|
||||
|
||||
scattered_image_t si;
|
||||
// we have detected segment scattering.
|
||||
// ensure that we can collect the vmaddr for each loader segment in IDA.
|
||||
if ( g_dbgmod.dbg_get_scattered_image(si, base) <= 0 )
|
||||
return false;
|
||||
|
||||
uint8 ubuf[16];
|
||||
bytevec_t uuid;
|
||||
// it is quite possible that the input file does not match the image in the cache.
|
||||
// if there is a mismatch we warn the user.
|
||||
if ( !g_dbgmod.dbg_get_image_uuid(&uuid, base)
|
||||
|| uuid.size() != sizeof(ubuf)
|
||||
|| node.supval(MACHO_ALT_UUID, ubuf, sizeof(ubuf)) <= 0
|
||||
|| memcmp(uuid.begin(), ubuf, sizeof(ubuf)) != 0 )
|
||||
{
|
||||
warning("AUTOHIDE DATABASE\n"
|
||||
"UUID mismatch between the input file and the image in memory.\n"
|
||||
"\n"
|
||||
"This could mean your dyld_shared_cache is out of sync with the library on disk,\n"
|
||||
"and the database will likely not be rebased properly.\n"
|
||||
"\n"
|
||||
"To ensure proper rebasing, please confirm that the input file was included\n"
|
||||
"the last time update_dyld_shared_cache was run.\n");
|
||||
}
|
||||
|
||||
// adjust any pointers between the code and data segments
|
||||
show_wait_box("Rebasing CODE -> DATA pointers");
|
||||
// we want to patch pointers in the database without writing to debugger memory
|
||||
lock_dbgmem_config();
|
||||
|
||||
for ( nodeidx_t nidx = node.charfirst(CODE_TAG);
|
||||
nidx != BADNODE && !user_cancelled();
|
||||
nidx = node.charnext(nidx, CODE_TAG) )
|
||||
{
|
||||
ea_t ea = node2ea(nidx);
|
||||
uchar kind = node.charval_ea(ea, CODE_TAG);
|
||||
switch ( kind )
|
||||
{
|
||||
case 1: // 32-bit pointer
|
||||
add_dword(ea, slide);
|
||||
break;
|
||||
case 2: // 64-bit pointer
|
||||
add_qword(ea, slide);
|
||||
break;
|
||||
default: // TODO: there are many more. we will deal with them later
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
replace_wait_box("Rebasing DATA -> CODE pointers");
|
||||
|
||||
for ( nodeidx_t nidx = node.charfirst(DATA_TAG);
|
||||
nidx != BADNODE && !user_cancelled();
|
||||
nidx = node.charnext(nidx, DATA_TAG) )
|
||||
{
|
||||
ea_t ea = node2ea(nidx);
|
||||
uchar kind = node.charval_ea(ea, DATA_TAG);
|
||||
switch ( kind )
|
||||
{
|
||||
case 1: // pointer
|
||||
if ( inf_is_64bit() )
|
||||
add_qword(ea, -slide);
|
||||
else
|
||||
add_dword(ea, -slide);
|
||||
break;
|
||||
default: // TODO: there a few more. we will deal with them later
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hide_wait_box();
|
||||
unlock_dbgmem_config();
|
||||
|
||||
qvector<segment_t *> ldrsegs;
|
||||
// we must collect all the loader segments before we start calling move_segm().
|
||||
// this is to avoid altering the areacb_t as we're iterating over it.
|
||||
for ( segment_t *s=get_first_seg(); s != NULL; s=get_next_seg(s->start_ea) )
|
||||
{
|
||||
if ( s->is_loader_segm() )
|
||||
ldrsegs.push_back(s);
|
||||
}
|
||||
|
||||
show_wait_box("Rebasing scattered segments");
|
||||
|
||||
bool ok = true;
|
||||
size_t ls_count = ldrsegs.size();
|
||||
size_t ss_count = si.size();
|
||||
|
||||
// rebase each loader segment according to its matching segment in the scattered image.
|
||||
// currently we require the list of scattered segments and the list of loader segments
|
||||
// to have the exact same ordering. this is because we have no way to uniquely match a
|
||||
// loader segment and a scattered segment without some context. the segment's name, start_ea,
|
||||
// type, and selector are all not sufficient in this situation.
|
||||
for ( size_t i = 0; i < ls_count && !user_cancelled(); i++ )
|
||||
{
|
||||
segment_t *s = ldrsegs[i];
|
||||
|
||||
qstring name;
|
||||
get_segm_name(&name, s);
|
||||
ea_t rebase_to = 0;
|
||||
|
||||
if ( i < ss_count && name == si[i].name )
|
||||
{
|
||||
// found the loader segment in memory. rebase it to this address.
|
||||
rebase_to = si[i].start_ea;
|
||||
}
|
||||
else if ( name == "UNDEF" )
|
||||
{
|
||||
// UNDEF segment is not actually in memory. just rebase it along with the other data segments.
|
||||
rebase_to = s->start_ea + (dbg_data - ldr_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg("%a: Failed to find segment %s in process memory!\n", s->start_ea, name.c_str());
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( s->start_ea != rebase_to )
|
||||
{
|
||||
replace_wait_box("Moving segment %s to %#a", name.c_str(), rebase_to);
|
||||
int code = move_segm(s, rebase_to, MSF_PRIORITY|MSF_SILENT);
|
||||
if ( code != MOVE_SEGM_OK )
|
||||
{
|
||||
msg("%a: Failed to rebase segment %s to %a, code=%d\n", s->start_ea, name.c_str(), rebase_to, code);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hide_wait_box();
|
||||
set_imagebase(base);
|
||||
node.altset(MACHO_ALT_IMAGEBASE, base);
|
||||
|
||||
// update segm eas in the database
|
||||
qstring idx;
|
||||
for ( ssize_t s = node.hashfirst(&idx, SEGM_TAG);
|
||||
s >= 0;
|
||||
s = node.hashnext(&idx, idx.c_str(), SEGM_TAG) )
|
||||
{
|
||||
ea_t start = g_dbgmod.dbg_get_segm_start(base, idx.c_str());
|
||||
if ( start != BADADDR )
|
||||
node.hashset(idx.c_str(), &start, sizeof(start), SEGM_TAG);
|
||||
}
|
||||
|
||||
if ( !ok )
|
||||
{
|
||||
char buf[QMAXPATH];
|
||||
dbg_get_input_path(buf, sizeof(buf));
|
||||
warning("AUTOHIDE DATABASE\n"
|
||||
"Some loader segments were not rebased properly.\n"
|
||||
"\n"
|
||||
"This error might occur if you are debugging a dylib from /System/Library or /usr/lib,\n"
|
||||
"since these files have different segment info when they are loaded from dyld_shared_cache.\n"
|
||||
"\n"
|
||||
"To ensure more accurate segment info when debugging, you can:\n"
|
||||
"\n"
|
||||
" 1. open the dyld_shared_cache in IDA (usually found in /var/db/dyld/)\n"
|
||||
" 2. select the 'Apple DYLD cache (single module)' option\n"
|
||||
" 3. select %s from the list of modules\n"
|
||||
" 4. use %s as the input file path in the Process Options dialog\n", qbasename(buf), buf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
60
idasdk75/dbg/makefile
Normal file
60
idasdk75/dbg/makefile
Normal file
@@ -0,0 +1,60 @@
|
||||
include ../allmake.mak
|
||||
|
||||
# the following platforms only build the servers, and not the plugins.
|
||||
ifneq ($(or $(__ANDROID__),$(__ANDROID_X86__),$(__ARMLINUX__),$(USE_STATIC_RUNTIME)),1)
|
||||
DBG_PLUGIN = $(L)dbg_plugin$(A)
|
||||
CONFIGS += exceptions.cfg
|
||||
endif
|
||||
|
||||
BASE_LIBS += $(L)dbg_rpc$(A)
|
||||
BASE_LIBS += $(L)dbg_server$(A)
|
||||
BASE_LIBS += $(DBG_PLUGIN)
|
||||
BASE_LIBS += $(L)dbg_proc$(A)
|
||||
GOALS += $(addprefix $(C),$(CONFIGS))
|
||||
|
||||
ALLDIRS += linux
|
||||
# ALLDIRS += mac
|
||||
ALLDIRS += win32
|
||||
|
||||
# default target
|
||||
all: $(ALLDIRS) $(GOALS)
|
||||
|
||||
# dependencies
|
||||
$(ALLDIRS): $(BASE_LIBS)
|
||||
|
||||
# recipes for subdirs
|
||||
.PHONY: $(ALLDIRS)
|
||||
$(sort $(ALLDIRS)):
|
||||
$(Q)$(MAKE) -C $@
|
||||
|
||||
clean::
|
||||
$(foreach dir,$(ALLDIRS),$(MAKE) -C $(dir) clean;)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
RPC_OBJS += $(F)dbg_rpc_engine$(O)
|
||||
RPC_OBJS += $(F)dbg_rpc_hlp$(O)
|
||||
$(L)dbg_rpc$(A): $(call lib, $(RPC_OBJS))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
SERVER_OBJS += $(F)bin_search$(O)
|
||||
SERVER_OBJS += $(F)dbg_rpc_handler$(O)
|
||||
SERVER_OBJS += $(F)debmod$(O)
|
||||
SERVER_OBJS += $(F)server$(O)
|
||||
$(L)dbg_server$(A): $(call lib, $(SERVER_OBJS))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
PLUGIN_OBJS += $(F)bin_search$(O)
|
||||
PLUGIN_OBJS += $(F)dbg_rpc_client$(O)
|
||||
PLUGIN_OBJS += $(F)debmod$(O)
|
||||
PLUGIN_OBJS += $(F)rpc_debmod$(O)
|
||||
$(L)dbg_plugin$(A): $(call lib, $(PLUGIN_OBJS))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
PROC_OBJS += $(F)arm_debmod$(O)
|
||||
PROC_OBJS += $(F)arm_regs$(O)
|
||||
PROC_OBJS += $(F)pc_debmod$(O)
|
||||
PROC_OBJS += $(F)pc_regs$(O)
|
||||
$(L)dbg_proc$(A): $(call lib, $(PROC_OBJS))
|
||||
|
||||
include $(IDA)objdir.mak
|
||||
|
||||
304
idasdk75/dbg/pc_debmod.cpp
Normal file
304
idasdk75/dbg/pc_debmod.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
#ifdef __NT__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <pro.h>
|
||||
#include <ua.hpp>
|
||||
#include "pc_debmod.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1566,pc_debmod_t::hwbpt_ea,pc_debmod_t::hwbpt_type)
|
||||
//lint -esym(1566,pc_debmod_t::dr6,pc_debmod_t::dr7)
|
||||
pc_debmod_t::pc_debmod_t()
|
||||
{
|
||||
static const uchar bpt[] = X86_BPT_CODE;
|
||||
bpt_code.append(bpt, sizeof(bpt));
|
||||
sp_idx = R_ESP;
|
||||
pc_idx = R_EIP;
|
||||
sr_idx = R_EFLAGS;
|
||||
fs_idx = R_FS;
|
||||
gs_idx = R_GS;
|
||||
cs_idx = R_CS;
|
||||
ds_idx = R_DS;
|
||||
es_idx = R_ES;
|
||||
ss_idx = R_SS;
|
||||
nregs = X86_NREGS;
|
||||
|
||||
cleanup_hwbpts();
|
||||
set_platform(get_local_platform());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int pc_debmod_t::get_regidx(const char *regname, int *clsmask)
|
||||
{
|
||||
return x86_get_regidx(clsmask, regname);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi pc_debmod_t::dbg_is_ok_bpt(bpttype_t type, ea_t ea, int /* len */)
|
||||
{
|
||||
if ( type == BPT_SOFT )
|
||||
return BPT_OK;
|
||||
|
||||
return find_hwbpt_slot(ea, type) == -1 ? BPT_TOO_MANY : BPT_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// returns -1 if something is wrong
|
||||
int pc_debmod_t::find_hwbpt_slot(ea_t ea, bpttype_t type) const
|
||||
{
|
||||
for ( int i=0; i < MAX_BPT; i++ )
|
||||
{
|
||||
if ( hwbpt_ea[i] == ea && hwbpt_type[i] == type ) // another breakpoint is here
|
||||
return -1;
|
||||
if ( hwbpt_ea[i] == BADADDR ) // empty slot found
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool pc_debmod_t::add_hwbpt(bpttype_t type, ea_t ea, int len)
|
||||
{
|
||||
int i = find_hwbpt_slot(ea, type); // get slot number
|
||||
if ( i != -1 )
|
||||
{
|
||||
hwbpt_ea[i] = ea;
|
||||
hwbpt_type[i] = type;
|
||||
if ( type == BPT_EXEC )
|
||||
type = 0; // exec bpts are encoded with 0 on x86
|
||||
|
||||
// length code used by the processor
|
||||
int lenc = (len == 2) ? 1
|
||||
: (len == 4) ? 3
|
||||
: (len == 8) ? 2
|
||||
: 0;
|
||||
|
||||
dr7 |= (1 << (i*2)); // enable local breakpoint
|
||||
dr7 |= (type << (16+(i*4))); // set breakpoint type
|
||||
dr7 |= (lenc << (18+(i*4))); // set breakpoint length
|
||||
|
||||
return refresh_hwbpts();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool pc_debmod_t::del_hwbpt(ea_t ea, bpttype_t type)
|
||||
{
|
||||
for ( int i=0; i < MAX_BPT; i++ )
|
||||
{
|
||||
if ( hwbpt_ea[i] == ea && hwbpt_type[i] == type )
|
||||
{
|
||||
hwbpt_ea[i] = BADADDR; // clean the address
|
||||
dr7 &= ~(3 << (i*2)); // clean the enable bits
|
||||
dr7 &= ~(0xF << (i*4+16)); // clean the length and type
|
||||
return refresh_hwbpts();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __NT__
|
||||
//--------------------------------------------------------------------------
|
||||
// Set hardware breakpoint for one thread
|
||||
bool pc_debmod_t::set_hwbpts(HANDLE hThread)
|
||||
{
|
||||
// sure_suspend_thread(ti);
|
||||
CONTEXT Context;
|
||||
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_CONTROL;
|
||||
|
||||
BOOL ok = GetThreadContext(hThread, &Context);
|
||||
if ( !ok )
|
||||
{
|
||||
deberr("GetThreadContext");
|
||||
return false;
|
||||
}
|
||||
Context.Dr0 = hwbpt_ea[0];
|
||||
Context.Dr1 = hwbpt_ea[1];
|
||||
Context.Dr2 = hwbpt_ea[2];
|
||||
Context.Dr3 = hwbpt_ea[3];
|
||||
Context.Dr6 = 0;
|
||||
Context.Dr7 = dr7;
|
||||
|
||||
ok = SetThreadContext(hThread, &Context);
|
||||
if ( !ok )
|
||||
{
|
||||
deberr("SetThreadContext");
|
||||
}
|
||||
// sure_resume_thread(ti);
|
||||
return ok != FALSE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ea_t pc_debmod_t::is_hwbpt_triggered(thid_t id, bool is_stepping)
|
||||
{
|
||||
CONTEXT Context;
|
||||
Context.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_CONTROL;
|
||||
HANDLE h = get_thread_handle(id);
|
||||
if ( GetThreadContext(h, &Context) )
|
||||
{
|
||||
for ( int i=0; i < MAX_BPT; i++ )
|
||||
{
|
||||
if ( (Context.Dr7 & uint32(1 << (i*2)))
|
||||
&& (Context.Dr6 & uint32(1 << i)) ) // Local hardware breakpoint 'i'
|
||||
{
|
||||
ULONG_PTR *dr = NULL;
|
||||
switch ( i )
|
||||
{
|
||||
case 0: dr = &Context.Dr0; break;
|
||||
case 1: dr = &Context.Dr1; break;
|
||||
case 2: dr = &Context.Dr2; break;
|
||||
case 3: dr = &Context.Dr3; break;
|
||||
}
|
||||
if ( dr == NULL )
|
||||
break;
|
||||
if ( hwbpt_ea[i] == *dr )
|
||||
{
|
||||
set_hwbpts(h); // Clear the status bits
|
||||
// do not report exec breakpoint if it occurs while we are stepping
|
||||
if ( is_stepping && hwbpt_type[i] == BPT_EXEC )
|
||||
break;
|
||||
return hwbpt_ea[i];
|
||||
}
|
||||
//? TRACING else
|
||||
// debdeb("System hardware breakpoint at %08X ???\n", *dr); //?
|
||||
// what to do ?:
|
||||
// reset it, and continue as if no event were received ?
|
||||
// send it to IDA, and let the user setup a "stop on non-debugger hardware breakpoint" option ?
|
||||
}
|
||||
}
|
||||
}
|
||||
return BADADDR;
|
||||
}
|
||||
#endif // ifdef __NT__
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void pc_debmod_t::cleanup_hwbpts()
|
||||
{
|
||||
for ( int i=0; i < MAX_BPT; i++ )
|
||||
{
|
||||
hwbpt_ea[i] = BADADDR;
|
||||
hwbpt_type[i] = bpttype_t(0);
|
||||
}
|
||||
dr6 = 0;
|
||||
dr7 = 0x100; // exact local breakpoints
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ea_t pc_debmod_t::calc_appcall_stack(const regvals_t ®vals)
|
||||
{
|
||||
ea_t ea = inherited::calc_appcall_stack(regvals);
|
||||
#ifndef __X86__
|
||||
// do not touch the red zone (used by gcc)
|
||||
ea = ea > 128 ? ea - 128 : BADADDR;
|
||||
#endif
|
||||
return ea;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int pc_debmod_t::finalize_appcall_stack(
|
||||
call_context_t &,
|
||||
regval_map_t &,
|
||||
bytevec_t &stk)
|
||||
{
|
||||
// pc-specific: add endless loop, so user does not execute unwanted code
|
||||
// after manual appcall. we do not really need to write bpt,
|
||||
// but it is easy to include it here than skip it.
|
||||
// previously we reserved 'addrsize' bytes on the stack for this purpose,
|
||||
// and we use 3 of them.
|
||||
static const uchar bpt_and_loop[] = { 0xCC, 0xEB, 0xFE };
|
||||
stk.append(bpt_and_loop, sizeof(bpt_and_loop));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool pc_debmod_t::should_stop_appcall(
|
||||
thid_t tid,
|
||||
const debug_event_t *event,
|
||||
ea_t ea)
|
||||
{
|
||||
if ( inherited::should_stop_appcall(tid, event, ea) )
|
||||
return true;
|
||||
|
||||
// Check if the current instruction is a "RET" and then dereferences
|
||||
// the contents of SP to find the return address. IF it matches, it is
|
||||
// time to stop
|
||||
regvals_t regs;
|
||||
regs.resize(X86_NREGS);
|
||||
do
|
||||
{
|
||||
// Start by reading registers
|
||||
if ( dbg_read_registers(tid, X86_RC_GENERAL, regs.begin(), NULL) != DRC_OK )
|
||||
break;
|
||||
|
||||
// Get the opcodes
|
||||
uchar opcode;
|
||||
if ( dbg_read_memory((ea_t)regs[pc_idx].ival, &opcode, 1, NULL) != 1 )
|
||||
break;
|
||||
// Check for "RET" and "RET n"
|
||||
if ( opcode != 0xC3 && opcode != 0xC2 )
|
||||
break;
|
||||
|
||||
// Dereference value at ESP
|
||||
ea_t at_sp = BADADDR;
|
||||
if ( dbg_read_memory((ea_t)regs[sp_idx].ival, &at_sp, sizeof(at_sp), NULL) != sizeof(at_sp) )
|
||||
break;
|
||||
return ea == at_sp; // time to stop!
|
||||
} while ( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool pc_debmod_t::preprocess_appcall_cleanup(thid_t, call_context_t &ctx)
|
||||
{
|
||||
// Linux 2.6.24-19 has a bug(?):
|
||||
// it doesn't clear trace flag after single-stepping
|
||||
// so if we single-step and then make an appcall, we would restore eflags with TF set
|
||||
// but next time we resume the program, kernel thinks that TF was set by the user
|
||||
// and doesn't clear it, and so our appcall stops immediately
|
||||
// to prevent that, we'll always clear trace flag before restoring eflags
|
||||
if ( ctx.saved_regs.size() > sr_idx )
|
||||
ctx.saved_regs[sr_idx].ival &= ~0x100;
|
||||
return true; // success
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void pc_debmod_t::read_fpu_registers(
|
||||
regval_t *values,
|
||||
int clsmask,
|
||||
const void *fptr,
|
||||
size_t step)
|
||||
{
|
||||
const uchar *vptr = (const uchar *)fptr;
|
||||
for ( int i=0; i < 8; i++,vptr+=step )
|
||||
{
|
||||
if ( (clsmask & X86_RC_FPU) != 0 )
|
||||
{
|
||||
regval_t *v = &values[R_ST0+i];
|
||||
memcpy(v->fval, vptr, 10); //-V512 v->fval underflow
|
||||
v->rvtype = RVT_FLOAT;
|
||||
}
|
||||
if ( (clsmask & X86_RC_MMX) != 0 )
|
||||
values[R_MMX0+i].set_bytes(vptr, 8);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const char *pc_debmod_t::get_local_platform()
|
||||
{
|
||||
#ifdef __NT__
|
||||
# define LOCAL_PLATFORM "win32"
|
||||
#else
|
||||
# ifdef __MAC__
|
||||
# define LOCAL_PLATFORM "macosx"
|
||||
# else
|
||||
# ifdef __LINUX__
|
||||
# define LOCAL_PLATFORM "linux"
|
||||
# else
|
||||
# define LOCAL_PLATFORM "PC_UNDEFINED"
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
return LOCAL_PLATFORM;
|
||||
}
|
||||
52
idasdk75/dbg/pc_debmod.h
Normal file
52
idasdk75/dbg/pc_debmod.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef __PC_DEBUGGER_MODULE__
|
||||
#define __PC_DEBUGGER_MODULE__
|
||||
|
||||
#ifdef __NT__
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "pc_regs.hpp"
|
||||
#include "deb_pc.hpp"
|
||||
#include "debmod.h"
|
||||
|
||||
class pc_debmod_t: public debmod_t
|
||||
{
|
||||
typedef debmod_t inherited;
|
||||
protected:
|
||||
// Hardware breakpoints
|
||||
ea_t hwbpt_ea[MAX_BPT];
|
||||
bpttype_t hwbpt_type[MAX_BPT];
|
||||
uint32 dr6;
|
||||
uint32 dr7;
|
||||
|
||||
int sr_idx;
|
||||
int fs_idx;
|
||||
int gs_idx;
|
||||
int cs_idx;
|
||||
int ds_idx;
|
||||
int es_idx;
|
||||
int ss_idx;
|
||||
|
||||
public:
|
||||
pc_debmod_t();
|
||||
void cleanup_hwbpts();
|
||||
virtual bool refresh_hwbpts() newapi { return false; }
|
||||
int find_hwbpt_slot(ea_t ea, bpttype_t type) const;
|
||||
bool del_hwbpt(ea_t ea, bpttype_t type);
|
||||
bool add_hwbpt(bpttype_t type, ea_t ea, int len);
|
||||
static const char *get_local_platform();
|
||||
#ifdef __NT__
|
||||
virtual bool set_hwbpts(HANDLE hThread) newapi;
|
||||
ea_t is_hwbpt_triggered(thid_t id, bool is_stepping);
|
||||
virtual HANDLE get_thread_handle(thid_t /*tid*/) newapi { return INVALID_HANDLE_VALUE; }
|
||||
#endif
|
||||
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) override;
|
||||
virtual int finalize_appcall_stack(call_context_t &, regval_map_t &, bytevec_t &stk) override;
|
||||
virtual ea_t calc_appcall_stack(const regvals_t ®vals) override;
|
||||
virtual bool should_stop_appcall(thid_t tid, const debug_event_t *event, ea_t ea) override;
|
||||
virtual bool preprocess_appcall_cleanup(thid_t tid, call_context_t &ctx) override;
|
||||
virtual int get_regidx(const char *regname, int *clsmask) override;
|
||||
static void read_fpu_registers(regval_t *values, int clsmask, const void *fptr, size_t step);
|
||||
};
|
||||
|
||||
#endif
|
||||
113
idasdk75/dbg/pc_local_impl.cpp
Normal file
113
idasdk75/dbg/pc_local_impl.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// x86-specific code (compiled only on IDA side, never on the server side)
|
||||
|
||||
#include <dbg.hpp>
|
||||
#include "pc_regs.hpp"
|
||||
#include "deb_pc.hpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// DEBUGGER REGISTER AND INSTRUCTION INFORMATIONS
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#if 0
|
||||
static void DEBUG_REGVALS(regval_t *values)
|
||||
{
|
||||
for ( int i = 0; i < qnumber(registers); i++ )
|
||||
{
|
||||
msg("%s = ", registers[i].name);
|
||||
switch ( registers[i].dtyp )
|
||||
{
|
||||
case dt_qword: msg("%016LX\n", values[i].ival); break;
|
||||
case dt_dword: msg("%08X\n", values[i].ival); break;
|
||||
case dt_word: msg("%04X\n", values[i].ival); break;
|
||||
case dt_tbyte:
|
||||
for ( int j = 0; j < sizeof(regval_t); j++ )
|
||||
{
|
||||
if ( j == 10 )
|
||||
msg(" - "); // higher bytes are not used by x86 floats
|
||||
msg("%02X ", ((unsigned char*)&values[i])[j]);
|
||||
}
|
||||
// msg("%02X ", (unsigned short)values[i].fval[j]);
|
||||
msg("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
msg("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi x86_read_registers(
|
||||
thid_t thread_id,
|
||||
int clsmask,
|
||||
regval_t *values,
|
||||
qstring *errbuf)
|
||||
{
|
||||
drc_t drc = s_read_registers(thread_id, clsmask, values, errbuf);
|
||||
if ( drc == DRC_OK )
|
||||
{
|
||||
// FPU related registers
|
||||
if ( (clsmask & X86_RC_FPU) != 0 )
|
||||
{
|
||||
for ( size_t i = 0; i < debugger.nregs; i++ )
|
||||
{
|
||||
const register_info_t &ri = debugger.regs(i);
|
||||
if ( ri.register_class == X86_RC_FPU && ri.dtype == dt_tbyte )
|
||||
{
|
||||
int rc = processor_t::realcvt(values[i].fval, values[i].fval, 004); // // load long double
|
||||
if ( rc == 0 )
|
||||
break; // realcvt not implemented
|
||||
else if ( rc < 0 ) // error
|
||||
memset(values[i].fval, 0, sizeof(values[i].fval));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi x86_write_register(
|
||||
thid_t thread_id,
|
||||
int reg_idx,
|
||||
const regval_t *value,
|
||||
qstring *errbuf)
|
||||
{
|
||||
regval_t rv = *value;
|
||||
// FPU related registers
|
||||
const register_info_t &ri = debugger.regs(reg_idx);
|
||||
if ( ri.register_class == X86_RC_FPU && ri.dtype == dt_tbyte )
|
||||
{
|
||||
uchar fn[10];
|
||||
int code = processor_t::realcvt(fn, rv.fval, 014); // store long double //-V536 octal
|
||||
if ( code == 1 )
|
||||
memcpy(rv.fval, fn, 10); //-V512 rv.fval underflow
|
||||
}
|
||||
return s_write_register(thread_id, reg_idx, &rv, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int is_x86_valid_bpt(bpttype_t type, ea_t ea, int len)
|
||||
{
|
||||
if ( type != BPT_SOFT )
|
||||
{
|
||||
if ( (debugger.flags & DBG_FLAG_ANYSIZE_HWBPT) == 0 )
|
||||
return check_x86_hwbpt(type, ea, len);
|
||||
|
||||
if ( type == 0 )
|
||||
return BPT_BAD_TYPE;
|
||||
}
|
||||
return BPT_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void processor_specific_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void processor_specific_term(void)
|
||||
{
|
||||
}
|
||||
329
idasdk75/dbg/pc_regs.cpp
Normal file
329
idasdk75/dbg/pc_regs.cpp
Normal file
@@ -0,0 +1,329 @@
|
||||
|
||||
#include "pc_regs.hpp"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: keep in sync with register_class_x86_t
|
||||
const char *x86_register_classes[] =
|
||||
{
|
||||
"General registers",
|
||||
"Segment registers",
|
||||
"FPU registers",
|
||||
"MMX registers",
|
||||
"XMM registers",
|
||||
"YMM registers",
|
||||
NULL
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const eflags[] =
|
||||
{
|
||||
"CF", // 0
|
||||
NULL, // 1
|
||||
"PF", // 2
|
||||
NULL, // 3
|
||||
"AF", // 4
|
||||
NULL, // 5
|
||||
"ZF", // 6
|
||||
"SF", // 7
|
||||
"TF", // 8
|
||||
"IF", // 9
|
||||
"DF", // 10
|
||||
"OF", // 11
|
||||
"IOPL", // 12
|
||||
"IOPL", // 13
|
||||
"NT", // 14
|
||||
NULL, // 15
|
||||
"RF", // 16
|
||||
"VM", // 17
|
||||
"AC", // 18
|
||||
"VIF", // 19
|
||||
"VIP", // 20
|
||||
"ID", // 21
|
||||
NULL, // 22
|
||||
NULL, // 23
|
||||
NULL, // 24
|
||||
NULL, // 25
|
||||
NULL, // 26
|
||||
NULL, // 27
|
||||
NULL, // 28
|
||||
NULL, // 29
|
||||
NULL, // 30
|
||||
NULL // 31
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const ctrlflags[] =
|
||||
{
|
||||
"CTRL.IM",
|
||||
"CTRL.DM",
|
||||
"CTRL.ZM",
|
||||
"CTRL.OM",
|
||||
"CTRL.UM",
|
||||
"CTRL.PM",
|
||||
NULL,
|
||||
NULL,
|
||||
"CTRL.PC",
|
||||
"CTRL.PC",
|
||||
"CTRL.RC",
|
||||
"CTRL.RC",
|
||||
"CTRL.X",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const statflags[] =
|
||||
{
|
||||
"STAT.IE",
|
||||
"STAT.DE",
|
||||
"STAT.ZE",
|
||||
"STAT.OE",
|
||||
"STAT.UE",
|
||||
"STAT.PE",
|
||||
"STAT.SF",
|
||||
"STAT.ES",
|
||||
"STAT.C0",
|
||||
"STAT.C1",
|
||||
"STAT.C2",
|
||||
"STAT.TOP",
|
||||
"STAT.TOP",
|
||||
"STAT.TOP",
|
||||
"STAT.C3",
|
||||
"STAT.B"
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const tagsflags[] =
|
||||
{
|
||||
"TAG0",
|
||||
"TAG0",
|
||||
"TAG1",
|
||||
"TAG1",
|
||||
"TAG2",
|
||||
"TAG2",
|
||||
"TAG3",
|
||||
"TAG3",
|
||||
"TAG4",
|
||||
"TAG4",
|
||||
"TAG5",
|
||||
"TAG5",
|
||||
"TAG6",
|
||||
"TAG6",
|
||||
"TAG7",
|
||||
"TAG7"
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const xmm_format[] =
|
||||
{
|
||||
"XMM_4_floats",
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const ymm_format[] =
|
||||
{
|
||||
"YMM_8_floats",
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const mmx_format[] =
|
||||
{
|
||||
"MMX_8_bytes",
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char *const mxcsr_bits[] =
|
||||
{
|
||||
"IE", // 0 Invalid Operation Flag
|
||||
"DE", // 1 Denormal Flag
|
||||
"ZE", // 2 Divide-by-Zero Flag
|
||||
"OE", // 3 Overflow Flag
|
||||
"UE", // 4 Underflow Flag
|
||||
"PE", // 5 Precision Flag
|
||||
"DAZ", // 6 Denormals Are Zeros*
|
||||
"IM", // 7 Invalid Operation Mask
|
||||
"DM", // 8 Denormal Operation Mask
|
||||
"ZM", // 9 Divide-by-Zero Mask
|
||||
"OM", // 10 Overflow Mask
|
||||
"UM", // 11 Underflow Mask
|
||||
"PM", // 12 Precision Mask
|
||||
"RC", // 13 Rounding Control
|
||||
"RC", // 14 Rounding Control
|
||||
"FZ", // 15 Flush to Zero
|
||||
NULL, // 16
|
||||
NULL, // 17
|
||||
NULL, // 18
|
||||
NULL, // 19
|
||||
NULL, // 20
|
||||
NULL, // 21
|
||||
NULL, // 22
|
||||
NULL, // 23
|
||||
NULL, // 24
|
||||
NULL, // 25
|
||||
NULL, // 26
|
||||
NULL, // 27
|
||||
NULL, // 28
|
||||
NULL, // 29
|
||||
NULL, // 30
|
||||
NULL // 31
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// General registers
|
||||
#ifdef __EA64__
|
||||
register_info_t r_rax = { "RAX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_rbx = { "RBX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_rcx = { "RCX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_rdx = { "RDX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_rsi = { "RSI", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_rdi = { "RDI", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_rbp = { "RBP", REGISTER_ADDRESS|REGISTER_FP, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_rsp = { "RSP", REGISTER_ADDRESS|REGISTER_SP, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_rip = { "RIP", REGISTER_ADDRESS|REGISTER_IP, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_r8 = { "R8", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_r9 = { "R9", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_r10 = { "R10", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_r11 = { "R11", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_r12 = { "R12", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_r13 = { "R13", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_r14 = { "R14", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
register_info_t r_r15 = { "R15", REGISTER_ADDRESS, X86_RC_GENERAL, dt_qword, NULL, 0 };
|
||||
#endif
|
||||
register_info_t r_eax = { "EAX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
register_info_t r_ebx = { "EBX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
register_info_t r_ecx = { "ECX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
register_info_t r_edx = { "EDX", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
register_info_t r_esi = { "ESI", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
register_info_t r_edi = { "EDI", REGISTER_ADDRESS, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
register_info_t r_ebp = { "EBP", REGISTER_ADDRESS|REGISTER_FP, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
register_info_t r_esp = { "ESP", REGISTER_ADDRESS|REGISTER_SP, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
register_info_t r_eip = { "EIP", REGISTER_ADDRESS|REGISTER_IP, X86_RC_GENERAL, dt_dword, NULL, 0 };
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: keep in sync with register_x86_t
|
||||
register_info_t x86_registers[] =
|
||||
{
|
||||
// FPU registers
|
||||
{ "ST0", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
|
||||
{ "ST1", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
|
||||
{ "ST2", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
|
||||
{ "ST3", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
|
||||
{ "ST4", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
|
||||
{ "ST5", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
|
||||
{ "ST6", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
|
||||
{ "ST7", 0, X86_RC_FPU, dt_tbyte, NULL, 0 },
|
||||
{ "CTRL", 0, X86_RC_FPU, dt_word, ctrlflags, 0x1F3F },
|
||||
{ "STAT", 0, X86_RC_FPU, dt_word, statflags, 0xFFFF },
|
||||
{ "TAGS", 0, X86_RC_FPU, dt_word, tagsflags, 0xFFFF },
|
||||
// Segment registers
|
||||
{ "CS", REGISTER_CS|REGISTER_NOLF, X86_RC_SEGMENTS, dt_word, NULL, 0 },
|
||||
{ "DS", REGISTER_NOLF, X86_RC_SEGMENTS, dt_word, NULL, 0 },
|
||||
{ "ES", 0, X86_RC_SEGMENTS, dt_word, NULL, 0 },
|
||||
{ "FS", REGISTER_NOLF, X86_RC_SEGMENTS, dt_word, NULL, 0 },
|
||||
{ "GS", REGISTER_NOLF, X86_RC_SEGMENTS, dt_word, NULL, 0 },
|
||||
{ "SS", REGISTER_SS, X86_RC_SEGMENTS, dt_word, NULL, 0 },
|
||||
// General registers
|
||||
#ifdef __EA64__
|
||||
r_rax,
|
||||
r_rbx,
|
||||
r_rcx,
|
||||
r_rdx,
|
||||
r_rsi,
|
||||
r_rdi,
|
||||
r_rbp,
|
||||
r_rsp,
|
||||
r_rip,
|
||||
r_r8,
|
||||
r_r9,
|
||||
r_r10,
|
||||
r_r11,
|
||||
r_r12,
|
||||
r_r13,
|
||||
r_r14,
|
||||
r_r15,
|
||||
#else
|
||||
r_eax,
|
||||
r_ebx,
|
||||
r_ecx,
|
||||
r_edx,
|
||||
r_esi,
|
||||
r_edi,
|
||||
r_ebp,
|
||||
r_esp,
|
||||
r_eip,
|
||||
#endif
|
||||
{ "EFL", 0, X86_RC_GENERAL, dt_dword, eflags, 0x00000FD5 }, // OF|DF|IF|TF|SF|ZF|AF|PF|CF
|
||||
// XMM registers
|
||||
{ "XMM0", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM1", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM2", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM3", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM4", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM5", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM6", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM7", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
#ifdef __EA64__
|
||||
{ "XMM8", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM9", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM10", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM11", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM12", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM13", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM14", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
{ "XMM15", REGISTER_CUSTFMT, X86_RC_XMM, dt_byte16, xmm_format, 0 },
|
||||
#endif
|
||||
{ "MXCSR", 0, X86_RC_XMM, dt_dword, mxcsr_bits, 0xFFFF },
|
||||
// MMX registers
|
||||
{ "MM0", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
|
||||
{ "MM1", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
|
||||
{ "MM2", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
|
||||
{ "MM3", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
|
||||
{ "MM4", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
|
||||
{ "MM5", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
|
||||
{ "MM6", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
|
||||
{ "MM7", REGISTER_CUSTFMT, X86_RC_MMX, dt_qword, mmx_format, 0 },
|
||||
// YMM registers
|
||||
{ "YMM0", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM1", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM2", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM3", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM4", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM5", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM6", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM7", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
#ifdef __EA64__
|
||||
{ "YMM8", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM9", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM10", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM11", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM12", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM13", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM14", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
{ "YMM15", REGISTER_CUSTFMT, X86_RC_YMM, dt_byte32, ymm_format, 0 },
|
||||
#endif
|
||||
};
|
||||
CASSERT(qnumber(x86_registers) == X86_NREGS);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int x86_get_regidx(int *clsmask, const char *regname)
|
||||
{
|
||||
for ( size_t i = 0; i < qnumber(x86_registers); i++ )
|
||||
{
|
||||
if ( strieq(regname, x86_registers[i].name) )
|
||||
{
|
||||
if ( clsmask != NULL )
|
||||
*clsmask = x86_registers[i].register_class;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int x86_get_regclass(int idx)
|
||||
{
|
||||
if ( idx >= 0 && idx < qnumber(x86_registers) )
|
||||
return x86_registers[idx].register_class;
|
||||
return 0;
|
||||
}
|
||||
172
idasdk75/dbg/pc_regs.hpp
Normal file
172
idasdk75/dbg/pc_regs.hpp
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pro.h>
|
||||
#include <idd.hpp>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: keep in sync with x86_register_classes
|
||||
enum register_class_x86_t
|
||||
{
|
||||
X86_RC_GENERAL = 0x01, // General registers
|
||||
X86_RC_SEGMENTS = 0x02, // Segment registers
|
||||
X86_RC_FPU = 0x04, // FPU registers
|
||||
X86_RC_MMX = 0x08, // MMX registers
|
||||
X86_RC_XMM = 0x10, // XMM registers
|
||||
X86_RC_YMM = 0x20, // YMM registers
|
||||
X86_RC_ALL = X86_RC_GENERAL
|
||||
| X86_RC_SEGMENTS
|
||||
| X86_RC_FPU
|
||||
| X86_RC_MMX
|
||||
| X86_RC_XMM
|
||||
| X86_RC_YMM
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: keep in sync with x86_registers
|
||||
enum register_x86_t
|
||||
{
|
||||
// FPU registers
|
||||
R_ST0,
|
||||
R_ST1,
|
||||
R_ST2,
|
||||
R_ST3,
|
||||
R_ST4,
|
||||
R_ST5,
|
||||
R_ST6,
|
||||
R_ST7,
|
||||
R_CTRL,
|
||||
R_STAT,
|
||||
R_TAGS,
|
||||
// Segment registers
|
||||
R_CS,
|
||||
R_DS,
|
||||
R_ES,
|
||||
R_FS,
|
||||
R_GS,
|
||||
R_SS,
|
||||
// General registers
|
||||
R_EAX,
|
||||
R_EBX,
|
||||
R_ECX,
|
||||
R_EDX,
|
||||
R_ESI,
|
||||
R_EDI,
|
||||
R_EBP,
|
||||
R_ESP,
|
||||
R_EIP,
|
||||
#ifdef __EA64__
|
||||
R_R8,
|
||||
R_R9,
|
||||
R_R10,
|
||||
R_R11,
|
||||
R_R12,
|
||||
R_R13,
|
||||
R_R14,
|
||||
R_R15,
|
||||
#endif
|
||||
R_EFLAGS,
|
||||
// XMM registers
|
||||
R_XMM0,
|
||||
R_XMM1,
|
||||
R_XMM2,
|
||||
R_XMM3,
|
||||
R_XMM4,
|
||||
R_XMM5,
|
||||
R_XMM6,
|
||||
R_XMM7,
|
||||
#ifndef __EA64__
|
||||
R_LAST_XMM = R_XMM7,
|
||||
#else
|
||||
R_XMM8,
|
||||
R_XMM9,
|
||||
R_XMM10,
|
||||
R_XMM11,
|
||||
R_XMM12,
|
||||
R_XMM13,
|
||||
R_XMM14,
|
||||
R_XMM15,
|
||||
R_LAST_XMM = R_XMM15,
|
||||
#endif
|
||||
R_MXCSR,
|
||||
// MMX registers
|
||||
R_MMX0,
|
||||
R_MMX1,
|
||||
R_MMX2,
|
||||
R_MMX3,
|
||||
R_MMX4,
|
||||
R_MMX5,
|
||||
R_MMX6,
|
||||
R_MMX7,
|
||||
// YMM registers
|
||||
R_YMM0,
|
||||
R_YMM1,
|
||||
R_YMM2,
|
||||
R_YMM3,
|
||||
R_YMM4,
|
||||
R_YMM5,
|
||||
R_YMM6,
|
||||
R_YMM7,
|
||||
#ifndef __EA64__
|
||||
R_LAST_YMM = R_YMM7,
|
||||
#else
|
||||
R_YMM8,
|
||||
R_YMM9,
|
||||
R_YMM10,
|
||||
R_YMM11,
|
||||
R_YMM12,
|
||||
R_YMM13,
|
||||
R_YMM14,
|
||||
R_YMM15,
|
||||
R_LAST_YMM = R_YMM15,
|
||||
#endif
|
||||
};
|
||||
|
||||
// Number of registers in x86 and x64
|
||||
#define X86_X64_NREGS 76
|
||||
#define X86_X86_NREGS 52
|
||||
|
||||
#ifdef __EA64__
|
||||
#define X86_NREGS X86_X64_NREGS
|
||||
#else
|
||||
#define X86_NREGS X86_X86_NREGS
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// General registers
|
||||
#ifdef __EA64__
|
||||
extern register_info_t r_rax;
|
||||
extern register_info_t r_rbx;
|
||||
extern register_info_t r_rcx;
|
||||
extern register_info_t r_rdx;
|
||||
extern register_info_t r_rsi;
|
||||
extern register_info_t r_rdi;
|
||||
extern register_info_t r_rbp;
|
||||
extern register_info_t r_rsp;
|
||||
extern register_info_t r_rip;
|
||||
extern register_info_t r_r8;
|
||||
extern register_info_t r_r9;
|
||||
extern register_info_t r_r10;
|
||||
extern register_info_t r_r11;
|
||||
extern register_info_t r_r12;
|
||||
extern register_info_t r_r13;
|
||||
extern register_info_t r_r14;
|
||||
extern register_info_t r_r15;
|
||||
#endif
|
||||
extern register_info_t r_eax;
|
||||
extern register_info_t r_ebx;
|
||||
extern register_info_t r_ecx;
|
||||
extern register_info_t r_edx;
|
||||
extern register_info_t r_esi;
|
||||
extern register_info_t r_edi;
|
||||
extern register_info_t r_ebp;
|
||||
extern register_info_t r_esp;
|
||||
extern register_info_t r_eip;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
extern const char *x86_register_classes[];
|
||||
extern register_info_t x86_registers[X86_NREGS];
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int x86_get_regidx(int *clsmask, const char *regname);
|
||||
int x86_get_regclass(int idx);
|
||||
18
idasdk75/dbg/plugin.mak
Normal file
18
idasdk75/dbg/plugin.mak
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
ifneq ($(wildcard ../../parse),)
|
||||
CC_DEFS += ENABLE_LOWCNDS
|
||||
endif
|
||||
CC_INCP += ..
|
||||
|
||||
include ../../plugins/plugin.mak
|
||||
|
||||
PLUGIN_LIBS += $(L)dbg_plugin$(A)
|
||||
PLUGIN_LIBS += $(L)dbg_rpc$(A)
|
||||
PLUGIN_LIBS += $(L)dbg_proc$(A)
|
||||
PLUGIN_LIBS += $(L)network$(A)
|
||||
$(MODULES): LIBS += $(PLUGIN_LIBS)
|
||||
$(MODULES): $(PLUGIN_LIBS)
|
||||
|
||||
ifeq ($(or $(__LINUX__),$(__MAC__)),1)
|
||||
$(MODULES): STDLIBS += -ldl
|
||||
endif
|
||||
996
idasdk75/dbg/rpc_debmod.cpp
Normal file
996
idasdk75/dbg/rpc_debmod.cpp
Normal file
@@ -0,0 +1,996 @@
|
||||
|
||||
#include <segment.hpp>
|
||||
#include <err.h>
|
||||
#include <network.hpp>
|
||||
|
||||
#include "rpc_debmod.h"
|
||||
#include "dbg_rpc_hlp.h"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
inline drc_t unpack_drc(memory_deserializer_t &mmdsr)
|
||||
{
|
||||
return drc_t(mmdsr.unpack_dd());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
rpc_debmod_t::rpc_debmod_t(const char *default_platform)
|
||||
: dbg_rpc_client_t(NULL)
|
||||
{
|
||||
nregs = debugger.nregs;
|
||||
for ( int i=0; i < nregs; i++ )
|
||||
{
|
||||
const register_info_t &ri = debugger.regs(i);
|
||||
if ( (ri.flags & REGISTER_SP) != 0 )
|
||||
sp_idx = i;
|
||||
if ( (ri.flags & REGISTER_IP) != 0 )
|
||||
pc_idx = i;
|
||||
}
|
||||
bpt_code.append(debugger.bpt_bytes, debugger.bpt_size);
|
||||
rpc = this;
|
||||
|
||||
set_platform(default_platform);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi rpc_debmod_t::handle_ioctl( //-V524 equivalent to 'send_ioctl'
|
||||
int fn,
|
||||
const void *buf,
|
||||
size_t size,
|
||||
void **poutbuf,
|
||||
ssize_t *poutsize)
|
||||
{
|
||||
return rpc_engine_t::send_ioctl(fn, buf, size, poutbuf, poutsize);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline int get_expected_addrsize(void)
|
||||
{
|
||||
if ( is_miniidb() )
|
||||
#ifdef __EA64__
|
||||
return 8;
|
||||
#else
|
||||
return 4;
|
||||
#endif
|
||||
return inf_is_64bit() ? 8 : 4;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi rpc_debmod_t::open_remote(
|
||||
const char *hostname,
|
||||
int port_number,
|
||||
const char *password,
|
||||
qstring *errbuf)
|
||||
{
|
||||
if ( hostname[0] == '\0' )
|
||||
{
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = "Please specify the hostname in Debugger, Process options";
|
||||
return false;
|
||||
}
|
||||
|
||||
rpc_packet_t *rp = NULL;
|
||||
network_error = false;
|
||||
client_irs = irs_new();
|
||||
if ( !irs_init_client(client_irs, hostname, port_number) )
|
||||
{
|
||||
FAILURE:
|
||||
if ( rp != NULL )
|
||||
qfree(rp);
|
||||
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = irs_strerror(client_irs);
|
||||
irs_term(&client_irs);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
rp = recv_packet();
|
||||
if ( rp == NULL || rp->code != RPC_OPEN ) // is this an ida debugger server?
|
||||
{
|
||||
dbg_rpc_client_t::dwarning("ICON ERROR\nAUTOHIDE NONE\n"
|
||||
"Bogus or irresponsive remote server");
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
int version = mmdsr.unpack_dd();
|
||||
int remote_debugger_id = mmdsr.unpack_dd();
|
||||
int easize = mmdsr.unpack_dd();
|
||||
qstring errstr;
|
||||
if ( version != IDD_INTERFACE_VERSION )
|
||||
errstr.sprnt("protocol version is %d, expected %d", version, IDD_INTERFACE_VERSION);
|
||||
else if ( remote_debugger_id != debugger.id )
|
||||
errstr.sprnt("debugger id is %d, expected %d (%s)", remote_debugger_id, debugger.id, debugger.name);
|
||||
else if ( easize < get_expected_addrsize() )
|
||||
errstr.sprnt("address size is %d bytes, expected at least %d", easize, get_expected_addrsize());
|
||||
if ( !errstr.empty() )
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_OK);
|
||||
req.pack_dd(false);
|
||||
send_data(req);
|
||||
warning("ICON ERROR\nAUTOHIDE NONE\n"
|
||||
"Incompatible debugging server:\n"
|
||||
"%s", errstr.c_str());
|
||||
goto FAILURE;
|
||||
}
|
||||
qfree(rp);
|
||||
|
||||
bytevec_t req = prepare_rpc_packet(RPC_OK);
|
||||
req.pack_dd(true);
|
||||
req.pack_str(password);
|
||||
send_data(req);
|
||||
|
||||
rp = recv_packet();
|
||||
if ( rp == NULL || rp->code != RPC_OK )
|
||||
goto FAILURE;
|
||||
|
||||
memory_deserializer_t mmdsr2(rp+1, rp->length);
|
||||
bool password_ok = mmdsr2.unpack_dd() != 0;
|
||||
if ( !password_ok ) // is this an ida debugger server?
|
||||
{
|
||||
warning("ICON ERROR\nAUTOHIDE NONE\n"
|
||||
"Bad password");
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
qfree(rp);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi rpc_debmod_t::dbg_add_bpt(bytevec_t *, bpttype_t, ea_t, int)
|
||||
{
|
||||
INTERR(30114);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi rpc_debmod_t::dbg_del_bpt(bpttype_t, ea_t, const uchar *, int)
|
||||
{
|
||||
INTERR(30115);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_update_lowcnds(
|
||||
int *nupdated,
|
||||
const lowcnd_t *lowcnds,
|
||||
int nlowcnds,
|
||||
qstring *errbuf)
|
||||
{
|
||||
ea_t ea = 0;
|
||||
bytevec_t req = prepare_rpc_packet(RPC_UPDATE_LOWCNDS);
|
||||
req.pack_dd(nlowcnds);
|
||||
const lowcnd_t *lc = lowcnds;
|
||||
for ( int i=0; i < nlowcnds; i++, lc++ )
|
||||
{
|
||||
req.pack_ea64(lc->ea-ea); ea = lc->ea;
|
||||
req.pack_str(lc->cndbody);
|
||||
if ( !lc->cndbody.empty() )
|
||||
{
|
||||
req.pack_dd(lc->type);
|
||||
if ( lc->type != BPT_SOFT )
|
||||
req.pack_dd(lc->size);
|
||||
req.pack_db(lc->orgbytes.size());
|
||||
req.append(lc->orgbytes.begin(), lc->orgbytes.size());
|
||||
req.pack_ea64(lc->cmd.ea);
|
||||
if ( lc->cmd.ea != BADADDR )
|
||||
req.append(&lc->cmd, sizeof(lc->cmd));
|
||||
}
|
||||
}
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
int ret_nupdated = mmdsr.unpack_dd();
|
||||
if ( nupdated != NULL )
|
||||
*nupdated = ret_nupdated;
|
||||
|
||||
if ( errbuf != NULL && drc != DRC_NONE )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_EVAL_LOWCND);
|
||||
req.pack_dd(tid);
|
||||
req.pack_ea64(ea);
|
||||
return send_request_get_drc_result(req, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_update_bpts(
|
||||
int *nbpts,
|
||||
update_bpt_info_t *ubpts,
|
||||
int nadd,
|
||||
int ndel,
|
||||
qstring *errbuf)
|
||||
{
|
||||
int skipped = 0;
|
||||
update_bpt_info_t *b;
|
||||
update_bpt_info_t *bend = ubpts + nadd;
|
||||
for ( b=ubpts; b != bend; b++ )
|
||||
if ( b->code != BPT_OK )
|
||||
skipped++;
|
||||
if ( skipped == nadd && ndel == 0 )
|
||||
{
|
||||
if ( nbpts != NULL )
|
||||
*nbpts = 0; // no bpts to update
|
||||
return DRC_OK;
|
||||
}
|
||||
|
||||
bytevec_t req = prepare_rpc_packet(RPC_UPDATE_BPTS);
|
||||
req.pack_dd(nadd-skipped);
|
||||
req.pack_dd(ndel);
|
||||
ea_t ea = 0;
|
||||
for ( b=ubpts; b != bend; b++ )
|
||||
{
|
||||
if ( b->code == BPT_OK )
|
||||
{
|
||||
req.pack_ea64(b->ea-ea); ea = b->ea;
|
||||
req.pack_dd(b->size);
|
||||
req.pack_dd(b->type);
|
||||
req.pack_dd(b->pid);
|
||||
req.pack_dd(b->tid);
|
||||
}
|
||||
}
|
||||
|
||||
ea = 0;
|
||||
bend += ndel;
|
||||
for ( ; b != bend; b++ )
|
||||
{
|
||||
req.pack_ea64(b->ea-ea); ea = b->ea;
|
||||
req.pack_db(b->orgbytes.size());
|
||||
req.append(b->orgbytes.begin(), b->orgbytes.size());
|
||||
req.pack_dd(b->type);
|
||||
req.pack_dd(b->pid);
|
||||
req.pack_dd(b->tid);
|
||||
}
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
int ret_nbpts = mmdsr.unpack_dd();
|
||||
if ( nbpts != NULL )
|
||||
*nbpts = ret_nbpts;
|
||||
bend = ubpts + nadd;
|
||||
for ( b=ubpts; b != bend; b++ )
|
||||
{
|
||||
if ( b->code == BPT_OK )
|
||||
{
|
||||
b->code = mmdsr.unpack_db();
|
||||
if ( b->code == BPT_OK && b->type == BPT_SOFT )
|
||||
{
|
||||
uchar len = mmdsr.unpack_db();
|
||||
b->orgbytes.resize(len);
|
||||
mmdsr.unpack_obj(b->orgbytes.begin(), len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bend += ndel;
|
||||
for ( ; b != bend; b++ )
|
||||
b->code = mmdsr.unpack_db();
|
||||
|
||||
if ( errbuf != NULL && drc != DRC_NONE )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_thread_get_sreg_base(ea_t *ea, thid_t tid, int sreg_value, qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_GET_SREG_BASE);
|
||||
req.pack_dd(tid);
|
||||
req.pack_dd(sreg_value);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
if ( drc == DRC_OK )
|
||||
*ea = mmdsr.unpack_ea64();
|
||||
else if ( errbuf != NULL )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rpc_debmod_t::dbg_set_exception_info(const exception_info_t *table, int qty)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_SET_EXCEPTION_INFO);
|
||||
req.pack_dd(qty);
|
||||
append_exception_info(req, table, qty);
|
||||
|
||||
qfree(send_request_and_receive_reply(req));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi rpc_debmod_t::dbg_open_file(const char *file, uint64 *fsize, bool readonly)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_OPEN_FILE);
|
||||
req.pack_str(file);
|
||||
req.pack_dd(readonly);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return -1;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
int fn = mmdsr.unpack_dd();
|
||||
if ( fn != -1 )
|
||||
{
|
||||
if ( fsize != NULL && readonly )
|
||||
*fsize = mmdsr.unpack_dq();
|
||||
}
|
||||
else
|
||||
{
|
||||
qerrcode(mmdsr.unpack_dd());
|
||||
}
|
||||
qfree(rp);
|
||||
return fn;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rpc_debmod_t::dbg_close_file(int fn)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_CLOSE_FILE);
|
||||
req.pack_dd(fn);
|
||||
|
||||
qfree(send_request_and_receive_reply(req));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi rpc_debmod_t::dbg_read_file(int fn, qoff64_t off, void *buf, size_t size)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_READ_FILE);
|
||||
req.pack_dd(fn);
|
||||
req.pack_dq(off);
|
||||
req.pack_dd((uint32)size);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return -1;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
int32 rsize = mmdsr.unpack_dd();
|
||||
if ( size != rsize )
|
||||
qerrcode(mmdsr.unpack_dd());
|
||||
|
||||
if ( rsize > 0 )
|
||||
{
|
||||
QASSERT(1204, rsize <= size);
|
||||
mmdsr.unpack_obj(buf, rsize);
|
||||
}
|
||||
qfree(rp);
|
||||
return rsize;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi rpc_debmod_t::dbg_write_file(int fn, qoff64_t off, const void *buf, size_t size)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_WRITE_FILE);
|
||||
req.pack_dd(fn);
|
||||
req.pack_dq(off);
|
||||
req.pack_buf(buf, size);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return -1;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
int32 rsize = mmdsr.unpack_dd();
|
||||
if ( size != rsize )
|
||||
qerrcode(mmdsr.unpack_dd());
|
||||
|
||||
qfree(rp);
|
||||
return rsize;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi rpc_debmod_t::dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_ISOK_BPT);
|
||||
req.pack_dd(type);
|
||||
req.pack_ea64(ea);
|
||||
req.pack_dd(len+1);
|
||||
|
||||
return send_request_get_long_result(req);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rpc_debmod_t::dbg_set_debugging(bool _debug_debugger)
|
||||
{
|
||||
debug_debugger = _debug_debugger;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_init(uint32_t *_flags2, qstring *errbuf)
|
||||
{
|
||||
has_pending_event = false;
|
||||
poll_debug_events = false;
|
||||
|
||||
bytevec_t req = prepare_rpc_packet(RPC_INIT);
|
||||
req.pack_dd(debugger.flags);
|
||||
req.pack_dd(debug_debugger);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == nullptr )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
uint32_t flags2 = mmdsr.unpack_dd();
|
||||
if ( _flags2 != nullptr )
|
||||
*_flags2 = flags2;
|
||||
if ( drc != DRC_OK && errbuf != nullptr )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rpc_debmod_t::dbg_term(void)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_TERM);
|
||||
|
||||
qfree(send_request_and_receive_reply(req));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_get_processes(procinfo_vec_t *procs, qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_GET_PROCESSES);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
|
||||
procs->qclear();
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
if ( drc == DRC_OK )
|
||||
extract_process_info_vec(procs, mmdsr);
|
||||
else if ( errbuf != NULL )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_detach_process(void)
|
||||
{
|
||||
return get_drc(RPC_DETACH_PROCESS);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_start_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
qstring *errbuf)
|
||||
{
|
||||
if ( inf_test_mode() )
|
||||
flags |= DBG_HIDE_WINDOW;
|
||||
bytevec_t req = prepare_rpc_packet(RPC_START_PROCESS);
|
||||
req.pack_str(path);
|
||||
req.pack_str(args);
|
||||
req.pack_str(startdir);
|
||||
req.pack_dd(flags);
|
||||
req.pack_str(input_path);
|
||||
req.pack_dd(input_file_crc32);
|
||||
|
||||
return process_start_or_attach(req, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
gdecode_t idaapi rpc_debmod_t::dbg_get_debug_event(debug_event_t *event, int timeout_ms)
|
||||
{
|
||||
if ( has_pending_event )
|
||||
{
|
||||
verbev(("get_debug_event => has pending event, returning it\n"));
|
||||
*event = pending_event;
|
||||
has_pending_event = false;
|
||||
poll_debug_events = false;
|
||||
return GDE_ONE_EVENT;
|
||||
}
|
||||
|
||||
gdecode_t result = GDE_NO_EVENT;
|
||||
if ( poll_debug_events )
|
||||
{
|
||||
// do we have something waiting?
|
||||
if ( irs_ready(client_irs, timeout_ms) > 0 )
|
||||
{
|
||||
verbev(("get_debug_event => remote has a packet for us\n"));
|
||||
// get the packet - it can RPC_EVENT or RPC_MSG/RPC_WARNING/RPC_ERROR
|
||||
bytevec_t empty;
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(empty, PREQ_GET_EVENT);
|
||||
verbev(("get_debug_event => processed remote event, has=%d\n", has_pending_event));
|
||||
if ( rp != NULL )
|
||||
{
|
||||
warning("rpc: event protocol error (rp=%p has_event=%d)", rp, has_pending_event);
|
||||
return GDE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
verbev(("get_debug_event => first time, send GET_DEBUG_EVENT\n"));
|
||||
bytevec_t req = prepare_rpc_packet(RPC_GET_DEBUG_EVENT);
|
||||
req.pack_dd(timeout_ms);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return GDE_ERROR;
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
|
||||
result = gdecode_t(mmdsr.unpack_dd());
|
||||
if ( result >= GDE_ONE_EVENT )
|
||||
extract_debug_event(event, mmdsr);
|
||||
else
|
||||
poll_debug_events = true;
|
||||
verbev(("get_debug_event => remote said %d, poll=%d now\n", result, poll_debug_events));
|
||||
qfree(rp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_attach_process(pid_t _pid, int event_id, int flags, qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_ATTACH_PROCESS);
|
||||
req.pack_dd(_pid);
|
||||
req.pack_dd(event_id);
|
||||
req.pack_dd(flags);
|
||||
return process_start_or_attach(req, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_prepare_to_pause_process(qstring *errbuf)
|
||||
{
|
||||
return get_drc(RPC_PREPARE_TO_PAUSE_PROCESS, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_exit_process(qstring *errbuf)
|
||||
{
|
||||
return get_drc(RPC_EXIT_PROCESS, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_continue_after_event(const debug_event_t *event)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_CONTINUE_AFTER_EVENT);
|
||||
append_debug_event(req, event);
|
||||
|
||||
return send_request_get_drc_result(req, NULL);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rpc_debmod_t::dbg_stopped_at_debug_event(
|
||||
import_infos_t *,
|
||||
bool dlls_added,
|
||||
thread_name_vec_t *thr_names)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_STOPPED_AT_DEBUG_EVENT);
|
||||
req.pack_db(dlls_added);
|
||||
bool ask_thr_names = thr_names != NULL;
|
||||
req.pack_db(ask_thr_names);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return;
|
||||
|
||||
if ( ask_thr_names )
|
||||
{
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
uint32 n = mmdsr.unpack_dd();
|
||||
thr_names->resize(n);
|
||||
for ( uint32 i=0; i < n; ++i )
|
||||
{
|
||||
thread_name_t &tn = (*thr_names)[i];
|
||||
tn.tid = mmdsr.unpack_dd();
|
||||
tn.name = mmdsr.unpack_str();
|
||||
}
|
||||
}
|
||||
|
||||
qfree(rp);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_thread_suspend(thid_t tid)
|
||||
{
|
||||
return get_drc_int(RPC_TH_SUSPEND, tid);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_thread_continue(thid_t tid)
|
||||
{
|
||||
return get_drc_int(RPC_TH_CONTINUE, tid);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_set_resume_mode(thid_t tid, resume_mode_t resmod)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_SET_RESUME_MODE);
|
||||
req.pack_dd(tid);
|
||||
req.pack_dd(resmod);
|
||||
|
||||
return send_request_get_drc_result(req, NULL);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// prepare bitmap of registers belonging to the specified classes
|
||||
// return size of the bitmap in bits (always the total number of registers)
|
||||
static int calc_regmap(bytevec_t *regmap, int clsmask)
|
||||
{
|
||||
int nregs = debugger.nregs;
|
||||
regmap->resize((nregs+7)/8, 0);
|
||||
for ( int i=0; i < nregs; i++ )
|
||||
if ( (debugger.regs(i).register_class & clsmask) != 0 )
|
||||
regmap->set_bit(i);
|
||||
return nregs;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_read_registers(
|
||||
thid_t tid,
|
||||
int clsmask,
|
||||
regval_t *values,
|
||||
qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_READ_REGS);
|
||||
req.pack_dd(tid);
|
||||
req.pack_dd(clsmask);
|
||||
// append additional information about the class structure
|
||||
bytevec_t regmap;
|
||||
int n_regs = calc_regmap(®map, clsmask);
|
||||
req.pack_dd(n_regs);
|
||||
req.append(regmap.begin(), regmap.size());
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
if ( drc == DRC_OK )
|
||||
unpack_regvals(values, n_regs, regmap.begin(), mmdsr);
|
||||
else if ( errbuf != NULL )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_write_register(
|
||||
thid_t tid,
|
||||
int reg_idx,
|
||||
const regval_t *value,
|
||||
qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_WRITE_REG);
|
||||
req.pack_dd(tid);
|
||||
req.pack_dd(reg_idx);
|
||||
append_regvals(req, value, 1, NULL);
|
||||
|
||||
return send_request_get_drc_result(req, errbuf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_get_memory_info(meminfo_vec_t &areas, qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_GET_MEMORY_INFO);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = drc_t(mmdsr.unpack_dd() + DRC_IDBSEG);
|
||||
if ( drc > DRC_NONE )
|
||||
{
|
||||
int n = mmdsr.unpack_dd();
|
||||
areas.resize(n);
|
||||
for ( int i=0; i < n; i++ )
|
||||
extract_memory_info(&areas[i], mmdsr);
|
||||
}
|
||||
else if ( errbuf != NULL )
|
||||
{
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
}
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi rpc_debmod_t::dbg_get_scattered_image(scattered_image_t &si, ea_t base)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_GET_SCATTERED_IMAGE);
|
||||
req.pack_ea64(base);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return false;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
int result = mmdsr.unpack_dd() - 2;
|
||||
if ( result > 0 )
|
||||
{
|
||||
int n = mmdsr.unpack_dd();
|
||||
si.resize(n);
|
||||
for ( int i=0; i < n; i++ )
|
||||
extract_scattered_segm(&si[i], mmdsr);
|
||||
}
|
||||
qfree(rp);
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi rpc_debmod_t::dbg_get_image_uuid(bytevec_t *uuid, ea_t base)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_GET_IMAGE_UUID);
|
||||
req.pack_ea64(base);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return false;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
bool result = mmdsr.unpack_dd() != 0;
|
||||
if ( result )
|
||||
{
|
||||
int n = mmdsr.unpack_dd();
|
||||
uuid->append(mmdsr.ptr, n);
|
||||
}
|
||||
qfree(rp);
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ea_t idaapi rpc_debmod_t::dbg_get_segm_start(ea_t base, const qstring &segname)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_GET_SEGM_START);
|
||||
req.pack_ea64(base);
|
||||
req.pack_str(segname.c_str());
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return false;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
ea_t result = mmdsr.unpack_ea64();
|
||||
qfree(rp);
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi rpc_debmod_t::dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_READ_MEMORY);
|
||||
req.pack_ea64(ea);
|
||||
req.pack_dd((uint32)size);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return -1;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
int result = mmdsr.unpack_dd();
|
||||
if ( result > 0 )
|
||||
{
|
||||
QASSERT(1205, result <= size);
|
||||
mmdsr.unpack_obj(buffer, result);
|
||||
}
|
||||
else if ( errbuf != NULL )
|
||||
{
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
}
|
||||
qfree(rp);
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi rpc_debmod_t::dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_WRITE_MEMORY);
|
||||
req.pack_ea64(ea);
|
||||
req.pack_buf(buffer, size);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return -1;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
int result = mmdsr.unpack_dd();
|
||||
if ( errbuf != NULL && result <= 0 )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
qfree(rp);
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_update_call_stack(thid_t tid, call_stack_t *trace)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_UPDATE_CALL_STACK);
|
||||
req.pack_dd(tid);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
if ( drc == DRC_OK )
|
||||
extract_call_stack(trace, mmdsr);
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ea_t idaapi rpc_debmod_t::dbg_appcall(
|
||||
ea_t func_ea,
|
||||
thid_t tid,
|
||||
int stkarg_nbytes,
|
||||
const struct regobjs_t *regargs,
|
||||
struct relobj_t *stkargs,
|
||||
struct regobjs_t *retregs,
|
||||
qstring *errbuf,
|
||||
debug_event_t *event,
|
||||
int flags)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_APPCALL);
|
||||
req.pack_ea64(func_ea);
|
||||
req.pack_dd(tid);
|
||||
req.pack_dd(stkarg_nbytes);
|
||||
req.pack_dd(flags);
|
||||
regobjs_t *rr = (flags & APPCALL_MANUAL) == 0 ? retregs : NULL;
|
||||
append_appcall(req, *regargs, *stkargs, rr);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return BADADDR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
ea_t sp = mmdsr.unpack_ea64();
|
||||
if ( sp == BADADDR )
|
||||
{
|
||||
if ( (flags & APPCALL_DEBEV) != 0 )
|
||||
extract_debug_event(event, mmdsr);
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
}
|
||||
else if ( (flags & APPCALL_MANUAL) == 0 )
|
||||
{
|
||||
if ( retregs != NULL )
|
||||
extract_regobjs(retregs, true, mmdsr);
|
||||
}
|
||||
qfree(rp);
|
||||
return sp;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_cleanup_appcall(thid_t tid)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_CLEANUP_APPCALL);
|
||||
req.pack_dd(tid);
|
||||
return send_request_get_drc_result(req, NULL);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi rpc_debmod_t::dbg_rexec(const char *cmdline)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_REXEC);
|
||||
req.pack_str(cmdline);
|
||||
return send_request_get_long_result(req);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t idaapi rpc_debmod_t::dbg_bin_search(
|
||||
ea_t *pea,
|
||||
ea_t start_ea,
|
||||
ea_t end_ea,
|
||||
const compiled_binpat_vec_t &ptns,
|
||||
int srch_flags,
|
||||
qstring *errbuf)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_BIN_SEARCH);
|
||||
req.pack_ea64(start_ea);
|
||||
req.pack_ea64(end_ea);
|
||||
// compiled_binpat_vec_t
|
||||
int sz = ptns.size();
|
||||
req.pack_dd(sz);
|
||||
for ( compiled_binpat_vec_t::const_iterator p=ptns.begin();
|
||||
p != ptns.end();
|
||||
++p )
|
||||
{ // compiled_binpat_t
|
||||
sz = p->bytes.size();
|
||||
req.pack_buf(p->bytes.begin(), sz);
|
||||
sz = p->mask.size();
|
||||
req.pack_buf(p->mask.begin(), sz);
|
||||
sz = p->strlits.size();
|
||||
req.pack_dd(sz);
|
||||
for ( int i=0; i < sz; ++i )
|
||||
{
|
||||
req.pack_ea64(p->strlits[i].start_ea);
|
||||
req.pack_ea64(p->strlits[i].end_ea);
|
||||
}
|
||||
req.pack_dd(p->encidx);
|
||||
}
|
||||
req.pack_dd(srch_flags);
|
||||
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
if ( drc == DRC_OK )
|
||||
{
|
||||
if ( pea != NULL )
|
||||
*pea = mmdsr.unpack_ea64();
|
||||
}
|
||||
else if ( drc != DRC_FAILED ) // DRC_FAILED means not found
|
||||
{
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
}
|
||||
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
drc_t rpc_debmod_t::close_remote()
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(RPC_OK);
|
||||
send_data(req);
|
||||
irs_term(&client_irs);
|
||||
network_error = false;
|
||||
return DRC_OK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi rpc_debmod_t::get_system_specific_errno(void) const
|
||||
{
|
||||
return irs_get_error(client_irs);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
drc_t rpc_debmod_t::process_start_or_attach(bytevec_t &req, qstring *errbuf)
|
||||
{
|
||||
rpc_packet_t *rp = send_request_and_receive_reply(req);
|
||||
if ( rp == NULL )
|
||||
return DRC_NETERR;
|
||||
|
||||
memory_deserializer_t mmdsr(rp+1, rp->length);
|
||||
drc_t drc = unpack_drc(mmdsr);
|
||||
if ( drc > DRC_NONE )
|
||||
{
|
||||
extract_debapp_attrs(&debapp_attrs, mmdsr);
|
||||
extract_dynamic_register_set(&idaregs, mmdsr);
|
||||
}
|
||||
else if ( errbuf != NULL )
|
||||
{
|
||||
*errbuf = mmdsr.unpack_str();
|
||||
}
|
||||
qfree(rp);
|
||||
return drc;
|
||||
}
|
||||
118
idasdk75/dbg/rpc_debmod.h
Normal file
118
idasdk75/dbg/rpc_debmod.h
Normal file
@@ -0,0 +1,118 @@
|
||||
#ifndef __RPC_DEBUGGER_MODULE__
|
||||
#define __RPC_DEBUGGER_MODULE__
|
||||
|
||||
#include "debmod.h"
|
||||
#include "dbg_rpc_client.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
class rpc_debmod_t
|
||||
: public debmod_t,
|
||||
public dbg_rpc_client_t
|
||||
{
|
||||
drc_t process_start_or_attach(bytevec_t &req, qstring *errbuf);
|
||||
|
||||
public:
|
||||
rpc_debmod_t(const char *default_platform = NULL);
|
||||
virtual bool idaapi open_remote(const char *hostname, int port_number, const char *password, qstring *errbuf) newapi;
|
||||
drc_t close_remote();
|
||||
|
||||
int send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize)
|
||||
{
|
||||
return rpc_engine_t::send_ioctl(fn, buf, size, poutbuf, poutsize);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline int getint(ushort code)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet((uchar)code);
|
||||
return send_request_get_long_result(req);
|
||||
}
|
||||
drc_t get_drc_int(uchar code, int x)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet(code);
|
||||
req.pack_dd(x);
|
||||
return send_request_get_drc_result(req, NULL);
|
||||
}
|
||||
inline drc_t get_drc(ushort code, qstring *errbuf=NULL)
|
||||
{
|
||||
bytevec_t req = prepare_rpc_packet((uchar)code);
|
||||
return send_request_get_drc_result(req, errbuf);
|
||||
}
|
||||
|
||||
//
|
||||
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
|
||||
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
|
||||
virtual void idaapi dbg_term(void) override;
|
||||
virtual drc_t idaapi dbg_get_processes(procinfo_vec_t *procs, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_detach_process(void) override;
|
||||
virtual drc_t idaapi dbg_start_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
qstring *errbuf) override;
|
||||
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
|
||||
virtual drc_t idaapi dbg_attach_process(pid_t process_id, int event_id, int flags, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
|
||||
virtual void idaapi dbg_set_exception_info(const exception_info_t *info, int qty) override;
|
||||
virtual void idaapi dbg_stopped_at_debug_event(import_infos_t *infos, bool dlls_added, thread_name_vec_t *thr_names) override;
|
||||
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
|
||||
virtual drc_t idaapi dbg_read_registers(
|
||||
thid_t thread_id,
|
||||
int clsmask,
|
||||
regval_t *values,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_write_register(
|
||||
thid_t thread_id,
|
||||
int reg_idx,
|
||||
const regval_t *value,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &areas, qstring *errbuf) override;
|
||||
virtual int idaapi dbg_get_scattered_image(scattered_image_t &si, ea_t base) override;
|
||||
virtual bool idaapi dbg_get_image_uuid(bytevec_t *uuid, ea_t base) override;
|
||||
virtual ea_t idaapi dbg_get_segm_start(ea_t base, const qstring &segname) override;
|
||||
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) override;
|
||||
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
|
||||
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
|
||||
virtual drc_t idaapi dbg_update_bpts(int *nbpts, update_bpt_info_t *bpts, int nadd, int ndel, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_update_lowcnds(int *nupdated, const lowcnd_t *lowcnds, int nlowcnds, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf) override;
|
||||
virtual int idaapi dbg_open_file(const char *file, uint64 *fsize, bool readonly) override;
|
||||
virtual void idaapi dbg_close_file(int fn) override;
|
||||
virtual ssize_t idaapi dbg_read_file(int fn, qoff64_t off, void *buf, size_t size) override;
|
||||
virtual ssize_t idaapi dbg_write_file(int fn, qoff64_t off, const void *buf, size_t size) override;
|
||||
virtual int idaapi handle_ioctl(int fn, const void *buf, size_t size, void **outbuf, ssize_t *outsize) override;
|
||||
virtual int idaapi get_system_specific_errno(void) const override;
|
||||
virtual drc_t idaapi dbg_update_call_stack(thid_t, call_stack_t *) override;
|
||||
virtual ea_t idaapi dbg_appcall(
|
||||
ea_t func_ea,
|
||||
thid_t tid,
|
||||
int stkarg_nbytes,
|
||||
const struct regobjs_t *regargs,
|
||||
struct relobj_t *stkargs,
|
||||
struct regobjs_t *retregs,
|
||||
qstring *errbuf,
|
||||
debug_event_t *event,
|
||||
int flags) override;
|
||||
virtual drc_t idaapi dbg_cleanup_appcall(thid_t tid) override;
|
||||
virtual int get_regidx(const char *, int *) override { INTERR(30116); }
|
||||
virtual int idaapi dbg_rexec(const char *cmdline) override;
|
||||
virtual drc_t idaapi dbg_bin_search(
|
||||
ea_t *ea,
|
||||
ea_t start_ea,
|
||||
ea_t end_ea,
|
||||
const compiled_binpat_vec_t &ptns,
|
||||
int srch_flags,
|
||||
qstring *errbuf) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
224
idasdk75/dbg/server.cpp
Normal file
224
idasdk75/dbg/server.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
IDA remote debugger server
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
// We use the deprecated inet_ntoa() function for Windows XP compatibility.
|
||||
//lint -e750 local macro '' not referenced
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <expr.hpp>
|
||||
|
||||
#include "server.h"
|
||||
|
||||
// Provide dummy versions for tinfo copy/clear. Debugger servers do not use them
|
||||
#if !defined(__NT__)
|
||||
void ida_export copy_tinfo_t(tinfo_t *, const tinfo_t &) {}
|
||||
void ida_export clear_tinfo_t(tinfo_t *) {}
|
||||
#endif
|
||||
|
||||
// We don't have a kernel. Provide envvar-based debug file directory retrieval.
|
||||
#if defined(__LINUX__)
|
||||
static bool _elf_debug_file_directory_resolved = false;
|
||||
static qstring _elf_debug_file_directory;
|
||||
idaman const char *ida_export get_elf_debug_file_directory()
|
||||
{
|
||||
if ( !_elf_debug_file_directory_resolved )
|
||||
{
|
||||
if ( !qgetenv("DEBUG_FILE_DIRECTORY", &_elf_debug_file_directory) )
|
||||
qgetenv("ELF_DEBUG_FILE_DIRECTORY", &_elf_debug_file_directory);
|
||||
if ( _elf_debug_file_directory.empty() )
|
||||
_elf_debug_file_directory = "/usr/lib/debug";
|
||||
_elf_debug_file_directory_resolved = true;
|
||||
}
|
||||
return _elf_debug_file_directory.c_str();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#ifdef TESTABLE_BUILD
|
||||
static std::map<int,qstring> _pid_elf_debug_file_directories;
|
||||
void set_elf_debug_file_directory_for_pid(int pid, const char *path)
|
||||
{
|
||||
_pid_elf_debug_file_directories[pid] = path;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
const char *get_elf_debug_file_directory_for_pid(int pid)
|
||||
{
|
||||
const char *found = NULL;
|
||||
std::map<int,qstring>::const_iterator it = _pid_elf_debug_file_directories.find(pid);
|
||||
if ( it != _pid_elf_debug_file_directories.end() )
|
||||
found = it->second.begin();
|
||||
else
|
||||
found = get_elf_debug_file_directory();
|
||||
return found;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//lint -esym(714, dump_udt) not referenced
|
||||
void dump_udt(const char *, const struct udt_type_data_t &) {}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// SERVER GLOBAL VARIABLES
|
||||
#ifdef __SINGLE_THREADED_SERVER__
|
||||
dbgsrv_dispatcher_t dispatcher(false);
|
||||
|
||||
static bool init_lock(void) { return true; }
|
||||
bool lock_begin(void) { return true; }
|
||||
bool lock_end(void) { return true; }
|
||||
#else
|
||||
dbgsrv_dispatcher_t dispatcher(true);
|
||||
|
||||
static qmutex_t g_mutex = NULL;
|
||||
static bool init_lock(void) { g_mutex = qmutex_create(); return g_mutex != NULL; }
|
||||
bool lock_begin(void) { return qmutex_lock(g_mutex); }
|
||||
bool lock_end(void) { return qmutex_unlock(g_mutex); }
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
dbg_rpc_handler_t *g_global_server = NULL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// perform an action (func) on all debuggers
|
||||
int for_all_debuggers(debmod_visitor_t &v)
|
||||
{
|
||||
int code = 0;
|
||||
dispatcher.clients_list->lock();
|
||||
{
|
||||
client_handlers_list_t::storage_t::iterator it;
|
||||
for ( it = dispatcher.clients_list->storage.begin();
|
||||
it != dispatcher.clients_list->storage.end();
|
||||
++it )
|
||||
{
|
||||
dbg_rpc_handler_t *h = (dbg_rpc_handler_t *) it->first;
|
||||
code = v.visit(h->get_debugger_instance());
|
||||
if ( code != 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
dispatcher.clients_list->unlock();
|
||||
return code;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
dbgsrv_dispatcher_t::dbgsrv_dispatcher_t(bool multi_threaded)
|
||||
: base_dispatcher_t(multi_threaded),
|
||||
broken_conns_supported(false),
|
||||
on_broken_conn(BCH_DEFAULT)
|
||||
{
|
||||
port_number = DEBUGGER_PORT_NUMBER;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void dbgsrv_dispatcher_t::collect_cliopts(cliopts_t *out)
|
||||
{
|
||||
struct ida_local ns_t
|
||||
{
|
||||
static void _set_dpassword(const char *value, void *ud)
|
||||
{
|
||||
((dbgsrv_dispatcher_t *) ud)->server_password = value;
|
||||
}
|
||||
static void _set_broken_connections_keep_debmod(const char *, void *ud)
|
||||
{
|
||||
((dbgsrv_dispatcher_t *) ud)->on_broken_conn = BCH_KEEP_DEBMOD;
|
||||
}
|
||||
static void _set_closing_session_kill_debuggee(const char *, void *ud)
|
||||
{
|
||||
((dbgsrv_dispatcher_t *) ud)->on_broken_conn = BCH_KILL_PROCESS;
|
||||
}
|
||||
};
|
||||
|
||||
static const cliopt_t cliopts[] =
|
||||
{
|
||||
{ 'P', "password", "Password", ns_t::_set_dpassword, 1 },
|
||||
};
|
||||
// the following options are valid only if broken connections are supported
|
||||
static const cliopt_t bc_cliopts[] =
|
||||
{
|
||||
{
|
||||
'k',
|
||||
"on-broken-connection-keep-session",
|
||||
"Keep debugger session alive when connection breaks",
|
||||
ns_t::_set_broken_connections_keep_debmod,
|
||||
0,
|
||||
},
|
||||
{
|
||||
'K',
|
||||
"on-stop-kill-process",
|
||||
"Kill debuggee when closing session",
|
||||
ns_t::_set_closing_session_kill_debuggee,
|
||||
0,
|
||||
},
|
||||
};
|
||||
|
||||
base_dispatcher_t::collect_cliopts(out);
|
||||
for ( size_t i = 0; i < qnumber(cliopts); ++i )
|
||||
out->push_back(cliopts[i]);
|
||||
|
||||
if ( broken_conns_supported )
|
||||
for ( size_t i = 0; i < qnumber(bc_cliopts); ++i )
|
||||
out->push_back(bc_cliopts[i]);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
client_handler_t *dbgsrv_dispatcher_t::new_client_handler(idarpc_stream_t *_irs)
|
||||
{
|
||||
dbg_rpc_handler_t *h = new dbg_rpc_handler_t(_irs, this);
|
||||
h->verbose = verbose;
|
||||
void *params = NULL;
|
||||
#if defined(__LINUX__) && defined(TESTABLE_BUILD)
|
||||
params = (void *) get_elf_debug_file_directory_for_pid; //lint !e611 cast between pointer to function type '' and pointer to object type 'void *'
|
||||
#endif
|
||||
h->set_debugger_instance(create_debug_session(params));
|
||||
g_global_server = h;
|
||||
return h;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void dbgsrv_dispatcher_t::shutdown_gracefully(int signum)
|
||||
{
|
||||
base_dispatcher_t::shutdown_gracefully(signum);
|
||||
term_subsystem();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// debugger remote server - TCP/IP mode
|
||||
int NT_CDECL main(int argc, const char *argv[])
|
||||
{
|
||||
#ifdef ENABLE_LOWCNDS
|
||||
init_idc();
|
||||
#endif
|
||||
|
||||
// call the debugger module to initialize its subsystem once
|
||||
if ( !init_lock() || !init_subsystem() )
|
||||
{
|
||||
lprintf("Could not initialize subsystem!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
qstring password;
|
||||
if ( qgetenv("IDA_DBGSRV_PASSWD", &password) )
|
||||
dispatcher.server_password = password;
|
||||
|
||||
int ida_major = IDA_SDK_VERSION / 100;
|
||||
#if (IDA_SDK_VERSION % 10) == 0
|
||||
int ida_minor = (IDA_SDK_VERSION % 100)/10; //740 -> 4
|
||||
#else
|
||||
int ida_minor = IDA_SDK_VERSION % 100; //741 -> 41
|
||||
#endif
|
||||
|
||||
lprintf("IDA " SYSTEM SYSBITS " remote debug server(" __SERVER_TYPE__ ") "
|
||||
"v%d.%d.%d. Hex-Rays (c) 2004-2020\n",
|
||||
ida_major, ida_minor, IDD_INTERFACE_VERSION);
|
||||
|
||||
dispatcher.broken_conns_supported = debmod_t::reuse_broken_connections;
|
||||
cliopts_t cliopts(lprintf);
|
||||
dispatcher.collect_cliopts(&cliopts);
|
||||
cliopts.apply(argc, argv, &dispatcher);
|
||||
dispatcher.install_signal_handlers();
|
||||
dispatcher.dispatch();
|
||||
}
|
||||
58
idasdk75/dbg/server.h
Normal file
58
idasdk75/dbg/server.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include <network.hpp>
|
||||
|
||||
#ifdef __NT__
|
||||
//# ifndef SIGHUP
|
||||
//# define SIGHUP 1
|
||||
//# endif
|
||||
# define DEBUGGER_ID DEBUGGER_ID_X86_IA32_WIN32_USER
|
||||
#else // not NT, i.e. UNIX
|
||||
# if defined(__LINUX__)
|
||||
# if defined(__ARM__)
|
||||
# define DEBUGGER_ID DEBUGGER_ID_ARM_LINUX_USER
|
||||
# else
|
||||
# define DEBUGGER_ID DEBUGGER_ID_X86_IA32_LINUX_USER
|
||||
# endif
|
||||
# elif defined(__MAC__)
|
||||
# define DEBUGGER_ID DEBUGGER_ID_X86_IA32_MACOSX_USER
|
||||
# endif
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
#endif // !__NT__
|
||||
|
||||
enum broken_conn_hndl_t
|
||||
{
|
||||
BCH_DEFAULT,
|
||||
BCH_KEEP_DEBMOD,
|
||||
BCH_KILL_PROCESS,
|
||||
};
|
||||
|
||||
struct dbgsrv_dispatcher_t : public base_dispatcher_t
|
||||
{
|
||||
qstring server_password;
|
||||
bool broken_conns_supported;
|
||||
broken_conn_hndl_t on_broken_conn;
|
||||
|
||||
dbgsrv_dispatcher_t(bool multi_threaded);
|
||||
|
||||
virtual void collect_cliopts(cliopts_t *out) override;
|
||||
virtual client_handler_t *new_client_handler(idarpc_stream_t *irs) override;
|
||||
|
||||
virtual void shutdown_gracefully(int signum) override;
|
||||
};
|
||||
|
||||
#include "debmod.h"
|
||||
#include "dbg_rpc_hlp.h"
|
||||
#include "dbg_rpc_handler.h"
|
||||
|
||||
// // sizeof(ea_t)==8 and sizeof(size_t)==4 servers cannot be used to debug 64-bit
|
||||
// // applications. but to debug 32-bit applications, simple 32-bit servers
|
||||
// // are enough and can work with both 32-bit and 64-bit versions of ida.
|
||||
// // so, there is no need to build sizeof(ea_t)==8 and sizeof(size_t)==4 servers
|
||||
// #if defined(__EA64__) == defined(__X86__)
|
||||
// #error "Mixed mode servers do not make sense, they should not be compiled"
|
||||
// #endif
|
||||
|
||||
#endif
|
||||
17
idasdk75/dbg/server.mak
Normal file
17
idasdk75/dbg/server.mak
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
SERVER_LIBS += $(L)dbg_server$(A)
|
||||
SERVER_LIBS += $(L)dbg_rpc$(A)
|
||||
SERVER_LIBS += $(L)dbg_proc$(A)
|
||||
SERVER_LIBS += $(L)network$(A)
|
||||
SERVER_LIBS += $(DUMB)
|
||||
SERVER_LIBS += $(L)unicode$(A)
|
||||
SERVER_LIBS += $(L)pro$(A)
|
||||
SERVER_LIBS += $(L)compress$(A)
|
||||
|
||||
server: $(SERVERS)
|
||||
$(SERVERS): LDFLAGS += $(SERVER_LDFLAGS)
|
||||
$(SERVERS): STDLIBS += $(SERVER_STDLIBS)
|
||||
$(SERVERS): $(SERVER_OBJS) $(SERVER_LIBS)
|
||||
$(call link_exe, $(SERVER_OBJS), $(SERVER_LIBS))
|
||||
$(CHECKSYMS_CMD)
|
||||
$(SERVER_POSTACTION)
|
||||
174
idasdk75/dbg/win32/makefile
Normal file
174
idasdk75/dbg/win32/makefile
Normal file
@@ -0,0 +1,174 @@
|
||||
include ../../allmake.mak
|
||||
|
||||
GOALS-$(BUILD_IDA) += modules # target in $(IDA)module.mak
|
||||
GOALS-$(BUILD_DBGSRV) += server # target in $(IDA)dbg/server.mak
|
||||
.PHONY: $(GOALS-1)
|
||||
all: $(GOALS-1)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
ifdef __NT__
|
||||
ifndef __X86__
|
||||
SERVER = win64_remote$(B)
|
||||
else
|
||||
SERVER = win32_remote$(B)
|
||||
endif
|
||||
endif
|
||||
ifdef SERVER
|
||||
SERVERS += $(call server_exe,$(SERVER))
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
STUB = $(call module_dll,win32_stub)
|
||||
ifdef BUILD_IDA
|
||||
MODULES += $(STUB)
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
USER = $(call module_dll,win32_user)
|
||||
ifeq ($(and $(BUILD_IDA),$(__NT__)),1)
|
||||
MODULES += $(USER)
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# we explicitly added our module targets
|
||||
NO_DEFAULT_TARGETS = 1
|
||||
|
||||
# NOTE: all MODULES must be defined before including plugin.mak.
|
||||
include ../plugin.mak
|
||||
# NOTE: target-specific rules and dependencies that use variable
|
||||
# expansion to name the target (such as "$(MODULE): [...]") must
|
||||
# come after including plugin.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# select OBJS common to user plugin and debugger server
|
||||
BASE_OBJS-$(__NT__) += $(F)win32_debmod$(O)
|
||||
BASE_OBJS-$(__NT__) += $(F)win32_util$(O)
|
||||
BASE_OBJS-$(__NT__) += $(F)winbase_debmod$(O)
|
||||
BASE_OBJS += $(BASE_OBJS-1)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
SERVER_OBJS += $(F)win32_server$(O)
|
||||
SERVER_OBJS += $(F)tilfuncs$(O)
|
||||
SERVER_OBJS += $(BASE_OBJS)
|
||||
|
||||
SERVER_STDLIBS += ole32.lib
|
||||
SERVER_STDLIBS += oleaut32.lib
|
||||
|
||||
include ../server.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
STUB_OBJS += $(F)win32_stub$(O)
|
||||
STUB_OBJS += $(F)w32sehch$(O)
|
||||
$(STUB): MODULE_OBJS += $(STUB_OBJS)
|
||||
$(STUB): $(STUB_OBJS)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
USER_OBJS += $(F)win32_user$(O)
|
||||
USER_OBJS += $(F)w32sehch$(O)
|
||||
USER_OBJS += $(BASE_OBJS)
|
||||
$(USER): MODULE_OBJS += $(USER_OBJS)
|
||||
$(USER): $(USER_OBJS)
|
||||
$(USER): STDLIBS += user32.lib
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
include $(IDA)objdir.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)tilfuncs$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)diskio.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)ins/pc.hpp $(I)intel.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)network.hpp $(I)pro.h $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/pe/cor.h ../../ldr/pe/corerror.h \
|
||||
../../ldr/pe/corhdr.h ../../ldr/pe/mycor.h \
|
||||
../../ldr/pe/pe.h ../../plugins/pdb/common.cpp \
|
||||
../../plugins/pdb/cvconst.h ../../plugins/pdb/dbghelp.h \
|
||||
../../plugins/pdb/dia2.h ../../plugins/pdb/idaaccess.hpp \
|
||||
../../plugins/pdb/msdia.cpp ../../plugins/pdb/msdia.hpp \
|
||||
../../plugins/pdb/pdb.hpp \
|
||||
../../plugins/pdb/pdbaccess.hpp \
|
||||
../../plugins/pdb/pdbida.hpp \
|
||||
../../plugins/pdb/pdblocal.cpp \
|
||||
../../plugins/pdb/pdblocal.hpp \
|
||||
../../plugins/pdb/varser.hpp ../debmod.h tilfuncs.cpp \
|
||||
tilfuncs.hpp
|
||||
$(F)w32sehch$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idd.hpp $(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp w32sehch.cpp w32sehch.h
|
||||
$(F)win32_debmod$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)dbg.hpp $(I)diskio.hpp $(I)entry.hpp \
|
||||
$(I)err.h $(I)exehdr.h $(I)fixup.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \
|
||||
$(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)offset.hpp $(I)pro.h $(I)prodir.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
|
||||
$(I)xref.hpp ../../ldr/pe/../idaldr.h \
|
||||
../../ldr/pe/common.cpp ../../ldr/pe/common.h \
|
||||
../../ldr/pe/pe.h ../dbg_pe_hlp.cpp ../deb_pc.hpp \
|
||||
../debmod.h ../pc_debmod.h ../pc_regs.hpp \
|
||||
win32_debmod.cpp win32_debmod.h win32_debmod_impl.cpp \
|
||||
win32_rpc.h win32_undoc.h win32_util.hpp \
|
||||
winbase_debmod.h
|
||||
$(F)win32_server$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \
|
||||
$(I)idp.hpp $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/pe/cor.h ../../ldr/pe/corerror.h \
|
||||
../../ldr/pe/corhdr.h ../../ldr/pe/mycor.h \
|
||||
../../ldr/pe/pe.h ../../plugins/pdb/cvconst.h \
|
||||
../../plugins/pdb/dia2.h ../../plugins/pdb/idaaccess.hpp \
|
||||
../../plugins/pdb/msdia.hpp ../../plugins/pdb/pdb.hpp \
|
||||
../../plugins/pdb/pdbaccess.hpp \
|
||||
../../plugins/pdb/pdbida.hpp \
|
||||
../../plugins/pdb/pdblocal.hpp ../dbg_rpc_hlp.h \
|
||||
../deb_pc.hpp ../debmod.h ../pc_debmod.h ../pc_regs.hpp \
|
||||
tilfuncs.hpp win32_debmod.h win32_rpc.h win32_server.cpp \
|
||||
win32_util.hpp winbase_debmod.h
|
||||
$(F)win32_stub$(O): $(I)../ldr/pe/pe.h $(I)../plugins/pdb/pdb.hpp \
|
||||
$(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/pe/pe.h ../common_local_impl.cpp \
|
||||
../common_stub_impl.cpp ../dbg_rpc_client.h \
|
||||
../dbg_rpc_engine.h ../dbg_rpc_hlp.h ../deb_pc.hpp \
|
||||
../debmod.h ../pc_local_impl.cpp ../pc_regs.hpp \
|
||||
../rpc_debmod.h w32sehch.h win32_local_impl.cpp \
|
||||
win32_rpc.h win32_stub.cpp
|
||||
$(F)win32_user$(O): $(I)../ldr/pe/pe.h $(I)../plugins/pdb/pdb.hpp \
|
||||
$(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)err.h $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
../../ldr/pe/pe.h ../common_local_impl.cpp \
|
||||
../common_stub_impl.cpp ../dbg_rpc_hlp.h ../deb_pc.hpp \
|
||||
../debmod.h ../pc_debmod.h ../pc_local_impl.cpp \
|
||||
../pc_regs.hpp w32sehch.h win32_debmod.h \
|
||||
win32_local_impl.cpp win32_rpc.h win32_server_stub.cpp \
|
||||
win32_user.cpp win32_util.hpp winbase_debmod.h
|
||||
$(F)win32_util$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp $(I)netnode.hpp \
|
||||
$(I)network.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../deb_pc.hpp ../debmod.h \
|
||||
../pc_debmod.h ../pc_regs.hpp win32_util.cpp \
|
||||
win32_util.hpp winbase_debmod.h
|
||||
$(F)winbase_debmod$(O): $(I)bytes.hpp $(I)ida.hpp $(I)idd.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp $(I)nalt.hpp \
|
||||
$(I)netnode.hpp $(I)network.hpp $(I)pro.h $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)ua.hpp $(I)xref.hpp ../deb_pc.hpp \
|
||||
../debmod.h ../pc_debmod.h ../pc_regs.hpp win32_util.hpp \
|
||||
winbase_debmod.cpp winbase_debmod.h
|
||||
256
idasdk75/dbg/win32/w32sehch.cpp
Normal file
256
idasdk75/dbg/win32/w32sehch.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
#include <set>
|
||||
#include <pro.h>
|
||||
#include <name.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <dbg.hpp>
|
||||
#include <loader.hpp>
|
||||
#include "w32sehch.h"
|
||||
|
||||
static int req_id = -1;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// non-modal exception handler chooser
|
||||
struct x86seh_chooser_t : public chooser_t
|
||||
{
|
||||
protected:
|
||||
thid_t tid;
|
||||
qvector<uint32> list; //lint !e958 padding is required to align members
|
||||
qstring title_;
|
||||
|
||||
static const int widths_[];
|
||||
static const char *const header_[];
|
||||
enum { ICON = 144 };
|
||||
|
||||
public:
|
||||
// this object must be allocated using `new`
|
||||
x86seh_chooser_t(thid_t tid);
|
||||
virtual ~x86seh_chooser_t()
|
||||
{
|
||||
unhook_from_notification_point(
|
||||
HT_DBG,
|
||||
dbg_handler, const_cast<char *>(title));
|
||||
}
|
||||
ssize_t choose(uint32 addr = uint32(-1)) //lint !e1511 member hides non-virtual member
|
||||
{
|
||||
return ::choose(this, &addr);
|
||||
}
|
||||
|
||||
virtual const void *get_obj_id(size_t *len) const override
|
||||
{
|
||||
*len = sizeof(tid);
|
||||
return &tid;
|
||||
}
|
||||
|
||||
virtual size_t idaapi get_count() const override { return list.size(); }
|
||||
virtual void idaapi get_row(
|
||||
qstrvec_t *cols,
|
||||
int *icon_,
|
||||
chooser_item_attrs_t *attrs,
|
||||
size_t n) const override;
|
||||
virtual cbret_t idaapi enter(size_t n) override;
|
||||
|
||||
// calculate the location of the item,
|
||||
// `item_data` is a pointer to a 32-bit address
|
||||
virtual ssize_t idaapi get_item_index(const void *item_data) const override;
|
||||
virtual bool idaapi init() override;
|
||||
virtual cbret_t idaapi refresh(ssize_t n) override;
|
||||
|
||||
protected:
|
||||
static ssize_t idaapi dbg_handler(void *ud, int notif_code, va_list va);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
const int x86seh_chooser_t::widths_[] =
|
||||
{
|
||||
CHCOL_HEX | 10, // Address
|
||||
30, // Name
|
||||
};
|
||||
const char *const x86seh_chooser_t::header_[] =
|
||||
{
|
||||
"Address", // 0
|
||||
"Name", // 1
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
inline x86seh_chooser_t::x86seh_chooser_t(thid_t tid_)
|
||||
: chooser_t(CH_NOBTNS | CH_FORCE_DEFAULT | CH_CAN_REFRESH,
|
||||
qnumber(widths_), widths_, header_),
|
||||
tid(tid_),
|
||||
list()
|
||||
{
|
||||
title_.sprnt("[%04X] - Structured exception handlers list", tid);
|
||||
title = title_.c_str();
|
||||
CASSERT(qnumber(widths_) == qnumber(header_));
|
||||
icon = ICON;
|
||||
|
||||
hook_to_notification_point(
|
||||
HT_DBG,
|
||||
dbg_handler, const_cast<char *>(title));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void idaapi x86seh_chooser_t::get_row(
|
||||
qstrvec_t *cols_,
|
||||
int *,
|
||||
chooser_item_attrs_t *,
|
||||
size_t n) const
|
||||
{
|
||||
// assert: n < list.size()
|
||||
uint32 addr = list[n];
|
||||
|
||||
qstrvec_t &cols = *cols_;
|
||||
cols[0].sprnt("%08X", addr);
|
||||
get_nice_colored_name(&cols[1], addr, GNCN_NOCOLOR | GNCN_NOLABEL);
|
||||
CASSERT(qnumber(header_) == 2);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
chooser_t::cbret_t idaapi x86seh_chooser_t::enter(size_t n)
|
||||
{
|
||||
// assert: n < list.size()
|
||||
ea_t ea = ea_t(list[n]);
|
||||
if ( !is_code(get_flags(ea)) )
|
||||
create_insn(ea);
|
||||
jumpto(ea);
|
||||
return cbret_t(); // nothing changed
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
ssize_t idaapi x86seh_chooser_t::get_item_index(const void *item_data) const
|
||||
{
|
||||
if ( list.empty() )
|
||||
return NO_SELECTION;
|
||||
|
||||
// `item_data` is a pointer to a 32-bit address
|
||||
uint32 item_addr = *(const uint32 *)item_data;
|
||||
if ( item_addr == uint32(-1) )
|
||||
return 0; // first item by default
|
||||
|
||||
// find `item_script` in the list
|
||||
const uint32 *p = list.find(item_addr);
|
||||
if ( p != list.end() )
|
||||
return p - list.begin();
|
||||
return 0; // first item by default
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi x86seh_chooser_t::init()
|
||||
{
|
||||
// rebuild the handlers list
|
||||
uint64 fs_sel;
|
||||
ea_t fs_base;
|
||||
uint32 excr_ea;
|
||||
list.clear();
|
||||
if ( !get_reg_val("fs", &fs_sel)
|
||||
|| internal_get_sreg_base(&fs_base, tid, int(fs_sel)) <= DRC_NONE
|
||||
|| read_dbg_memory(fs_base, &excr_ea, sizeof(excr_ea)) != sizeof(excr_ea) )
|
||||
{
|
||||
warning("Failed to build the SEH list for thread %08X", tid);
|
||||
return false; // do not show the empty chooser
|
||||
}
|
||||
|
||||
struct EXC_REG_RECORD
|
||||
{
|
||||
uint32 p_prev;
|
||||
uint32 p_handler;
|
||||
};
|
||||
EXC_REG_RECORD rec;
|
||||
std::set<uint32> seen;
|
||||
while ( excr_ea != 0xffffffff )
|
||||
{
|
||||
if ( read_dbg_memory(excr_ea, &rec, sizeof(rec)) != sizeof(rec) )
|
||||
break;
|
||||
|
||||
if ( !seen.insert(excr_ea).second )
|
||||
{
|
||||
msg("Circular SEH record has been detected\n");
|
||||
break;
|
||||
}
|
||||
|
||||
list.push_back(rec.p_handler);
|
||||
excr_ea = rec.p_prev;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
chooser_t::cbret_t idaapi x86seh_chooser_t::refresh(ssize_t n)
|
||||
{
|
||||
uint32 item_addr = uint32(-1);
|
||||
if ( n >= 0 && n < list.size() )
|
||||
item_addr = list[n]; // remember the currently selected handler
|
||||
|
||||
init();
|
||||
|
||||
if ( n < 0 )
|
||||
return NO_SELECTION;
|
||||
ssize_t idx = get_item_index(&item_addr);
|
||||
// no need to adjust `idx` as get_item_index() returns first item by
|
||||
// default
|
||||
return idx;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
ssize_t idaapi x86seh_chooser_t::dbg_handler(void *ud, int code, va_list)
|
||||
{
|
||||
if ( code == dbg_suspend_process )
|
||||
{
|
||||
const char *ttl = static_cast<const char *>(ud);
|
||||
refresh_chooser(ttl);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct show_window_ah_t : public action_handler_t
|
||||
{
|
||||
virtual int idaapi activate(action_activation_ctx_t *) override
|
||||
{
|
||||
thid_t tid = get_current_thread();
|
||||
x86seh_chooser_t *ch = new x86seh_chooser_t(tid);
|
||||
return ch->choose() == 0;
|
||||
} //lint !e429 Custodial pointer 'ch' has not been freed or returned
|
||||
|
||||
virtual action_state_t idaapi update(action_update_ctx_t *) override
|
||||
{
|
||||
return AST_ENABLE;
|
||||
}
|
||||
};
|
||||
static show_window_ah_t show_window_ah;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void remove_x86seh_menu()
|
||||
{
|
||||
if ( req_id != -1 )
|
||||
{
|
||||
cancel_exec_request(req_id);
|
||||
req_id = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void install_x86seh_menu()
|
||||
{
|
||||
// HACK: We queue this request because commdbg apparently enables the debug menus
|
||||
// just after calling init_debugger().
|
||||
struct uireq_install_menu_t: public ui_request_t
|
||||
{
|
||||
virtual bool idaapi run() override
|
||||
{
|
||||
if ( !inf_is_64bit() )
|
||||
{
|
||||
register_and_attach_to_menu(
|
||||
"Debugger/Debugger windows/Stack trace",
|
||||
"dbg:sehList", "SEH list", NULL, SETMENU_APP,
|
||||
&show_window_ah,
|
||||
&PLUGIN,
|
||||
ADF_OT_PLUGIN);
|
||||
}
|
||||
req_id = -1;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
req_id = execute_ui_requests(new uireq_install_menu_t, NULL);
|
||||
}
|
||||
7
idasdk75/dbg/win32/w32sehch.h
Normal file
7
idasdk75/dbg/win32/w32sehch.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef __W32SEHCH__
|
||||
#define __W32SEHCH__
|
||||
|
||||
void install_x86seh_menu();
|
||||
void remove_x86seh_menu();
|
||||
|
||||
#endif
|
||||
3330
idasdk75/dbg/win32/win32_debmod.cpp
Normal file
3330
idasdk75/dbg/win32/win32_debmod.cpp
Normal file
File diff suppressed because it is too large
Load Diff
428
idasdk75/dbg/win32/win32_debmod.h
Normal file
428
idasdk75/dbg/win32/win32_debmod.h
Normal file
@@ -0,0 +1,428 @@
|
||||
#ifndef __WIN32_DEBUGGER_MODULE__
|
||||
#define __WIN32_DEBUGGER_MODULE__
|
||||
|
||||
#include <windows.h>
|
||||
#include <Tlhelp32.h>
|
||||
#include "../../ldr/pe/pe.h"
|
||||
#include "winbase_debmod.h"
|
||||
|
||||
//-V::720 It is advised to utilize the 'SuspendThread' function only when developing a debugger
|
||||
|
||||
// Type definitions
|
||||
|
||||
class win32_debmod_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// image information
|
||||
struct image_info_t
|
||||
{
|
||||
image_info_t() { memset(this, 0, sizeof(*this)); }
|
||||
image_info_t(win32_debmod_t *);
|
||||
image_info_t(win32_debmod_t *, ea_t _base, uint32 _imagesize, const qstring &_name);
|
||||
image_info_t(win32_debmod_t *, const LOAD_DLL_DEBUG_INFO &i, uint32 _imagesize, const char *_name);
|
||||
image_info_t(win32_debmod_t *, const modinfo_t &m);
|
||||
|
||||
win32_debmod_t *sess;
|
||||
ea_t base;
|
||||
uval_t imagesize;
|
||||
qstring name;
|
||||
LOAD_DLL_DEBUG_INFO dll_info;
|
||||
};
|
||||
|
||||
// key: image base address
|
||||
typedef std::map<ea_t, image_info_t> images_t;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct context_holder_t
|
||||
{
|
||||
bytevec_t buffer;
|
||||
PCONTEXT ptr;
|
||||
|
||||
context_holder_t() : ptr(NULL) {}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct context_helper_t
|
||||
{
|
||||
typedef DWORD64 (WINAPI *PGETENABLEDXSTATEFEATURES)();
|
||||
PGETENABLEDXSTATEFEATURES pfnGetEnabledXStateFeatures;
|
||||
|
||||
typedef BOOL (WINAPI *PINITIALIZECONTEXT)(PVOID Buffer, DWORD ContextFlags, PCONTEXT *Context, PDWORD ContextLength);
|
||||
PINITIALIZECONTEXT pfnInitializeContext;
|
||||
|
||||
typedef BOOL (WINAPI *PGETXSTATEFEATURESMASK)(PCONTEXT Context, PDWORD64 FeatureMask);
|
||||
PGETXSTATEFEATURESMASK pfnGetXStateFeaturesMask;
|
||||
|
||||
typedef PVOID (WINAPI *LOCATEXSTATEFEATURE)(PCONTEXT Context, DWORD FeatureId, PDWORD Length);
|
||||
LOCATEXSTATEFEATURE pfnLocateXStateFeature;
|
||||
|
||||
typedef BOOL (WINAPI *SETXSTATEFEATURESMASK)(PCONTEXT Context, DWORD64 FeatureMask);
|
||||
SETXSTATEFEATURESMASK pfnSetXStateFeaturesMask;
|
||||
|
||||
typedef BOOL (WINAPI *COPYCONTEXT)(PCONTEXT Destination, DWORD ContextFlags, PCONTEXT Source);
|
||||
COPYCONTEXT pfnCopyContext;
|
||||
|
||||
int xstate_context_size;
|
||||
bool get_xstate_context_size(int *out_ctxsz);
|
||||
context_helper_t() { clear(); }
|
||||
bool create_context(context_holder_t *out, int *ctxflags);
|
||||
bool xstate_helpers_loaded() const { return xstate_context_size > 0; }
|
||||
void clear();
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// thread information
|
||||
struct thread_info_t : public CREATE_THREAD_DEBUG_INFO
|
||||
{
|
||||
thread_info_t(
|
||||
win32_debmod_t *dm,
|
||||
const CREATE_THREAD_DEBUG_INFO &i,
|
||||
thid_t t,
|
||||
wow64_state_t wow64_state);
|
||||
win32_debmod_t *debmod;
|
||||
thid_t tid; // thread id
|
||||
int suspend_count;
|
||||
ea_t bpt_ea;
|
||||
int flags;
|
||||
#define THR_CLSMASK 0x0007 // valid register classes in CONTEXT structure
|
||||
// we use X86_RC.. constants here
|
||||
#define THR_TRACING 0x0100 // expecting a STEP event
|
||||
#define THR_FSSAVED 0x0200 // remembered FS value
|
||||
#define THR_WOW64 0x0400 // is wow64 process?
|
||||
#define THR_NEWNAME 0x0800 // thread was renamed
|
||||
context_holder_t ctx_holder;
|
||||
ea_t callgate_ea;
|
||||
qstring name;
|
||||
|
||||
void invalidate_context(void) { flags &= ~THR_CLSMASK; if ( ctx_holder.ptr != NULL ) get_ctx().ContextFlags = 0; }
|
||||
bool read_context(int clsmask);
|
||||
bool write_context(int clsmask);
|
||||
void cvt_from_wow64(
|
||||
const WOW64_CONTEXT &wow64ctx,
|
||||
int clsmask,
|
||||
PCONTEXT xstate_ctx) const;
|
||||
void cvt_to_wow64(
|
||||
WOW64_CONTEXT *wow64ctx,
|
||||
PCONTEXT xstate_ctx,
|
||||
int clsmask) const;
|
||||
bool toggle_tbit(bool set_tbit);
|
||||
bool is_tracing(void) const { return (flags & THR_TRACING) != 0; }
|
||||
void set_tracing(void) { flags |= THR_TRACING; }
|
||||
void clr_tracing(void) { flags &= ~THR_TRACING; }
|
||||
#ifdef __X86__
|
||||
ea_t get_ip(void) { return read_context(X86_RC_GENERAL) ? get_ctx().Eip : BADADDR; }
|
||||
#else
|
||||
ea_t get_ip(void) { return read_context(X86_RC_GENERAL) ? get_ctx().Rip : BADADDR; }
|
||||
#endif
|
||||
bool is_new_name(void) const { return (flags & THR_NEWNAME) != 0; }
|
||||
void clr_new_name(void) { flags &= ~THR_NEWNAME; }
|
||||
void set_new_name(void) { flags |= THR_NEWNAME; }
|
||||
CONTEXT &get_ctx() const { QASSERT(1669, ctx_holder.ptr != NULL); return *ctx_holder.ptr; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline thread_info_t::thread_info_t(
|
||||
win32_debmod_t *dm,
|
||||
const CREATE_THREAD_DEBUG_INFO &i,
|
||||
thid_t t,
|
||||
wow64_state_t wow64_state)
|
||||
: CREATE_THREAD_DEBUG_INFO(i), tid(t), suspend_count(0), bpt_ea(BADADDR),
|
||||
debmod(dm),
|
||||
flags(wow64_state > 0 ? THR_WOW64 : 0),
|
||||
callgate_ea(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Check if the context structure has valid values at the specified portion
|
||||
// portion is a conbination of CONTEXT_... bitmasks
|
||||
inline bool has_portion(const CONTEXT &ctx, int portion)
|
||||
{
|
||||
return (ctx.ContextFlags & portion & 0xFFFF) != 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// (tid -> info)
|
||||
struct threads_t: public std::map<DWORD, thread_info_t>
|
||||
{
|
||||
thread_info_t *get(DWORD tid)
|
||||
{
|
||||
const iterator it = find(tid);
|
||||
if ( it == end() )
|
||||
return NULL;
|
||||
return &it->second;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef qvector<thread_info_t> threadvec_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// structure for the internal breakpoint information for threads
|
||||
struct internal_bpt_info_t
|
||||
{
|
||||
int count; // number of times this breakpoint is 'set'
|
||||
uchar orig_bytes[BPT_CODE_SIZE]; // original byte values
|
||||
};
|
||||
typedef std::map<ea_t, internal_bpt_info_t> bpt_info_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef int (*process_cb_t)(debmod_t *, PROCESSENTRY32 *pe32, void *ud);
|
||||
typedef int (*module_cb_t)(debmod_t *, MODULEENTRY32 *me32, void *ud);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// A live PDB session, that will be used remotely (typically by non-windows machines).
|
||||
struct pdb_remote_session_t;
|
||||
void close_pdb_remote_session(pdb_remote_session_t *);
|
||||
|
||||
//Wow64-specific events
|
||||
#ifndef STATUS_WX86_BREAKPOINT
|
||||
# define STATUS_WX86_BREAKPOINT 0x4000001f
|
||||
#endif
|
||||
#ifndef STATUS_WX86_SINGLE_STEP
|
||||
# define STATUS_WX86_SINGLE_STEP 0x4000001e
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class win32_debmod_t : public winbase_debmod_t
|
||||
{
|
||||
typedef winbase_debmod_t inherited;
|
||||
|
||||
gdecode_t get_debug_event(debug_event_t *event, int timeout_ms);
|
||||
void check_thread(bool must_be_main_thread) const;
|
||||
void add_thread(const CREATE_THREAD_DEBUG_INFO &thr_info, thid_t tid);
|
||||
void install_callgate_workaround(thread_info_t *ti, const debug_event_t *event);
|
||||
int describe_stack_segment(
|
||||
thid_t tid,
|
||||
images_t &thr_ranges,
|
||||
images_t &cls_ranges,
|
||||
const _NT_TIB &tib,
|
||||
const char *pref);
|
||||
void update_thread_names(thread_name_vec_t *thr_names);
|
||||
|
||||
bool get_pe_exports_from_path(
|
||||
const char *path,
|
||||
linput_t *li,
|
||||
ea_t imagebase,
|
||||
name_info_t &ni,
|
||||
const char *exported_name=NULL) const;
|
||||
void patch_context_struct(
|
||||
CONTEXT &ctx,
|
||||
int reg_idx,
|
||||
const thread_info_t *ti,
|
||||
const regval_t *value) const;
|
||||
|
||||
public:
|
||||
// debugged process information
|
||||
qstring process_path;
|
||||
HANDLE thread_handle;
|
||||
HANDLE redirin_handle;
|
||||
HANDLE redirout_handle;
|
||||
attach_status_t attach_status;
|
||||
HANDLE attach_evid;
|
||||
int8 expecting_debug_break;
|
||||
bool stop_at_ntdll_bpts;
|
||||
|
||||
images_t curproc; // image of the running process
|
||||
images_t dlls; // list of loaded DLLs
|
||||
images_t images; // list of detected PE images
|
||||
images_t thread_ranges; // list of ranges related to threads
|
||||
images_t class_ranges; // list of ranges related to class names
|
||||
|
||||
easet_t dlls_to_import; // list of dlls to import information from
|
||||
modinfo_t binary_to_import; // executable to import information from
|
||||
|
||||
bpt_info_t thread_bpts;
|
||||
|
||||
threads_t threads;
|
||||
|
||||
// ID of a thread for which we must emulate a STEP event on XP (using a breakpoint)
|
||||
thid_t winxp_step_thread;
|
||||
|
||||
CREATE_PROCESS_DEBUG_INFO cpdi;
|
||||
|
||||
debug_event_t *in_event; // current debug event
|
||||
bool fake_suspend_event;
|
||||
bool exiting;
|
||||
bool pause_requested;
|
||||
procinfo_vec_t processes;
|
||||
|
||||
// threads suspended by the fiber created for restoring broken connections
|
||||
threadvec_t _suspended_threads;
|
||||
// event to wait until the broken connection is completely restored
|
||||
HANDLE broken_event_handle;
|
||||
context_helper_t context_helper;
|
||||
|
||||
// Module specific methods, to be implemented
|
||||
virtual void idaapi dbg_set_debugging(bool _debug_debugger) override;
|
||||
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) override;
|
||||
virtual void idaapi dbg_term(void) override;
|
||||
virtual drc_t idaapi dbg_detach_process(void) override;
|
||||
virtual drc_t idaapi dbg_start_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
int flags,
|
||||
const char *input_path,
|
||||
uint32 input_file_crc32,
|
||||
qstring *errbuf) override;
|
||||
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_ms) override;
|
||||
virtual drc_t idaapi dbg_attach_process(
|
||||
pid_t process_id,
|
||||
int event_id,
|
||||
int flags,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) override;
|
||||
virtual void idaapi dbg_stopped_at_debug_event(
|
||||
import_infos_t *infos,
|
||||
bool dlls_added,
|
||||
thread_name_vec_t *thr_names) override;
|
||||
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) override;
|
||||
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) override;
|
||||
virtual drc_t idaapi dbg_read_registers(
|
||||
thid_t thread_id,
|
||||
int clsmask,
|
||||
regval_t *values,
|
||||
qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_write_register(
|
||||
thid_t thread_id,
|
||||
int reg_idx,
|
||||
const regval_t *value,
|
||||
qstring *errbuf) override;
|
||||
|
||||
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) override;
|
||||
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &ranges, qstring *errbuf) override;
|
||||
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) override;
|
||||
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) override;
|
||||
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) override;
|
||||
virtual int idaapi handle_ioctl(int fn, const void *buf, size_t size, void **outbuf, ssize_t *outsize) override;
|
||||
//
|
||||
win32_debmod_t();
|
||||
~win32_debmod_t() { cleanup(); }
|
||||
|
||||
void handle_pdb_thread_request(void *data);
|
||||
uint32 calc_imagesize(eanat_t base);
|
||||
bool get_filename_for(
|
||||
char *buf,
|
||||
size_t bufsize,
|
||||
eanat_t image_name_ea,
|
||||
bool use_unicode,
|
||||
eanat_t image_base);
|
||||
ea_t get_dll_export(
|
||||
const images_t &dlls,
|
||||
ea_t imagebase,
|
||||
const char *exported_name);
|
||||
|
||||
bool create_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
bool is_gui,
|
||||
bool hide_window,
|
||||
PROCESS_INFORMATION *ProcessInformation);
|
||||
|
||||
void show_debug_event(const DEBUG_EVENT &ev);
|
||||
|
||||
ssize_t _read_memory(eanat_t ea, void *buffer, size_t size, bool suspend = false);
|
||||
ssize_t _write_memory(eanat_t ea, const void *buffer, size_t size, bool suspend = false);
|
||||
|
||||
int rdmsr(int reg, uint64 *value);
|
||||
int wrmsr(int reg, uint64 value);
|
||||
int kldbgdrv_access_msr(struct SYSDBG_MSR *msr, bool write);
|
||||
|
||||
// !! OVERWRITTEN METHODS !!
|
||||
bool refresh_hwbpts();
|
||||
|
||||
// Utility methods
|
||||
gdecode_t handle_exception(debug_event_t *event,
|
||||
const EXCEPTION_RECORD &er,
|
||||
bool was_thread_bpt,
|
||||
bool firsttime);
|
||||
ssize_t access_memory(eanat_t ea, void *buffer, ssize_t size, bool write, bool suspend);
|
||||
inline void resume_all_threads(bool raw = false);
|
||||
inline void suspend_all_threads(bool raw = false);
|
||||
size_t add_dll(image_info_t &ii);
|
||||
bool module_present(const char *modname);
|
||||
HANDLE get_thread_handle(thid_t tid);
|
||||
static int get_dmi_cb(debmod_t *sess, MODULEENTRY32 *me32, void *ud);
|
||||
void get_debugged_module_info(modinfo_t *dmi);
|
||||
int for_each_module(DWORD pid, module_cb_t module_cb, void *ud);
|
||||
bool myCloseHandle(HANDLE &h);
|
||||
void cleanup(void);
|
||||
void restore_original_bytes(ea_t ea, bool really_restore = true);
|
||||
int save_original_bytes(ea_t ea);
|
||||
bool set_thread_bpt(thread_info_t &ti, ea_t ea);
|
||||
bool del_thread_bpt(thread_info_t &ti, ea_t ea);
|
||||
bool del_thread_bpts(ea_t ea);
|
||||
bool has_bpt_at(ea_t ea);
|
||||
bool can_access(ea_t addr);
|
||||
ea_t get_kernel_bpt_ea(ea_t ea, thid_t tid);
|
||||
void create_attach_event(debug_event_t *event, bool attached);
|
||||
void create_start_event(debug_event_t *event);
|
||||
bool check_for_hwbpt(debug_event_t *event, bool is_stepping=false);
|
||||
ea_t get_region_info(ea_t ea, memory_info_t *info);
|
||||
bool get_dll_exports(
|
||||
const images_t &dlls,
|
||||
ea_t imagebase,
|
||||
name_info_t &ni,
|
||||
const char *exported_name = NULL);
|
||||
bool get_filename_from_process(
|
||||
eanat_t name_ea,
|
||||
bool is_unicode,
|
||||
char *buf,
|
||||
size_t bufsize);
|
||||
bool get_debug_string(const DEBUG_EVENT &ev, char *buf, size_t bufsize);
|
||||
int add_thread_ranges(
|
||||
thid_t tid,
|
||||
images_t &thread_ranges,
|
||||
images_t &class_ranges);
|
||||
ea_t get_pe_header(eanat_t imagebase, peheader_t *nh);
|
||||
bool get_pe_export_name_from_process(
|
||||
eanat_t imagebase,
|
||||
char *name,
|
||||
size_t namesize);
|
||||
|
||||
void show_exception_record(const EXCEPTION_RECORD &er, int level=0);
|
||||
|
||||
eanat_t pstos0(eanat_t ea);
|
||||
eanat_t s0tops(eanat_t ea);
|
||||
|
||||
bool prepare_to_stop_process(debug_event_t *, const threads_t &);
|
||||
bool disable_hwbpts();
|
||||
bool enable_hwbpts();
|
||||
bool may_write(ea_t ea);
|
||||
LPVOID correct_exe_image_base(LPVOID base);
|
||||
bool clear_tbit(thread_info_t &th);
|
||||
void invalidate_all_contexts(void);
|
||||
void enqueue_event(const debug_event_t &ev, queue_pos_t pos);
|
||||
|
||||
void suspend_running_threads(threadvec_t &suspended);
|
||||
void resume_suspended_threads(threadvec_t suspended) const;
|
||||
bool reopen_threads(void);
|
||||
|
||||
virtual bool idaapi write_registers(
|
||||
thid_t thread_id,
|
||||
int start,
|
||||
int count,
|
||||
const regval_t *values) override;
|
||||
|
||||
virtual bool idaapi dbg_prepare_broken_connection(void) override;
|
||||
virtual bool idaapi dbg_continue_broken_connection(pid_t pid) override;
|
||||
|
||||
qvector<pdb_remote_session_t*> pdb_remote_sessions;
|
||||
pdb_remote_session_t *get_pdb_session(int id);
|
||||
void delete_pdb_session(int id);
|
||||
|
||||
protected:
|
||||
virtual int dbg_freeze_threads_except(thid_t tid) override;
|
||||
virtual int dbg_thaw_threads_except(thid_t tid) override;
|
||||
};
|
||||
|
||||
ea_t s0tops(ea_t ea);
|
||||
|
||||
#endif
|
||||
|
||||
717
idasdk75/dbg/win32/win32_debmod_impl.cpp
Normal file
717
idasdk75/dbg/win32/win32_debmod_impl.cpp
Normal file
@@ -0,0 +1,717 @@
|
||||
//
|
||||
//
|
||||
// This file contains win32 specific implementations of win32_debmod class
|
||||
//
|
||||
//
|
||||
|
||||
#include <diskio.hpp>
|
||||
#include "win32_rpc.h"
|
||||
#include "win32_undoc.h"
|
||||
|
||||
#include "dbg_pe_hlp.cpp"
|
||||
|
||||
struct impfunc_t
|
||||
{
|
||||
const char *name;
|
||||
void *fptr;
|
||||
};
|
||||
#define IMPFUNC(x) { TEXT(#x), &x }
|
||||
|
||||
//lint -esym(843,ntdll) -esym(844,ntdll) could be const
|
||||
static HMODULE ntdll = NULL;
|
||||
static NtSystemDebugControl_t *NtSystemDebugControl;
|
||||
static NtLoadDriver_t *NtLoadDriver;
|
||||
static NtUnloadDriver_t *NtUnloadDriver;
|
||||
static RtlAdjustPrivilege_t *RtlAdjustPrivilege;
|
||||
static NtCreateFile_t *NtCreateFile;
|
||||
static NtDeviceIoControlFile_t *NtDeviceIoControlFile;
|
||||
|
||||
static const impfunc_t ntfuncs[] =
|
||||
{
|
||||
IMPFUNC(NtSystemDebugControl),
|
||||
IMPFUNC(NtLoadDriver),
|
||||
IMPFUNC(NtUnloadDriver),
|
||||
IMPFUNC(RtlAdjustPrivilege),
|
||||
IMPFUNC(NtCreateFile),
|
||||
IMPFUNC(NtDeviceIoControlFile),
|
||||
};
|
||||
|
||||
// To read MSRs, we use a local kernel debugger driver provided by Microsoft.
|
||||
//lint -esym(843,DriverHandle,DriverPath,DriverName) could be const
|
||||
//lint -esym(844,DriverHandle) could be pointing to const
|
||||
static HANDLE DriverHandle = NULL;
|
||||
static UNICODE_STRING DriverPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES\\kldbgdrv");
|
||||
static UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"\\Device\\kldbgdrv");
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// PE COMMON HELPER FUNCTIONS
|
||||
#define lread myread // since we can't use loader_failure()
|
||||
inline void myread(linput_t *li, void *buf, size_t size)
|
||||
{
|
||||
int bytes_read = qlread(li, buf, size);
|
||||
if ( bytes_read != size )
|
||||
{
|
||||
int saved_code = qerrcode();
|
||||
const char *errmsg = qerrstr();
|
||||
uint64 pos = qltell(li) - bytes_read;
|
||||
static const char *const format =
|
||||
"Read error: %s\n"
|
||||
"(file position 0x%" FMT_64 "X, wanted 0x%" FMT_Z "X bytes, read 0x%X)";
|
||||
|
||||
error(format,
|
||||
saved_code ? errmsg : "read past end of file",
|
||||
pos,
|
||||
size,
|
||||
bytes_read);
|
||||
}
|
||||
}
|
||||
|
||||
#include "../../ldr/pe/common.cpp"
|
||||
|
||||
#define GetMappedFileName_Name "GetMappedFileNameW"
|
||||
#define GetModuleFileNameEx_Name "GetModuleFileNameExW"
|
||||
|
||||
// function prototypes
|
||||
typedef DWORD (WINAPI *GetMappedFileName_t)(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, DWORD nSize);
|
||||
typedef DWORD (WINAPI *GetModuleFileNameEx_t)(HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize);
|
||||
|
||||
// functions pointers
|
||||
//lint -esym(843,_GetMappedFileName,_GetModuleFileNameEx) could be const
|
||||
static GetMappedFileName_t _GetMappedFileName = NULL;
|
||||
static GetModuleFileNameEx_t _GetModuleFileNameEx = NULL;
|
||||
|
||||
// dynamic linking information for PSAPI functions
|
||||
//lint -esym(843,hPSAPI) -esym(844,hPSAPI) could be const
|
||||
static HMODULE hPSAPI = NULL;
|
||||
|
||||
// dw32 support
|
||||
//lint -esym(843,system_teb_size) could be const
|
||||
static DWORD system_teb_size = MEMORY_PAGE_SIZE;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
LPVOID win32_debmod_t::correct_exe_image_base(LPVOID base)
|
||||
{
|
||||
return base;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
eanat_t win32_debmod_t::s0tops(eanat_t ea)
|
||||
{
|
||||
return ea;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
eanat_t win32_debmod_t::pstos0(eanat_t ea)
|
||||
{
|
||||
return ea;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool win32_debmod_t::prepare_to_stop_process(debug_event_t *, const threads_t &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool win32_debmod_t::disable_hwbpts()
|
||||
{
|
||||
for ( page_bpts_t::iterator p = page_bpts.begin(); p != page_bpts.end(); ++p )
|
||||
dbg_enable_page_bpt(p, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool win32_debmod_t::enable_hwbpts()
|
||||
{
|
||||
for ( page_bpts_t::iterator p = page_bpts.begin(); p != page_bpts.end(); ++p )
|
||||
dbg_enable_page_bpt(p, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool win32_debmod_t::may_write(ea_t /*ea*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int win32_debmod_t::describe_stack_segment(
|
||||
thid_t tid,
|
||||
images_t &thr_ranges,
|
||||
images_t &cls_ranges,
|
||||
const _NT_TIB &tib,
|
||||
const char *pref) // "x64" for x64 part of wow64 processes
|
||||
{
|
||||
int cnt = 1;
|
||||
char name[MAXSTR];
|
||||
asize_t size = EA_T(tib.StackBase) - EA_T(tib.StackLimit);
|
||||
qsnprintf(name, sizeof(name), "%sStack[%08X]", pref, tid);
|
||||
image_info_t ii_stack(this, EA_T(tib.StackLimit), size, name);
|
||||
thr_ranges.insert(std::make_pair(ii_stack.base, ii_stack));
|
||||
ii_stack.name = "STACK";
|
||||
cls_ranges.insert(std::make_pair(ii_stack.base, ii_stack));
|
||||
// verify a Stack PAGE_GUARD page exists
|
||||
ea_t ea_guard = ii_stack.base - MEMORY_PAGE_SIZE;
|
||||
MEMORY_BASIC_INFORMATION MemoryBasicInformation;
|
||||
if ( VirtualQueryEx(process_handle, (LPCVOID)(size_t)ea_guard,
|
||||
&MemoryBasicInformation, sizeof(MemoryBasicInformation)) )
|
||||
{
|
||||
if ( MemoryBasicInformation.Protect & PAGE_GUARD ) // a Stack PAGE_GUARD exists
|
||||
{
|
||||
qsnprintf(name, sizeof(name), "%sStack_PAGE_GUARD[%08X]", pref, tid);
|
||||
image_info_t ii_guard(this, ea_guard, MEMORY_PAGE_SIZE, name);
|
||||
thr_ranges.insert(std::make_pair(ii_guard.base, ii_guard));
|
||||
ii_guard.name = "STACK";
|
||||
cls_ranges.insert(std::make_pair(ii_guard.base, ii_guard));
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int win32_debmod_t::add_thread_ranges(
|
||||
thid_t tid,
|
||||
images_t &thr_ranges,
|
||||
images_t &cls_ranges)
|
||||
{
|
||||
thread_info_t *ti = threads.get(tid);
|
||||
if ( ti == NULL )
|
||||
return 0;
|
||||
|
||||
// This structure is specific to NT, but stack related records are Win9X compatible
|
||||
_NT_TIB tib;
|
||||
ea_t ea_tib = EA_T(ti->lpThreadLocalBase);
|
||||
if ( _read_memory(ea_tib, &tib, sizeof(tib)) != sizeof(tib) ) // read the TIB
|
||||
return 0;
|
||||
|
||||
// additional test: we verify that TIB->Self contains the TIB's linear address
|
||||
if ( EA_T(tib.Self) != ea_tib )
|
||||
return false;
|
||||
|
||||
// add TIB range
|
||||
char name[MAXSTR];
|
||||
qsnprintf(name, sizeof(name), "TIB[%08X]", tid);
|
||||
// we suppose the whole page is reserved for the TIB
|
||||
image_info_t ii_tib(this, ea_tib, system_teb_size, name);
|
||||
thr_ranges.insert(std::make_pair(ii_tib.base, ii_tib));
|
||||
|
||||
int cnt = 0;
|
||||
const char *pref = "";
|
||||
if ( check_wow64_process() == WOW64_YES )
|
||||
{
|
||||
// Note: This works for Windows versions <= 8.1
|
||||
// The offset of the 32-bit TEB address within the 64-bit TEB is 0.
|
||||
// This can be used to directly access the 32-bit TEB of a WOW64 thread
|
||||
ea_t wow64_tib_ea = *(uint32*)&tib;
|
||||
struct _NT_TIB32
|
||||
{
|
||||
DWORD ExceptionList;
|
||||
DWORD StackBase;
|
||||
DWORD StackLimit;
|
||||
DWORD SubSystemTib;
|
||||
DWORD FiberData;
|
||||
DWORD ArbitraryUserPointer;
|
||||
DWORD Self;
|
||||
};
|
||||
_NT_TIB32 tib32;
|
||||
if ( _read_memory(wow64_tib_ea, &tib32, sizeof(tib32)) == sizeof(tib32) )
|
||||
{
|
||||
_NT_TIB tib2;
|
||||
tib2.StackBase = (PVOID)(eanat_t)tib32.StackBase;
|
||||
tib2.StackLimit = (PVOID)(eanat_t)tib32.StackLimit;
|
||||
cnt += describe_stack_segment(tid, thr_ranges, cls_ranges, tib2, pref);
|
||||
}
|
||||
pref = "x64";
|
||||
}
|
||||
|
||||
// add stack range
|
||||
cnt += describe_stack_segment(tid, thr_ranges, cls_ranges, tib, pref);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Get PE header
|
||||
// In: ea=DLL imagebase, nh=buffer to keep the answer
|
||||
// child==true:ea is an address in the child process
|
||||
// child==false:ea is an address in the the debugger itself
|
||||
// Returns: offset to the headers, BADADDR means failure
|
||||
ea_t win32_debmod_t::get_pe_header(eanat_t ea, peheader_t *nh)
|
||||
{
|
||||
uint32 offset = 0;
|
||||
uint32 magic;
|
||||
if ( _read_memory(ea, &magic, sizeof(magic)) != sizeof(magic) )
|
||||
return BADADDR;
|
||||
if ( ushort(magic) == MC2('M','Z') )
|
||||
{
|
||||
if ( _read_memory(ea+PE_PTROFF, &offset, sizeof(offset)) != sizeof(offset) )
|
||||
return BADADDR;
|
||||
}
|
||||
peheader64_t pe64;
|
||||
if ( _read_memory(ea+offset, &pe64, sizeof(pe64)) != sizeof(pe64) )
|
||||
return BADADDR;
|
||||
if ( !pe64_to_pe(*nh, pe64, true, true) )
|
||||
return BADADDR;
|
||||
if ( nh->signature != PEEXE_ID )
|
||||
return BADADDR;
|
||||
return offset;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// calculate dll image size
|
||||
// since we could not find anything nice, we just look
|
||||
// at the beginning of the DLL module in the memory and extract
|
||||
// correct value from the file header
|
||||
uint32 win32_debmod_t::calc_imagesize(eanat_t base)
|
||||
{
|
||||
peheader_t nh;
|
||||
ea_t peoff = get_pe_header(base, &nh);
|
||||
if ( peoff == BADADDR )
|
||||
return 0;
|
||||
return nh.imagesize;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool win32_debmod_t::create_process(
|
||||
const char *path,
|
||||
const char *args,
|
||||
const char *startdir,
|
||||
bool is_gui,
|
||||
bool hide_window,
|
||||
PROCESS_INFORMATION *ProcessInformation)
|
||||
{
|
||||
linput_t *li = open_linput(path, false);
|
||||
if ( li == NULL )
|
||||
return false;
|
||||
pe_loader_t pl;
|
||||
pl.read_header(li, true);
|
||||
close_linput(li);
|
||||
|
||||
#ifndef __EA64__
|
||||
if ( pl.pe.is_pe_plus() )
|
||||
{
|
||||
dwarning("AUTOHIDE NONE\nPlease use ida64 to debug 64-bit applications");
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __X86__
|
||||
if ( pl.pe.is_pe_plus() )
|
||||
{
|
||||
static const char server_name[] = "win64_remote64.exe";
|
||||
if ( ask_yn(ASKBTN_YES,
|
||||
"AUTOHIDE REGISTRY\nHIDECANCEL\n"
|
||||
"Debugging 64-bit applications is only possible with the %s server.\n"
|
||||
"Launch it now?",
|
||||
server_name) == ASKBTN_YES )
|
||||
{
|
||||
do
|
||||
{
|
||||
// Switch to the remote win32 debugger
|
||||
if ( !load_debugger("win32_stub", true) )
|
||||
{
|
||||
warning("Failed to switch to the remote windows debugger!");
|
||||
break;
|
||||
}
|
||||
|
||||
// Form the server path
|
||||
char server_exe[QMAXPATH];
|
||||
qmakepath(server_exe, sizeof(server_exe), idadir(NULL), server_name, NULL);
|
||||
|
||||
// Try to launch the server
|
||||
STARTUPINFO si = { sizeof(si) };
|
||||
PROCESS_INFORMATION pi;
|
||||
if ( hide_window )
|
||||
{
|
||||
si.dwFlags |= STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE; /* SW_FORCEMINIMIZE ? */
|
||||
}
|
||||
if ( !::CreateProcess(server_exe, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) )
|
||||
{
|
||||
warning("Failed to run the 64-bit remote server!");
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the remote debugging options: localhost
|
||||
set_remote_debugger("localhost", "", -1);
|
||||
|
||||
// Notify the user
|
||||
info("Debugging server has been started, please try debugging the program again.");
|
||||
} while ( false );
|
||||
}
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return false;
|
||||
}
|
||||
#endif // __X86__
|
||||
|
||||
// Empty directory means our directory
|
||||
if ( startdir != NULL && startdir[0] == '\0' )
|
||||
startdir = NULL;
|
||||
|
||||
// Args passed as empty string?
|
||||
if ( args != NULL && args[0] == '\0' )
|
||||
args = NULL;
|
||||
|
||||
launch_process_params_t lpp;
|
||||
lpp.flags |= LP_TRACE | LP_PATH_WITH_ARGS;
|
||||
if ( !is_gui )
|
||||
lpp.flags |= LP_NEW_CONSOLE;
|
||||
if ( hide_window )
|
||||
lpp.flags |= LP_HIDE_WINDOW;
|
||||
|
||||
lpp.path = path;
|
||||
lpp.args = args;
|
||||
lpp.startdir = startdir;
|
||||
lpp.info = ProcessInformation;
|
||||
|
||||
qstring errbuf;
|
||||
if ( launch_process(lpp, &errbuf) == NULL )
|
||||
{
|
||||
dwarning("AUTOHIDE NONE\n%s", errbuf.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void term_win32_subsystem(void)
|
||||
{
|
||||
if ( hPSAPI != NULL )
|
||||
{
|
||||
FreeLibrary(hPSAPI);
|
||||
hPSAPI = NULL;
|
||||
}
|
||||
if ( DriverHandle != NULL )
|
||||
{
|
||||
CloseHandle(DriverHandle);
|
||||
DriverHandle = NULL;
|
||||
NtUnloadDriver(&DriverPath);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void init_win32_subsystem(void)
|
||||
{
|
||||
ntdll = GetModuleHandle(TEXT("ntdll.dll"));
|
||||
if ( ntdll != NULL )
|
||||
{
|
||||
for ( int i=0; i < qnumber(ntfuncs); i++ )
|
||||
*(FARPROC*)ntfuncs[i].fptr = GetProcAddress(ntdll, ntfuncs[i].name);
|
||||
}
|
||||
|
||||
// load the library
|
||||
hPSAPI = LoadLibrary(TEXT("psapi.dll"));
|
||||
if ( hPSAPI != NULL )
|
||||
{
|
||||
// find the needed functions
|
||||
*(FARPROC*)&_GetMappedFileName = GetProcAddress(hPSAPI, TEXT(GetMappedFileName_Name));
|
||||
*(FARPROC*)&_GetModuleFileNameEx = GetProcAddress(hPSAPI, TEXT(GetModuleFileNameEx_Name));
|
||||
if ( _GetMappedFileName == NULL )
|
||||
{
|
||||
FreeLibrary(hPSAPI);
|
||||
hPSAPI = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool win32_debmod_t::can_access(ea_t addr)
|
||||
{
|
||||
char dummy;
|
||||
return access_memory(addr, &dummy, 1, false, false) == 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// return the address of all names exported by a DLL in 'ni'
|
||||
// if 'exported_name' is given, only the address of this exported name will be returned in 'ni'
|
||||
bool win32_debmod_t::get_pe_exports_from_path(
|
||||
const char *path,
|
||||
linput_t *li,
|
||||
ea_t imagebase,
|
||||
name_info_t &ni,
|
||||
const char *exported_name) const
|
||||
{
|
||||
// prepare nice name prefix for exported functions names
|
||||
char prefix[MAXSTR];
|
||||
qstrncpy(prefix, qbasename(path), sizeof(prefix));
|
||||
char *ptr = strrchr(prefix, '.');
|
||||
if ( ptr != NULL )
|
||||
*ptr = '\0';
|
||||
qstrlwr(prefix);
|
||||
|
||||
pe_loader_t pl;
|
||||
if ( !pl.read_header(li) )
|
||||
return false;
|
||||
|
||||
struct export_reader_t : public pe_export_visitor_t
|
||||
{
|
||||
const char *prefix;
|
||||
ea_t imagebase;
|
||||
name_info_t ∋
|
||||
const char *exported_name;
|
||||
export_reader_t(const char *pfx, ea_t base, name_info_t &_ni, const char *exname)
|
||||
: prefix(pfx), imagebase(base), ni(_ni), exported_name(exname) {}
|
||||
int idaapi visit_export(uint32 rva, uint32 ord, const char *name, const char *)
|
||||
{
|
||||
ea_t fulladdr = imagebase + rva;
|
||||
if ( exported_name != NULL )
|
||||
{
|
||||
if ( strcmp(exported_name, name) == 0 )
|
||||
{
|
||||
ni.addrs.push_back(fulladdr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qstring n2;
|
||||
if ( name[0] == '\0' )
|
||||
n2.sprnt("%s_%u", prefix, ord);
|
||||
else
|
||||
n2.sprnt("%s_%s", prefix, name);
|
||||
ni.addrs.push_back(fulladdr);
|
||||
ni.names.push_back(n2.extract());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
export_reader_t er(prefix, imagebase, ni, exported_name);
|
||||
return pl.process_exports(li, er) >= 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// return the address of all names exported by a DLL in 'ni'
|
||||
// if 'exported_name' is given, only the address of this exported name will be returned in 'ni'
|
||||
bool win32_debmod_t::get_dll_exports(
|
||||
const images_t &loaded_dlls,
|
||||
ea_t imagebase,
|
||||
name_info_t &ni,
|
||||
const char *exported_name)
|
||||
{
|
||||
char prefix[MAXSTR];
|
||||
images_t::const_iterator p = loaded_dlls.find(imagebase);
|
||||
if ( p == loaded_dlls.end() )
|
||||
{
|
||||
dwarning("get_dll_exports: can't find dll name for imagebase %a", imagebase);
|
||||
return false;
|
||||
}
|
||||
char dname[MAXSTR];
|
||||
const char *dllname = p->second.name.c_str();
|
||||
qstrncpy(dname, dllname, sizeof(dname));
|
||||
if ( debapp_attrs.addrsize == 4 )
|
||||
replace_system32(dname, MAXSTR);
|
||||
linput_t *li = open_linput(dname, false);
|
||||
if ( li == NULL )
|
||||
{
|
||||
// sysWOW64: ntdll32.dll does not exist but there is a file called ntdll.dll
|
||||
if ( stricmp(qbasename(dllname), "ntdll32.dll") != 0 )
|
||||
return false;
|
||||
if ( qisabspath(dllname) )
|
||||
{
|
||||
qstrncpy(prefix, dllname, sizeof(prefix));
|
||||
char *fname = qbasename(prefix);
|
||||
qstrncpy(fname, "ntdll.dll", sizeof(prefix)-(fname-prefix));
|
||||
dllname = prefix;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __X86__
|
||||
// TODO: On X86 there might by file redirection active on a X64 host
|
||||
// Therefore we will load on such system always 32 bit DLL, as we can
|
||||
// access 64 bit one without disabling the redirection
|
||||
dllname = "C:\\Windows\\System32\\ntdll.dll";
|
||||
#else
|
||||
#ifndef __EA64__
|
||||
dllname = "C:\\Windows\\SysWOW64\\ntdll.dll";
|
||||
#else
|
||||
dllname = debapp_attrs.addrsize != 4 ? "C:\\Windows\\System32\\ntdll.dll" : "C:\\Windows\\SysWOW64\\ntdll.dll";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
li = open_linput(dllname, false);
|
||||
if ( li == NULL )
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = get_pe_exports_from_path(dllname, li, imagebase, ni, exported_name);
|
||||
close_linput(li);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// get name from export directory in PE image in debugged process
|
||||
bool win32_debmod_t::get_pe_export_name_from_process(
|
||||
eanat_t imagebase,
|
||||
char *name,
|
||||
size_t namesize)
|
||||
{
|
||||
peheader_t pe;
|
||||
ea_t peoff = get_pe_header(imagebase, &pe);
|
||||
if ( peoff != BADADDR && pe.expdir.rva != 0 )
|
||||
{
|
||||
eanat_t ea = imagebase + pe.expdir.rva;
|
||||
peexpdir_t expdir;
|
||||
if ( _read_memory(ea, &expdir, sizeof(expdir)) == sizeof(expdir) )
|
||||
{
|
||||
ea = imagebase + expdir.dllname;
|
||||
name[0] = '\0';
|
||||
_read_memory(ea, name, namesize); // don't check the return code because
|
||||
// we might have read more than necessary
|
||||
if ( name[0] != '\0' )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Read/write a model specific register using the driver provided by WinDbg.
|
||||
// The following requirements are imposed by this code:
|
||||
// - debugger module should be run with admin privileges
|
||||
// - System must be loaded with /debug switch (use bcdedit.exe to turn it on)
|
||||
// - Windbg local kernel debugging should be used at least once
|
||||
// This code is based on a sample kindly provided by Alex Ionescu.
|
||||
int win32_debmod_t::kldbgdrv_access_msr(SYSDBG_MSR *msr, bool write)
|
||||
{
|
||||
NTSTATUS code;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
if ( DriverHandle == NULL )
|
||||
{
|
||||
//
|
||||
// Acquire 'load driver' privilege
|
||||
//
|
||||
BOOLEAN Old;
|
||||
code = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, TRUE, FALSE, &Old);
|
||||
if ( FAILED(code) )
|
||||
{
|
||||
dwarning("AUTOHIDE NONE\n"
|
||||
"Failed to acquire 'load driver' privilege, please run as admin!\n"
|
||||
"Error: %s\n", winerr(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
//
|
||||
// And need this for the driver to accept our commands
|
||||
// Additionally, system must be booted in /DEBUG mode
|
||||
//
|
||||
code = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &Old);
|
||||
if ( FAILED(code) )
|
||||
{
|
||||
dwarning("AUTOHIDE NONE\n"
|
||||
"Failed to acquire 'debug' privilege, is system booted in /debug mode?\n"
|
||||
"Error: %s\n", winerr(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
//
|
||||
// Now load the driver
|
||||
//
|
||||
code = NtLoadDriver(&DriverPath);
|
||||
if ( FAILED(code) && code != STATUS_IMAGE_ALREADY_LOADED )
|
||||
{
|
||||
dwarning("AUTOHIDE NONE\n"
|
||||
"Failed to load 'kldbgdrv', please use local kernel debugging at least once!\n"
|
||||
"Error: %s\n", winerr(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
//
|
||||
// Open a handle to it
|
||||
//
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
InitializeObjectAttributes(&ObjectAttributes, &DriverName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
code = NtCreateFile(&DriverHandle,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
FILE_CREATE,
|
||||
FILE_NON_DIRECTORY_FILE,
|
||||
NULL,
|
||||
0);
|
||||
if ( FAILED(code) )
|
||||
{
|
||||
dwarning("AUTOHIDE NONE\n"
|
||||
"Failed to open 'kldbgdrv'\n"
|
||||
"Error: %s\n", winerr(code));
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Package the input parameters into the private structure
|
||||
//
|
||||
KLDD_DATA_DEBUG_CONTROL KldDebugCommand;
|
||||
KldDebugCommand.Command = write ? SysDbgWriteMsr : SysDbgReadMsr;
|
||||
KldDebugCommand.InputBuffer = msr;
|
||||
KldDebugCommand.InputBufferLength = sizeof(*msr);
|
||||
|
||||
//
|
||||
// Send the request -- output isn't packaged, just specify directly the buffer
|
||||
//
|
||||
code = NtDeviceIoControlFile(DriverHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
KLDD_CODE_DEBUG_CONTROL,
|
||||
&KldDebugCommand,
|
||||
sizeof(KldDebugCommand),
|
||||
msr,
|
||||
sizeof(*msr));
|
||||
if ( FAILED(code) )
|
||||
{
|
||||
dwarning("AUTOHIDE NONE\n"
|
||||
"Failed to access model specific register, is system booted in /debug mode?\n"
|
||||
"Error: %s\n", winerr(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
// all ok!
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int win32_debmod_t::rdmsr(int reg, uint64 *value)
|
||||
{
|
||||
SYSDBG_MSR msr;
|
||||
msr.reg = reg;
|
||||
msr.value = 0; // shut up the compiler
|
||||
|
||||
NTSTATUS code;
|
||||
if ( NtSystemDebugControl == NULL )
|
||||
code = STATUS_NOT_IMPLEMENTED;
|
||||
else
|
||||
code = NtSystemDebugControl(SysDbgReadMsr, &msr, sizeof(msr), &msr, sizeof(msr), 0);
|
||||
|
||||
// if failed to read it with SystemDebugControl, try the driver
|
||||
if ( FAILED(code) )
|
||||
code = kldbgdrv_access_msr(&msr, false);
|
||||
|
||||
if ( SUCCEEDED(code) )
|
||||
*value = msr.value;
|
||||
return code;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int win32_debmod_t::wrmsr(int reg, uint64 value)
|
||||
{
|
||||
SYSDBG_MSR msr;
|
||||
msr.reg = reg;
|
||||
msr.value = value;
|
||||
|
||||
NTSTATUS code;
|
||||
if ( NtSystemDebugControl == NULL )
|
||||
code = STATUS_NOT_IMPLEMENTED;
|
||||
else
|
||||
code = NtSystemDebugControl(SysDbgWriteMsr, &msr, sizeof(msr), NULL, 0, 0);
|
||||
|
||||
// if failed to write it with SystemDebugControl, try the driver
|
||||
if ( FAILED(code) )
|
||||
code = kldbgdrv_access_msr(&msr, true);
|
||||
|
||||
return code;
|
||||
}
|
||||
208
idasdk75/dbg/win32/win32_local_impl.cpp
Normal file
208
idasdk75/dbg/win32/win32_local_impl.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
#ifndef __NT__
|
||||
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
|
||||
#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT
|
||||
#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT
|
||||
#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP
|
||||
#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED
|
||||
#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND
|
||||
#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO
|
||||
#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT
|
||||
#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION
|
||||
#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW
|
||||
#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK
|
||||
#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW
|
||||
#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO
|
||||
#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW
|
||||
#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION
|
||||
#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR
|
||||
#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION
|
||||
#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION
|
||||
#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW
|
||||
#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION
|
||||
#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION
|
||||
#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE
|
||||
#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT
|
||||
#define DBG_CONTROL_C 0x40010005L
|
||||
#define DBG_CONTROL_BREAK 0x40010008L
|
||||
#define STATUS_GUARD_PAGE_VIOLATION 0x80000001L
|
||||
#define STATUS_DATATYPE_MISALIGNMENT 0x80000002L
|
||||
#define STATUS_BREAKPOINT 0x80000003L
|
||||
#define STATUS_SINGLE_STEP 0x80000004L
|
||||
#define STATUS_ACCESS_VIOLATION 0xC0000005L
|
||||
#define STATUS_IN_PAGE_ERROR 0xC0000006L
|
||||
#define STATUS_INVALID_HANDLE 0xC0000008L
|
||||
#define STATUS_NO_MEMORY 0xC0000017L
|
||||
#define STATUS_ILLEGAL_INSTRUCTION 0xC000001DL
|
||||
#define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025L
|
||||
#define STATUS_INVALID_DISPOSITION 0xC0000026L
|
||||
#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008CL
|
||||
#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008DL
|
||||
#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008EL
|
||||
#define STATUS_FLOAT_INEXACT_RESULT 0xC000008FL
|
||||
#define STATUS_FLOAT_INVALID_OPERATION 0xC0000090L
|
||||
#define STATUS_FLOAT_OVERFLOW 0xC0000091L
|
||||
#define STATUS_FLOAT_STACK_CHECK 0xC0000092L
|
||||
#define STATUS_FLOAT_UNDERFLOW 0xC0000093L
|
||||
#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094L
|
||||
#define STATUS_INTEGER_OVERFLOW 0xC0000095L
|
||||
#define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096L
|
||||
#define STATUS_STACK_OVERFLOW 0xC00000FDL
|
||||
#define STATUS_CONTROL_C_EXIT 0xC000013AL
|
||||
#define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4L
|
||||
#define STATUS_FLOAT_MULTIPLE_TRAPS 0xC00002B5L
|
||||
#define STATUS_REG_NAT_CONSUMPTION 0xC00002C9L
|
||||
#define SUCCEEDED(x) (x >= 0)
|
||||
#define FAILED(x) (x < 0)
|
||||
#endif
|
||||
|
||||
#include <expr.hpp>
|
||||
#include <loader.hpp>
|
||||
#include "../ldr/pe/pe.h"
|
||||
#include "../plugins/pdb/pdb.hpp"
|
||||
#include "win32_rpc.h"
|
||||
#include "dbg_rpc_hlp.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char idc_win32_rdmsr_args[] = { VT_LONG, 0 };
|
||||
static error_t idaapi idc_win32_rdmsr(idc_value_t *argv, idc_value_t *res)
|
||||
{
|
||||
uint64 value = 0; // shut up the compiler
|
||||
uval_t reg = argv[0].num;
|
||||
#ifdef RPC_CLIENT
|
||||
void *out = NULL;
|
||||
ssize_t outsize;
|
||||
int code = g_dbgmod.send_ioctl(WIN32_IOCTL_RDMSR, ®, sizeof(reg), &out, &outsize);
|
||||
if ( SUCCEEDED(code) && outsize == sizeof(value) )
|
||||
value = *(uint64*)out;
|
||||
qfree(out);
|
||||
#else
|
||||
int code = g_dbgmod.rdmsr(reg, &value);
|
||||
#endif
|
||||
if ( FAILED(code) )
|
||||
{
|
||||
res->num = code;
|
||||
return set_qerrno(eExecThrow); // read error, raise exception
|
||||
}
|
||||
res->set_int64(value);
|
||||
return eOk;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char idc_win32_wrmsr_args[] = { VT_LONG, VT_INT64, 0 };
|
||||
static error_t idaapi idc_win32_wrmsr(idc_value_t *argv, idc_value_t *res)
|
||||
{
|
||||
win32_wrmsr_t msr;
|
||||
msr.reg = argv[0].num;
|
||||
msr.value = argv[1].i64;
|
||||
#ifdef RPC_CLIENT
|
||||
res->num = g_dbgmod.send_ioctl(WIN32_IOCTL_WRMSR, &msr, sizeof(msr), NULL, NULL);
|
||||
#else
|
||||
res->num = g_dbgmod.wrmsr(msr.reg, msr.value);
|
||||
#endif
|
||||
return eOk;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Installs or uninstalls debugger specific idc functions
|
||||
static bool register_idc_funcs(bool reg)
|
||||
{
|
||||
static const ext_idcfunc_t idcfuncs[] =
|
||||
{
|
||||
{ IDC_READ_MSR, idc_win32_rdmsr, idc_win32_rdmsr_args, NULL, 0, 0 },
|
||||
{ IDC_WRITE_MSR, idc_win32_wrmsr, idc_win32_wrmsr_args, NULL, 0, 0 },
|
||||
};
|
||||
return add_idc_funcs(idcfuncs, qnumber(idcfuncs), reg);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi rebase_if_required_to(ea_t new_base)
|
||||
{
|
||||
netnode penode(PE_NODE);
|
||||
ea_t currentbase = new_base;
|
||||
ea_t imagebase = ea_t(penode.altval(PE_ALT_IMAGEBASE)); // loading address (usually pe.imagebase)
|
||||
|
||||
if ( imagebase == 0 )
|
||||
{
|
||||
if ( !is_miniidb() )
|
||||
warning("AUTOHIDE DATABASE\n"
|
||||
"IDA could not automatically determine if the program should be\n"
|
||||
"rebased in the database because the database format is too old and\n"
|
||||
"doesn't contain enough information.\n"
|
||||
"Create a new database if you want automated rebasing to work properly.\n"
|
||||
"Note you can always manually rebase the program by using the\n"
|
||||
"Edit, Segments, Rebase program command.");
|
||||
}
|
||||
else if ( imagebase != currentbase )
|
||||
{
|
||||
rebase_or_warn(imagebase, currentbase);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool read_pe_header(peheader_t *pe)
|
||||
{
|
||||
netnode penode(PE_NODE);
|
||||
return penode.valobj(pe, sizeof(peheader_t)) > 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialize Win32 debugger plugin
|
||||
static bool win32_init_plugin(void)
|
||||
{
|
||||
// Remote debugger? Then nothing to initialize locally
|
||||
#ifndef RPC_CLIENT
|
||||
if ( !init_subsystem() )
|
||||
return false;
|
||||
#endif
|
||||
if ( !netnode::inited() || is_miniidb() || inf_is_snapshot() )
|
||||
{
|
||||
#ifndef __NT__
|
||||
// local debugger is available if we are running under Windows
|
||||
// for other systems only the remote debugger is available
|
||||
if ( !debugger.is_remote() )
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( inf_get_filetype() != f_PE )
|
||||
return false; // only PE files
|
||||
|
||||
processor_t &ph = PH;
|
||||
if ( ph.id != TARGET_PROCESSOR && ph.id != -1 )
|
||||
return false;
|
||||
|
||||
// find out the pe header
|
||||
peheader_t pe;
|
||||
if ( !read_pe_header(&pe) )
|
||||
return false;
|
||||
|
||||
// debug only gui, console, or unknown applications
|
||||
if ( pe.subsys != PES_WINGUI // Windows GUI
|
||||
&& pe.subsys != PES_WINCHAR // Windows Character
|
||||
&& pe.subsys != PES_UNKNOWN ) // Unknown
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void win32_term_plugin(void)
|
||||
{
|
||||
#ifndef RPC_CLIENT
|
||||
term_subsystem();
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdb_remote_session_t;
|
||||
void close_pdb_remote_session(pdb_remote_session_t *)
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef HAVE_PLUGIN_COMMENTS
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "Userland win32 debugger plugin";
|
||||
#endif
|
||||
203
idasdk75/dbg/win32/win32_rpc.h
Normal file
203
idasdk75/dbg/win32/win32_rpc.h
Normal file
@@ -0,0 +1,203 @@
|
||||
|
||||
#ifndef WIN32_RPC_H
|
||||
#define WIN32_RPC_H
|
||||
|
||||
// IOCTL codes for the win32 debugger
|
||||
|
||||
#define WIN32_IOCTL_RDMSR 0 // read model specific register
|
||||
#define WIN32_IOCTL_WRMSR 1 // write model specific register
|
||||
#define WIN32_IOCTL_READFILE 2 // server->client: read bytes from the input file
|
||||
// uint64 offset;
|
||||
// uint32 length;
|
||||
// returns: 1 - ok
|
||||
// -2 - error (text in output buffer)
|
||||
|
||||
// Open file for PDB retrieval.
|
||||
//
|
||||
// This operation will *typically* require that executable data
|
||||
// be provided to the underlying MS PDB "DIA" dll. Therefore,
|
||||
// there is _no_ way (currently) that this operation will
|
||||
// immediately return something relevant. The client must
|
||||
// poll for _OPERATION_COMPLETE-ness.
|
||||
//
|
||||
// client->server
|
||||
// (unpacked) compiler_info_t: compiler_info
|
||||
// (packed) uint64 : base_address
|
||||
// (unpacked) char * : input_file
|
||||
// (unpacked) char * : user symbols path
|
||||
// server->client
|
||||
// (packed) uint32 : session handle
|
||||
#define WIN32_IOCTL_PDB_OPEN 3
|
||||
|
||||
// Close PDB 'session', previously opened with _PDB_OPEN.
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// server->client
|
||||
// void
|
||||
#define WIN32_IOCTL_PDB_CLOSE 4
|
||||
|
||||
// Fetch the data for one symbol.
|
||||
//
|
||||
// Synchronous operation.
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (packed) uint64 : symbol ID
|
||||
// server->client
|
||||
// (unpacked) uint32: The integer value 1.
|
||||
// (serialized) data: Packed symbol data (once).
|
||||
#define WIN32_IOCTL_PDB_FETCH_SYMBOL 5
|
||||
|
||||
// Fetch the data for the children of a symbol.
|
||||
//
|
||||
// Synchronous operation.
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (packed) uint64 : symbol ID
|
||||
// (packed) uint32 : children type (a SymTagEnum)
|
||||
// server->client
|
||||
// (unpacked) uint32: Number of symbols whose data
|
||||
// has been fetched.
|
||||
// (serialized) data: Packed symbol data (N times).
|
||||
#define WIN32_IOCTL_PDB_FETCH_CHILDREN 6
|
||||
|
||||
// Is the current operation complete?
|
||||
//
|
||||
// Depending on the type of the operation, the contents
|
||||
// of the results will differ:
|
||||
// - _OPEN
|
||||
// (packed) uint64 : Global symbol ID.
|
||||
// (packed) uint32 : machine type.
|
||||
// (packed) uint32 : DIA version.
|
||||
//
|
||||
// NOTE: Currently, this IOCTL only makes sense to check
|
||||
// for completeness of operation _OPEN, but this
|
||||
// might change in the future.
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// server->client
|
||||
// (packed) uint32 : See pdb_op_completion_t
|
||||
// Depending on this first byte, the following will be come:
|
||||
// pdb_op_not_complete:
|
||||
// nothing
|
||||
// pdb_op_complete:
|
||||
// (packed) uint32 : global symbol ID
|
||||
// (packed) uint32 : machine type
|
||||
// (packed) uint32 : DIA version
|
||||
// (unpacked) str : used file name
|
||||
// pdb_op_failure:
|
||||
// (unpacked) str : error message
|
||||
|
||||
#define WIN32_IOCTL_PDB_OPERATION_COMPLETE 7
|
||||
|
||||
// Get lines by VA
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (packed) ea_t : VA
|
||||
// (packed) uint64 : length
|
||||
// server->client
|
||||
// (packed) uint32 : the number of line-number objects
|
||||
// (packed) data : the line-number objects (N times)
|
||||
//
|
||||
// Each of the line-number objects is transmitted like so:
|
||||
// (packed) ea_t : VA
|
||||
// (packed) uint32 : length
|
||||
// (packed) uint32 : columnNumber
|
||||
// (packed) uint32 : columnNumberEnd
|
||||
// (packed) uint32 : lineNumber
|
||||
// (packed) uint32 : lineNumberEnd
|
||||
// (packed) uint32 : file_id
|
||||
// (unpacked) byte : statement
|
||||
#define WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA 8
|
||||
|
||||
// Get lines by coordinates
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (packed) uint32 : file ID
|
||||
// (packed) uint32 : lnnum
|
||||
// (packed) uint32 : colnum
|
||||
// server->client
|
||||
// same as WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA
|
||||
#define WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_COORDS 9
|
||||
|
||||
// Get symbols at EA
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (packed) ea_t : VA
|
||||
// (packed) uint64 : length
|
||||
// (packed) uint32 : children type (a SymTagEnum)
|
||||
// server->client
|
||||
// (unpacked) uint32: Number of symbols whose data
|
||||
// has been fetched.
|
||||
// (serialized) data: Packed symbol data (N times).
|
||||
#define WIN32_IOCTL_PDB_SIP_FETCH_SYMBOLS_AT_VA 10
|
||||
|
||||
// Get compilands for file
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (packed) uint32 : file ID
|
||||
// server->client
|
||||
// (unpacked) uint32: Number of symbols whose data
|
||||
// has been fetched.
|
||||
// (serialized) data: Packed symbol data (N times).
|
||||
#define WIN32_IOCTL_PDB_SIP_FETCH_FILE_COMPILANDS 11
|
||||
|
||||
// Get path for file ID
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (packed) uint32 : file ID
|
||||
// server->client
|
||||
// (unpacked) str : the path
|
||||
#define WIN32_IOCTL_PDB_SIP_FETCH_FILE_PATH 12
|
||||
|
||||
// Get files IDs for files corresponding to symbol
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (packed) uint64 : symbol ID
|
||||
// server->client
|
||||
// (packed) uint32 : the number of IDs
|
||||
// (packed) uint32 : file ID (N times).
|
||||
#define WIN32_IOCTL_PDB_SIP_FETCH_SYMBOL_FILES 13
|
||||
|
||||
// Get files IDs for files whose name matches
|
||||
//
|
||||
// client->server
|
||||
// (packed) uint32 : session handle
|
||||
// (unpacked) str : the file name
|
||||
// server->client
|
||||
// (packed) uint32 : the number of IDs
|
||||
// (packed) uint32 : file ID (N times).
|
||||
#define WIN32_IOCTL_PDB_SIP_FIND_FILES 14
|
||||
|
||||
enum ioctl_pdb_code_t
|
||||
{
|
||||
pdb_ok = 1,
|
||||
pdb_error = -2,
|
||||
};
|
||||
|
||||
enum pdb_op_completion_t
|
||||
{
|
||||
pdb_op_not_complete = 0,
|
||||
pdb_op_complete = 1,
|
||||
pdb_op_failure = -1,
|
||||
};
|
||||
|
||||
|
||||
// WIN32_IOCTL_WRMSR uses this structure:
|
||||
struct win32_wrmsr_t
|
||||
{
|
||||
uint32 reg;
|
||||
uint64 value;
|
||||
};
|
||||
|
||||
|
||||
#endif // WIN32_RPC_H
|
||||
406
idasdk75/dbg/win32/win32_server.cpp
Normal file
406
idasdk75/dbg/win32/win32_server.cpp
Normal file
@@ -0,0 +1,406 @@
|
||||
//
|
||||
//
|
||||
// This file contains win32 specific implementations of win32_debugger_module class
|
||||
// server-side functionality only
|
||||
//
|
||||
//
|
||||
|
||||
#include <pro.h>
|
||||
#include "win32_rpc.h"
|
||||
#include "win32_debmod.h"
|
||||
#include "dbg_rpc_hlp.h"
|
||||
|
||||
bool ida_export idb_utf8(qstring *, const char *, int, int) { return false; }
|
||||
|
||||
#include "tilfuncs.hpp"
|
||||
|
||||
//---------------------------------------------------------- main thread ---
|
||||
static AS_PRINTF(3, 4) int pdb_ioctl_error(void **poutbuf, ssize_t *poutsize, const char *format, ...)
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
int len = qvsnprintf(buf, sizeof(buf), format, va);
|
||||
va_end(va);
|
||||
msg("%s", buf);
|
||||
|
||||
*poutsize = len + 1;
|
||||
*poutbuf = qstrdup(buf);
|
||||
return pdb_error;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------- main thread ---
|
||||
void win32_debmod_t::handle_pdb_thread_request(void *_pdb_rsess)
|
||||
{
|
||||
pdb_remote_session_t *pdb_rsess = (pdb_remote_session_t *) _pdb_rsess;
|
||||
pdb_remote_session_t::client_read_request_t &rr = pdb_rsess->client_read_request;
|
||||
if ( rr.kind == READ_INPUT_FILE )
|
||||
{
|
||||
// read input file
|
||||
bytevec_t req;
|
||||
req.pack_dq(rr.off_ea);
|
||||
req.pack_dd(rr.size);
|
||||
void *outbuf = NULL;
|
||||
ssize_t outsize = 0;
|
||||
// send request to IDA
|
||||
int rc = send_ioctl(WIN32_IOCTL_READFILE, req.begin(), req.size(), &outbuf, &outsize);
|
||||
if ( rc == 1 && outbuf != NULL )
|
||||
{
|
||||
// OK
|
||||
size_t copylen = qmin(rr.size, outsize);
|
||||
memcpy(rr.buffer, outbuf, copylen);
|
||||
rr.size = copylen;
|
||||
rr.result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rr.result = false;
|
||||
}
|
||||
if ( outbuf != NULL )
|
||||
qfree(outbuf);
|
||||
}
|
||||
else if ( rr.kind == READ_MEMORY )
|
||||
{
|
||||
// read memory
|
||||
ea_t ea = ea_t(rr.off_ea);
|
||||
void *buf = rr.buffer;
|
||||
size_t size = rr.size;
|
||||
ssize_t rc = _read_memory(ea, buf, size);
|
||||
if ( rc >= 0 )
|
||||
rr.size = rc;
|
||||
rr.result = rc >= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown request
|
||||
rr.result = false;
|
||||
}
|
||||
|
||||
rr.read_complete();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
pdb_remote_session_t *win32_debmod_t::get_pdb_session(int id)
|
||||
{
|
||||
for ( size_t i = 0; i < pdb_remote_sessions.size(); ++i )
|
||||
if ( pdb_remote_sessions[i]->get_id() == id )
|
||||
return pdb_remote_sessions[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void win32_debmod_t::delete_pdb_session(int id)
|
||||
{
|
||||
for ( size_t i = 0; i < pdb_remote_sessions.size(); ++i )
|
||||
{
|
||||
if ( pdb_remote_sessions[i]->get_id() == id )
|
||||
{
|
||||
pdb_remote_sessions[i]->stop();
|
||||
delete pdb_remote_sessions[i];
|
||||
pdb_remote_sessions.erase(pdb_remote_sessions.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void close_pdb_remote_session(pdb_remote_session_t *session)
|
||||
{
|
||||
session->stop();
|
||||
delete session;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------- main thread ---
|
||||
int idaapi win32_debmod_t::handle_ioctl(
|
||||
int fn,
|
||||
const void *buf,
|
||||
size_t size,
|
||||
void **poutbuf,
|
||||
ssize_t *poutsize)
|
||||
{
|
||||
qnotused(size);
|
||||
int sid = 0; // pdb_remote_session_t ID
|
||||
pdb_remote_session_t *pdb_rsess = NULL;
|
||||
switch ( fn )
|
||||
{
|
||||
case WIN32_IOCTL_RDMSR:
|
||||
QASSERT(30119, size == sizeof(uval_t));
|
||||
{
|
||||
uint64 value;
|
||||
uval_t reg = *(uval_t *)buf;
|
||||
int code = rdmsr(reg, &value);
|
||||
if ( SUCCEEDED(code) )
|
||||
{
|
||||
*poutbuf = qalloc(sizeof(value));
|
||||
if ( *poutbuf != NULL )
|
||||
{
|
||||
memcpy(*poutbuf, &value, sizeof(value));
|
||||
*poutsize = sizeof(value);
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_WRMSR:
|
||||
QASSERT(30120, size == sizeof(win32_wrmsr_t));
|
||||
{
|
||||
win32_wrmsr_t &msr = *(win32_wrmsr_t *)buf;
|
||||
return wrmsr(msr.reg, msr.value);
|
||||
}
|
||||
|
||||
#define ENSURE_PDB_THREAD() \
|
||||
do \
|
||||
{ \
|
||||
if ( !pdb_thread.is_running() ) \
|
||||
return pdb_ioctl_error( \
|
||||
poutbuf, poutsize, "PDB thread not running?!?\n"); \
|
||||
} while ( false )
|
||||
|
||||
#define GET_OPENED_SESSION() \
|
||||
do \
|
||||
{ \
|
||||
if ( mmdsr.empty() ) \
|
||||
return pdb_error; \
|
||||
sid = mmdsr.unpack_dd(); \
|
||||
pdb_rsess = get_pdb_session(sid); \
|
||||
} while ( false )
|
||||
|
||||
#define ENSURE_SESSION_OPENED() \
|
||||
do \
|
||||
{ \
|
||||
GET_OPENED_SESSION(); \
|
||||
if ( pdb_rsess == NULL ) \
|
||||
return pdb_ioctl_error( \
|
||||
poutbuf, poutsize, "Unknown PDB session #%d\n", sid); \
|
||||
} while ( false )
|
||||
|
||||
#define FLUSH_PDB_REQUEST_STORAGE() \
|
||||
do \
|
||||
{ \
|
||||
size_t sz = pdb_rsess->storage.size(); \
|
||||
uint8 *raw = (uint8 *) qalloc(sz); \
|
||||
if ( raw == NULL ) \
|
||||
return pdb_error; \
|
||||
memcpy(raw, pdb_rsess->storage.begin(), sz); \
|
||||
*poutbuf = raw; \
|
||||
*poutsize = sz; \
|
||||
} while ( false )
|
||||
|
||||
case WIN32_IOCTL_PDB_OPEN:
|
||||
{
|
||||
pdb_thread.start_if_needed();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
|
||||
pdb_rsess = new pdb_remote_session_t();
|
||||
pdb_remote_sessions.push_back(pdb_rsess);
|
||||
|
||||
compiler_info_t cci;
|
||||
mmdsr.unpack_obj(&cci, sizeof(cci));
|
||||
pdbargs_t args;
|
||||
args.pdb_path = mmdsr.unpack_str();
|
||||
args.input_path = mmdsr.unpack_str();
|
||||
mmdsr.unpack_obj(&args.pdb_sign, sizeof(args.pdb_sign));
|
||||
args.spath = mmdsr.unpack_str();
|
||||
args.loaded_base = mmdsr.unpack_ea64();
|
||||
args.flags = mmdsr.unpack_dd();
|
||||
pdb_rsess->open(cci, args);
|
||||
bytevec_t storage;
|
||||
storage.pack_dd(pdb_rsess->get_id());
|
||||
*poutsize = storage.size();
|
||||
*poutbuf = storage.extract();
|
||||
pdb_rsess->is_opening = true;
|
||||
}
|
||||
return pdb_ok;
|
||||
|
||||
case WIN32_IOCTL_PDB_OPERATION_COMPLETE:
|
||||
// This is used, in a polling fashion, by the the client,
|
||||
// to check on completeness of the fetch. At the same time,
|
||||
// this is our wake-up call for looking whether the
|
||||
// fetch thread requires more information.
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
|
||||
// If we've got a read request, handle it now
|
||||
if ( pdb_rsess->client_read_request.pending() )
|
||||
handle_pdb_thread_request(pdb_rsess);
|
||||
|
||||
bytevec_t storage;
|
||||
bool done = pdb_rsess->is_done();
|
||||
if ( done )
|
||||
{
|
||||
pdb_rsess->is_opening = false;
|
||||
const char *fname = pdb_rsess->session_ref.session->get_used_fname();
|
||||
local_pdb_access_t *acc = pdb_rsess->session_ref.session->pdb_access;
|
||||
HRESULT hr = acc != NULL ? S_OK : E_FAIL;
|
||||
if ( SUCCEEDED(hr) )
|
||||
{
|
||||
storage.pack_dd(uint32(pdb_op_complete));
|
||||
storage.pack_dd(acc->get_global_symbol_id());
|
||||
storage.pack_dd(acc->get_machine_type());
|
||||
storage.pack_dd(acc->get_dia_version());
|
||||
storage.pack_str(fname);
|
||||
}
|
||||
else
|
||||
{
|
||||
storage.pack_dd(uint32(pdb_op_failure));
|
||||
qstring errmsg;
|
||||
errmsg.sprnt("%s: %s\n", fname, pdberr(hr));
|
||||
storage.pack_str(errmsg.c_str());
|
||||
delete_pdb_session(sid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
storage.pack_dd(uint32(pdb_op_not_complete));
|
||||
}
|
||||
|
||||
*poutsize = storage.size();
|
||||
*poutbuf = storage.extract();
|
||||
return pdb_ok;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_FETCH_SYMBOL:
|
||||
case WIN32_IOCTL_PDB_FETCH_CHILDREN:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
|
||||
DWORD sym_id = mmdsr.unpack_dd();
|
||||
// msg("Fetch%s 0x%x\n",
|
||||
// (fn == WIN32_IOCTL_PDB_FETCH_CHILDREN ? " children for" : ""),
|
||||
// (uint32) sym);
|
||||
bool ok;
|
||||
if ( fn == WIN32_IOCTL_PDB_FETCH_SYMBOL )
|
||||
{
|
||||
// Symbol
|
||||
ok = pdb_rsess->fetch_symbol(sym_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Children
|
||||
enum SymTagEnum children_type = (enum SymTagEnum) mmdsr.unpack_dd();
|
||||
ok = pdb_rsess->fetch_children(sym_id, children_type);
|
||||
}
|
||||
|
||||
if ( ok )
|
||||
FLUSH_PDB_REQUEST_STORAGE();
|
||||
|
||||
return ok ? pdb_ok : pdb_error;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_CLOSE:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
GET_OPENED_SESSION();
|
||||
if ( pdb_rsess != NULL )
|
||||
delete_pdb_session(sid);
|
||||
|
||||
return pdb_ok;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
ea_t va = mmdsr.unpack_ea64();
|
||||
uint64 length = mmdsr.unpack_dq();
|
||||
|
||||
bool ok = pdb_rsess->fetch_lines_by_va(
|
||||
va, length);
|
||||
if ( ok )
|
||||
FLUSH_PDB_REQUEST_STORAGE();
|
||||
return ok ? pdb_ok : pdb_error;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_COORDS:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
|
||||
DWORD file_id = mmdsr.unpack_dd();
|
||||
DWORD lnnum = mmdsr.unpack_dd();
|
||||
DWORD colnum = mmdsr.unpack_dd();
|
||||
bool ok = pdb_rsess->fetch_lines_by_coords(file_id, lnnum, colnum);
|
||||
if ( ok )
|
||||
FLUSH_PDB_REQUEST_STORAGE();
|
||||
return ok ? pdb_ok : pdb_error;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_SYMBOLS_AT_VA:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
|
||||
ea_t va = mmdsr.unpack_ea64();
|
||||
uint64 length = mmdsr.unpack_dq();
|
||||
enum SymTagEnum type = (enum SymTagEnum) mmdsr.unpack_dd();
|
||||
bool ok = pdb_rsess->fetch_symbols_at_va(va, length, type);
|
||||
if ( ok )
|
||||
FLUSH_PDB_REQUEST_STORAGE();
|
||||
return ok ? pdb_ok : pdb_error;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_FILE_COMPILANDS:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
|
||||
uint32 file_id = mmdsr.unpack_dd();
|
||||
bool ok = pdb_rsess->fetch_file_compilands(file_id);
|
||||
if ( ok )
|
||||
FLUSH_PDB_REQUEST_STORAGE();
|
||||
return ok ? pdb_ok : pdb_error;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_FILE_PATH:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
|
||||
uint32 file_id = mmdsr.unpack_dd();
|
||||
bool ok = pdb_rsess->fetch_file_path(file_id);
|
||||
if ( ok )
|
||||
FLUSH_PDB_REQUEST_STORAGE();
|
||||
return ok ? pdb_ok : pdb_error;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_SYMBOL_FILES:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
|
||||
DWORD sym_id = mmdsr.unpack_dd();
|
||||
bool ok = pdb_rsess->fetch_symbol_files(sym_id);
|
||||
if ( ok )
|
||||
FLUSH_PDB_REQUEST_STORAGE();
|
||||
return ok ? pdb_ok : pdb_error;
|
||||
}
|
||||
|
||||
case WIN32_IOCTL_PDB_SIP_FIND_FILES:
|
||||
{
|
||||
ENSURE_PDB_THREAD();
|
||||
memory_deserializer_t mmdsr(buf, size);
|
||||
ENSURE_SESSION_OPENED();
|
||||
|
||||
qstring fname = mmdsr.unpack_str();
|
||||
bool ok = pdb_rsess->fetch_files(fname.c_str());
|
||||
if ( ok )
|
||||
FLUSH_PDB_REQUEST_STORAGE();
|
||||
return ok ? pdb_ok : pdb_error;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
15
idasdk75/dbg/win32/win32_server_stub.cpp
Normal file
15
idasdk75/dbg/win32/win32_server_stub.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
//
|
||||
// This file contains win32 specific implementations of win32_debugger_module class
|
||||
// IDA-side functionality only (for local debugger)
|
||||
//
|
||||
//
|
||||
|
||||
#include <pro.h>
|
||||
#include "win32_debmod.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi win32_debmod_t::handle_ioctl(int /*fn*/, const void * /*buf*/, size_t /*size*/, void ** /*poutbuf*/, ssize_t * /*poutsize*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
128
idasdk75/dbg/win32/win32_stub.cpp
Normal file
128
idasdk75/dbg/win32/win32_stub.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#define REMOTE_DEBUGGER
|
||||
#define RPC_CLIENT
|
||||
|
||||
static const char wanted_name[] = "Remote Windows debugger";
|
||||
|
||||
#define DEBUGGER_NAME "win32"
|
||||
#define PROCESSOR_NAME "metapc"
|
||||
#define DEFAULT_PLATFORM_NAME "win32"
|
||||
#define TARGET_PROCESSOR PLFM_386
|
||||
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_WIN32_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_REMOTE \
|
||||
| DBG_FLAG_EXITSHOTOK \
|
||||
| DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD \
|
||||
| DBG_FLAG_ANYSIZE_HWBPT)
|
||||
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_PE
|
||||
#define win32_term_plugin term_plugin
|
||||
|
||||
#include <pro.h>
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <ua.hpp>
|
||||
#include <range.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <network.hpp>
|
||||
|
||||
#include "w32sehch.h"
|
||||
#include "dbg_rpc_client.h"
|
||||
#include "rpc_debmod.h"
|
||||
|
||||
class win32_rpc_debmod_t : public rpc_debmod_t
|
||||
{
|
||||
typedef rpc_debmod_t inherited;
|
||||
public:
|
||||
win32_rpc_debmod_t(const char *default_platform)
|
||||
: rpc_debmod_t(default_platform) {}
|
||||
|
||||
virtual bool idaapi open_remote(
|
||||
const char *hostname,
|
||||
int port_number,
|
||||
const char *password,
|
||||
qstring *errbuf) override
|
||||
{
|
||||
char path[QMAXPATH];
|
||||
get_input_file_path(path, sizeof(path));
|
||||
pdb_file_path = path;
|
||||
return inherited::open_remote(hostname, port_number, password, errbuf);
|
||||
}
|
||||
|
||||
qstring pdb_file_path;
|
||||
};
|
||||
|
||||
win32_rpc_debmod_t g_dbgmod(DEFAULT_PLATFORM_NAME);
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "pc_local_impl.cpp"
|
||||
#include "win32_local_impl.cpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// handler on IDA: Server -> IDA
|
||||
static int ioctl_handler(
|
||||
rpc_engine_t * /*rpc*/,
|
||||
int fn,
|
||||
const void *buf,
|
||||
size_t size,
|
||||
void **poutbuf,
|
||||
ssize_t *poutsize)
|
||||
{
|
||||
qnotused(size);
|
||||
switch ( fn )
|
||||
{
|
||||
case WIN32_IOCTL_READFILE:
|
||||
{
|
||||
user_cancelled();
|
||||
const uchar *ptr = (const uchar *)buf;
|
||||
const uchar *end = ptr + size;
|
||||
uint64 offset = unpack_dq(&ptr, end);
|
||||
uint32 length = unpack_dd(&ptr, end);
|
||||
|
||||
*poutbuf = NULL;
|
||||
*poutsize = 0;
|
||||
if ( length != 0 )
|
||||
{
|
||||
FILE *infile = qfopen(g_dbgmod.pdb_file_path.c_str(), "rb");
|
||||
if ( infile == NULL )
|
||||
return -2;
|
||||
|
||||
void *outbuf = qalloc(length);
|
||||
if ( outbuf == NULL )
|
||||
return -2;
|
||||
|
||||
qfseek(infile, offset, SEEK_SET);
|
||||
int readlen = qfread(infile, outbuf, length);
|
||||
qfclose(infile);
|
||||
|
||||
if ( readlen < 0 || readlen > length )
|
||||
{
|
||||
qfree(outbuf);
|
||||
return -2;
|
||||
}
|
||||
*poutbuf = outbuf;
|
||||
*poutsize = readlen;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//lint -esym(528,init_plugin) static symbol '' not referenced
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialize Win32 debugger stub
|
||||
static bool init_plugin(void)
|
||||
{
|
||||
// There is no need to call win32_init_plugin() (which checks the PE
|
||||
// file parameters) if the debugger is only being used to fetch PDBs.
|
||||
bool should_init = !netnode(PDB_NODE_NAME).altval(PDB_LOADING_WIN32_DBG);
|
||||
if ( should_init && !win32_init_plugin() )
|
||||
return false;
|
||||
g_dbgmod.set_ioctl_handler(ioctl_handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
#include "common_local_impl.cpp"
|
||||
282
idasdk75/dbg/win32/win32_undoc.h
Normal file
282
idasdk75/dbg/win32/win32_undoc.h
Normal file
@@ -0,0 +1,282 @@
|
||||
|
||||
#ifndef WIN32_UNDOC_H
|
||||
#define WIN32_UNDOC_H
|
||||
|
||||
// Definitions for Windows DDK and other undocumented MS Windows types.
|
||||
// Instead of requiring a DDK and NDK, we just use this file.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// WinDDK types
|
||||
|
||||
struct UNICODE_STRING
|
||||
{
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWCH Buffer;
|
||||
};
|
||||
typedef UNICODE_STRING *PUNICODE_STRING;
|
||||
|
||||
extern "C" char _RTL_CONSTANT_STRING_type_check(const WCHAR *s);
|
||||
// __typeof would be desirable here instead of sizeof.
|
||||
template <size_t N> class _RTL_CONSTANT_STRING_remove_const_template_class;
|
||||
template <> class _RTL_CONSTANT_STRING_remove_const_template_class<sizeof(char)>
|
||||
{
|
||||
public:
|
||||
typedef char T;
|
||||
};
|
||||
template <> class _RTL_CONSTANT_STRING_remove_const_template_class<sizeof(WCHAR)>
|
||||
{
|
||||
public:
|
||||
typedef WCHAR T;
|
||||
};
|
||||
#define _RTL_CONSTANT_STRING_remove_const_macro(s) \
|
||||
(const_cast<_RTL_CONSTANT_STRING_remove_const_template_class<sizeof((s)[0])>::T*>(s))
|
||||
|
||||
#define RTL_CONSTANT_STRING(s) \
|
||||
{ \
|
||||
sizeof(s) - sizeof((s)[0]), \
|
||||
sizeof(s) / sizeof(_RTL_CONSTANT_STRING_type_check(s)), \
|
||||
_RTL_CONSTANT_STRING_remove_const_macro(s) \
|
||||
}
|
||||
|
||||
typedef struct _OBJECT_ATTRIBUTES64
|
||||
{
|
||||
ULONG Length;
|
||||
ULONG64 RootDirectory;
|
||||
ULONG64 ObjectName;
|
||||
ULONG Attributes;
|
||||
ULONG64 SecurityDescriptor;
|
||||
ULONG64 SecurityQualityOfService;
|
||||
} OBJECT_ATTRIBUTES64;
|
||||
typedef OBJECT_ATTRIBUTES64 *POBJECT_ATTRIBUTES64;
|
||||
typedef CONST OBJECT_ATTRIBUTES64 *PCOBJECT_ATTRIBUTES64;
|
||||
|
||||
typedef struct _OBJECT_ATTRIBUTES32
|
||||
{
|
||||
ULONG Length;
|
||||
ULONG RootDirectory;
|
||||
ULONG ObjectName;
|
||||
ULONG Attributes;
|
||||
ULONG SecurityDescriptor;
|
||||
ULONG SecurityQualityOfService;
|
||||
} OBJECT_ATTRIBUTES32;
|
||||
typedef OBJECT_ATTRIBUTES32 *POBJECT_ATTRIBUTES32;
|
||||
typedef CONST OBJECT_ATTRIBUTES32 *PCOBJECT_ATTRIBUTES32;
|
||||
|
||||
typedef struct _OBJECT_ATTRIBUTES
|
||||
{
|
||||
ULONG Length;
|
||||
HANDLE RootDirectory;
|
||||
PUNICODE_STRING ObjectName;
|
||||
ULONG Attributes;
|
||||
PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
|
||||
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
|
||||
} OBJECT_ATTRIBUTES;
|
||||
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
|
||||
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;
|
||||
|
||||
#define InitializeObjectAttributes(p,n,a,r,s) \
|
||||
{ \
|
||||
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
|
||||
(p)->RootDirectory = (r); \
|
||||
(p)->Attributes = (a); \
|
||||
(p)->ObjectName = (n); \
|
||||
(p)->SecurityDescriptor = (s); \
|
||||
(p)->SecurityQualityOfService = NULL; \
|
||||
}
|
||||
|
||||
//
|
||||
// Definitions for Object Creation
|
||||
//
|
||||
#define OBJ_INHERIT 0x00000002L
|
||||
#define OBJ_PERMANENT 0x00000010L
|
||||
#define OBJ_EXCLUSIVE 0x00000020L
|
||||
#define OBJ_CASE_INSENSITIVE 0x00000040L
|
||||
#define OBJ_OPENIF 0x00000080L
|
||||
#define OBJ_OPENLINK 0x00000100L
|
||||
#define OBJ_KERNEL_HANDLE 0x00000200L
|
||||
#define OBJ_FORCE_ACCESS_CHECK 0x00000400L
|
||||
#define OBJ_VALID_ATTRIBUTES 0x000007F2L
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Undocumented types - pulled out of MS Windows NDK by Alex Ionecsu
|
||||
|
||||
//
|
||||
// Privilege constants
|
||||
//
|
||||
#define SE_MIN_WELL_KNOWN_PRIVILEGE (2L)
|
||||
#define SE_CREATE_TOKEN_PRIVILEGE (2L)
|
||||
#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE (3L)
|
||||
#define SE_LOCK_MEMORY_PRIVILEGE (4L)
|
||||
#define SE_INCREASE_QUOTA_PRIVILEGE (5L)
|
||||
#define SE_UNSOLICITED_INPUT_PRIVILEGE (6L)
|
||||
#define SE_MACHINE_ACCOUNT_PRIVILEGE (6L)
|
||||
#define SE_TCB_PRIVILEGE (7L)
|
||||
#define SE_SECURITY_PRIVILEGE (8L)
|
||||
#define SE_TAKE_OWNERSHIP_PRIVILEGE (9L)
|
||||
#define SE_LOAD_DRIVER_PRIVILEGE (10L)
|
||||
#define SE_SYSTEM_PROFILE_PRIVILEGE (11L)
|
||||
#define SE_SYSTEMTIME_PRIVILEGE (12L)
|
||||
#define SE_PROF_SINGLE_PROCESS_PRIVILEGE (13L)
|
||||
#define SE_INC_BASE_PRIORITY_PRIVILEGE (14L)
|
||||
#define SE_CREATE_PAGEFILE_PRIVILEGE (15L)
|
||||
#define SE_CREATE_PERMANENT_PRIVILEGE (16L)
|
||||
#define SE_BACKUP_PRIVILEGE (17L)
|
||||
#define SE_RESTORE_PRIVILEGE (18L)
|
||||
#define SE_SHUTDOWN_PRIVILEGE (19L)
|
||||
#define SE_DEBUG_PRIVILEGE (20L)
|
||||
#define SE_AUDIT_PRIVILEGE (21L)
|
||||
#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L)
|
||||
#define SE_CHANGE_NOTIFY_PRIVILEGE (23L)
|
||||
#define SE_REMOTE_SHUTDOWN_PRIVILEGE (24L)
|
||||
#define SE_MAX_WELL_KNOWN_PRIVILEGE (SE_REMOTE_SHUTDOWN_PRIVILEGE)
|
||||
|
||||
|
||||
// Undocumented NTSystemDebugControl function (to read/write MSRs)
|
||||
enum SYSDBG_COMMAND
|
||||
{
|
||||
SysDbgQueryModuleInformation = 1,
|
||||
SysDbgQueryTraceInformation = 2,
|
||||
SysDbgSetTracepoint = 3,
|
||||
SysDbgSetSpecialCall = 4,
|
||||
SysDbgClearSpecialCalls = 5,
|
||||
SysDbgQuerySpecialCalls = 6,
|
||||
SysDbgReadMsr = 16,
|
||||
SysDbgWriteMsr = 17,
|
||||
};
|
||||
|
||||
struct SYSDBG_MSR
|
||||
{
|
||||
uint32 reg;
|
||||
uint32 padding;
|
||||
uint64 value;
|
||||
};
|
||||
#define NTSTATUS int
|
||||
#ifndef NTAPI
|
||||
#define NTAPI WINAPI
|
||||
#endif
|
||||
|
||||
#ifndef STATUS_NOT_IMPLEMENTED
|
||||
#define STATUS_NOT_IMPLEMENTED 0xC0000002
|
||||
#endif
|
||||
|
||||
#ifndef STATUS_IMAGE_ALREADY_LOADED
|
||||
#define STATUS_IMAGE_ALREADY_LOADED 0xC000010E
|
||||
#endif
|
||||
|
||||
//
|
||||
// NtCreateFile OpenType Flags
|
||||
//
|
||||
#define FILE_SUPERSEDE 0x00000000
|
||||
#define FILE_OPEN 0x00000001
|
||||
#define FILE_CREATE 0x00000002
|
||||
#define FILE_OPEN_IF 0x00000003
|
||||
#define FILE_OVERWRITE 0x00000004
|
||||
#define FILE_OVERWRITE_IF 0x00000005
|
||||
#define FILE_MAXIMUM_DISPOSITION 0x00000005
|
||||
|
||||
//
|
||||
// NtCreateFile Flags
|
||||
//
|
||||
#define FILE_DIRECTORY_FILE 0x00000001
|
||||
#define FILE_WRITE_THROUGH 0x00000002
|
||||
#define FILE_SEQUENTIAL_ONLY 0x00000004
|
||||
#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008
|
||||
#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
|
||||
#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
|
||||
#define FILE_NON_DIRECTORY_FILE 0x00000040
|
||||
#define FILE_CREATE_TREE_CONNECTION 0x00000080
|
||||
#define FILE_COMPLETE_IF_OPLOCKED 0x00000100
|
||||
#define FILE_NO_EA_KNOWLEDGE 0x00000200
|
||||
#define FILE_OPEN_FOR_RECOVERY 0x00000400
|
||||
#define FILE_RANDOM_ACCESS 0x00000800
|
||||
#define FILE_DELETE_ON_CLOSE 0x00001000
|
||||
#define FILE_OPEN_BY_FILE_ID 0x00002000
|
||||
#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
|
||||
#define FILE_NO_COMPRESSION 0x00008000
|
||||
#define FILE_RESERVE_OPFILTER 0x00100000
|
||||
#define FILE_OPEN_REPARSE_POINT 0x00200000
|
||||
#define FILE_OPEN_NO_RECALL 0x00400000
|
||||
#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
|
||||
|
||||
//
|
||||
// Interface for communicating with private WinDBG interface
|
||||
//
|
||||
#define KLDD_CODE_DEBUG_CONTROL \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
|
||||
|
||||
typedef struct _KLDD_DATA_DEBUG_CONTROL
|
||||
{
|
||||
SYSDBG_COMMAND Command;
|
||||
PVOID InputBuffer;
|
||||
SIZE_T InputBufferLength;
|
||||
} KLDD_DATA_DEBUG_CONTROL, *PKLDD_DATA_DEBUG_CONTROL;
|
||||
|
||||
//
|
||||
// I/O Status Block
|
||||
//
|
||||
typedef struct _IO_STATUS_BLOCK
|
||||
{
|
||||
union
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PVOID Pointer;
|
||||
};
|
||||
ULONG_PTR Information;
|
||||
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||
|
||||
//
|
||||
// APC Callback for NtDeviceIoControlFile
|
||||
//
|
||||
typedef VOID
|
||||
(NTAPI *PIO_APC_ROUTINE)(
|
||||
IN PVOID ApcContext,
|
||||
IN PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG Reserved);
|
||||
|
||||
typedef NTSTATUS NTAPI NtSystemDebugControl_t(
|
||||
IN SYSDBG_COMMAND Command,
|
||||
IN PVOID InputBuffer OPTIONAL,
|
||||
IN ULONG InputBufferLength,
|
||||
OUT PVOID OutputBuffer OPTIONAL,
|
||||
IN ULONG OutputBufferLength,
|
||||
OUT PULONG ReturnLength OPTIONAL);
|
||||
|
||||
typedef NTSTATUS NTAPI NtLoadDriver_t(
|
||||
IN PUNICODE_STRING DriverServiceName);
|
||||
|
||||
typedef NTSTATUS NTAPI NtUnloadDriver_t(
|
||||
IN PUNICODE_STRING DriverServiceName);
|
||||
|
||||
typedef NTSTATUS NTAPI RtlAdjustPrivilege_t(
|
||||
IN ULONG Privilege,
|
||||
IN BOOLEAN NewValue,
|
||||
IN BOOLEAN ForThread,
|
||||
OUT PBOOLEAN OldValue);
|
||||
|
||||
typedef NTSTATUS NTAPI NtCreateFile_t(
|
||||
OUT PHANDLE FileHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN PLARGE_INTEGER AllocationSize OPTIONAL,
|
||||
IN ULONG FileAttributes,
|
||||
IN ULONG ShareAccess,
|
||||
IN ULONG CreateDisposition,
|
||||
IN ULONG CreateOptions,
|
||||
IN PVOID EaBuffer OPTIONAL,
|
||||
IN ULONG EaLength);
|
||||
|
||||
typedef NTSTATUS NTAPI NtDeviceIoControlFile_t(
|
||||
IN HANDLE DeviceHandle,
|
||||
IN HANDLE Event OPTIONAL,
|
||||
IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
|
||||
IN PVOID UserApcContext OPTIONAL,
|
||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG IoControlCode,
|
||||
IN PVOID InputBuffer,
|
||||
IN ULONG InputBufferSize,
|
||||
OUT PVOID OutputBuffer,
|
||||
IN ULONG OutputBufferSize);
|
||||
|
||||
#endif // define WIN32_UNDOC_H
|
||||
46
idasdk75/dbg/win32/win32_user.cpp
Normal file
46
idasdk75/dbg/win32/win32_user.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
This is main source code for the local win32 debugger module
|
||||
*/
|
||||
|
||||
static const char wanted_name[] = "Local Windows debugger";
|
||||
|
||||
#define DEBUGGER_NAME "win32"
|
||||
#define PROCESSOR_NAME "metapc"
|
||||
#define TARGET_PROCESSOR PLFM_386
|
||||
#define DEBUGGER_ID DEBUGGER_ID_X86_IA32_WIN32_USER
|
||||
#define DEBUGGER_FLAGS (DBG_FLAG_EXITSHOTOK \
|
||||
| DBG_FLAG_LOWCNDS \
|
||||
| DBG_FLAG_DEBTHREAD \
|
||||
| DBG_FLAG_ANYSIZE_HWBPT)
|
||||
#define DEBUGGER_RESMOD (DBG_RESMOD_STEP_INTO)
|
||||
|
||||
#define HAVE_APPCALL
|
||||
#define S_FILETYPE f_PE
|
||||
|
||||
// We must rename those method because common files
|
||||
// refer to them as init_plugin/term_plugin
|
||||
// Some other debugger modules compatible with win32
|
||||
// have their own init/term and still call win32_init/term
|
||||
// (since no renaming takes place)
|
||||
#define win32_init_plugin init_plugin
|
||||
#define win32_term_plugin term_plugin
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <objidl.h>
|
||||
|
||||
#include <fpro.h>
|
||||
#include <ua.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <loader.hpp>
|
||||
#include "win32_debmod.h"
|
||||
#include "w32sehch.h"
|
||||
|
||||
win32_debmod_t g_dbgmod;
|
||||
#include "common_stub_impl.cpp"
|
||||
|
||||
#include "pc_local_impl.cpp"
|
||||
#include "win32_local_impl.cpp"
|
||||
#include "common_local_impl.cpp"
|
||||
|
||||
#include "win32_server_stub.cpp"
|
||||
87
idasdk75/dbg/win32/win32_util.cpp
Normal file
87
idasdk75/dbg/win32/win32_util.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <windows.h>
|
||||
#include <pro.h>
|
||||
#include "winbase_debmod.h"
|
||||
#include "win32_util.hpp"
|
||||
|
||||
#ifndef __X86__
|
||||
typedef BOOL WINAPI IsWow64Process_t(HANDLE, PBOOL);
|
||||
static IsWow64Process_t *_IsWow64Process = NULL;
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(818,handle) could be pointer to const
|
||||
wow64_state_t check_wow64_handle(HANDLE handle)
|
||||
{
|
||||
#ifdef __X86__
|
||||
qnotused(handle);
|
||||
#else
|
||||
if ( _IsWow64Process == NULL )
|
||||
{
|
||||
HMODULE k32 = GetModuleHandle(kernel32_dll);
|
||||
*(FARPROC*)&_IsWow64Process = GetProcAddress(k32, TEXT("IsWow64Process"));
|
||||
if ( _IsWow64Process == NULL )
|
||||
return WOW64_NONE; // unknown
|
||||
}
|
||||
BOOL bIsWow64 = FALSE;
|
||||
if ( _IsWow64Process(handle, &bIsWow64) && bIsWow64 != 0 )
|
||||
return WOW64_YES;
|
||||
#endif
|
||||
return WOW64_NO;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
wow64_state_t check_wow64_pid(int pid)
|
||||
{
|
||||
wow64_state_t r = WOW64_BAD; // assume pid is bad
|
||||
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if ( h != NULL )
|
||||
{
|
||||
r = check_wow64_handle(h);
|
||||
CloseHandle(h);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996) // GetVersionEx was declared deprecated
|
||||
#endif
|
||||
win_version_t::win_version_t()
|
||||
{
|
||||
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
|
||||
ver_ok = GetVersionEx(&OSVersionInfo) != 0; //lint !e2586 is deprecated
|
||||
#ifdef __X86__
|
||||
is_64bit_os = false;
|
||||
if ( OSVersionInfo.dwMajorVersion > 5
|
||||
|| OSVersionInfo.dwMajorVersion == 5 && OSVersionInfo.dwMinorVersion >= 1 )
|
||||
{
|
||||
is_64bit_os = check_wow64_handle(GetCurrentProcess()) > 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
win_tool_help_t::win_tool_help_t()
|
||||
{
|
||||
use_debug_break = qgetenv("IDA_DEBUGBREAKPROCESS");
|
||||
HMODULE kern_handle = GetModuleHandle(kernel32_dll);
|
||||
*(FARPROC*)&_DebugActiveProcessStop = GetProcAddress(kern_handle, TEXT("DebugActiveProcessStop"));
|
||||
*(FARPROC*)&_DebugBreakProcess = GetProcAddress(kern_handle, TEXT("DebugBreakProcess"));
|
||||
|
||||
// find the needed functions
|
||||
*(FARPROC*)&_CreateToolhelp32Snapshot = GetProcAddress(kern_handle, TEXT("CreateToolhelp32Snapshot"));
|
||||
*(FARPROC*)&_Process32First = GetProcAddress(kern_handle, TEXT("Process32First"));
|
||||
*(FARPROC*)&_Process32Next = GetProcAddress(kern_handle, TEXT("Process32Next"));
|
||||
*(FARPROC*)&_Module32First = GetProcAddress(kern_handle, TEXT("Module32First"));
|
||||
*(FARPROC*)&_Module32Next = GetProcAddress(kern_handle, TEXT("Module32Next"));
|
||||
|
||||
inited = _CreateToolhelp32Snapshot != NULL
|
||||
&& _Process32First != NULL
|
||||
&& _Process32Next != NULL
|
||||
&& _Module32First != NULL
|
||||
&& _Module32Next != NULL;
|
||||
}
|
||||
347
idasdk75/dbg/win32/win32_util.hpp
Normal file
347
idasdk75/dbg/win32/win32_util.hpp
Normal file
@@ -0,0 +1,347 @@
|
||||
//
|
||||
// Wrapper for Windows ToolHelp library: enumerate processes/modules
|
||||
//
|
||||
// PSAPI.DLL: NT, 2K, XP/2K3
|
||||
// KERNEL32.DLL (ToolHelp functions): 9X, ME, 2K, XP/2K3
|
||||
//? add NT support
|
||||
|
||||
#ifndef __TOOLHELP_HPP__
|
||||
#define __TOOLHELP_HPP__
|
||||
|
||||
#ifdef __NT__
|
||||
|
||||
#include <windows.h>
|
||||
#include <Tlhelp32.h>
|
||||
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include <segment.hpp>
|
||||
|
||||
#ifdef UNICODE
|
||||
#define LookupPrivilegeValue_Name "LookupPrivilegeValueW"
|
||||
#else
|
||||
#define LookupPrivilegeValue_Name "LookupPrivilegeValueA"
|
||||
#endif
|
||||
|
||||
#ifndef TH32CS_SNAPNOHEAPS
|
||||
# define TH32CS_SNAPNOHEAPS 0x0
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum wow64_state_t
|
||||
{
|
||||
WOW64_NONE = -2, // unknown yet
|
||||
WOW64_BAD = -1,
|
||||
WOW64_NO = 0,
|
||||
WOW64_YES = 1,
|
||||
};
|
||||
|
||||
wow64_state_t check_wow64_handle(HANDLE handle);
|
||||
wow64_state_t check_wow64_pid(int pid);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class win_version_t
|
||||
{
|
||||
public:
|
||||
win_version_t();
|
||||
const OSVERSIONINFO &get_info() const { return OSVersionInfo; }
|
||||
bool ok() { return ver_ok; }
|
||||
bool is_NT()
|
||||
{
|
||||
return ok() && OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT;
|
||||
}
|
||||
bool is_strictly_xp() // Is strictly XP (32bit)?
|
||||
{
|
||||
return ok()
|
||||
&& is_NT()
|
||||
&& OSVersionInfo.dwMajorVersion == 5
|
||||
&& OSVersionInfo.dwMinorVersion == 1;
|
||||
}
|
||||
bool is_DW32()
|
||||
{
|
||||
return ok() && OSVersionInfo.dwPlatformId == 3;
|
||||
}
|
||||
bool is_2K() // Is at least Win2K?
|
||||
{
|
||||
return ok() && OSVersionInfo.dwMajorVersion >= 5;
|
||||
}
|
||||
bool is_64bitOS()
|
||||
{
|
||||
#ifndef __X86__
|
||||
return true;
|
||||
#else
|
||||
return is_64bit_os;
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// GetProcessDEPPolicy() is broken for Win8, Win8.1, Win10:
|
||||
// always set *lpPermanent == CL register, if not permanently policy.
|
||||
// https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/05683d76-3c8a-49de-91e3-9d7ab8492f39/getprocessdeppolicy-does-not-set-the-correct-value-to-lppermanent?forum=windowscompatibility
|
||||
bool is_GetProcessDEPPolicy_broken()
|
||||
{
|
||||
return ok()
|
||||
&& ((OSVersionInfo.dwMajorVersion == 10 && OSVersionInfo.dwMinorVersion == 0) // Windows 10
|
||||
|| (OSVersionInfo.dwMajorVersion == 6 && OSVersionInfo.dwMinorVersion == 3) // Windows 8.1
|
||||
|| (OSVersionInfo.dwMajorVersion == 6 && OSVersionInfo.dwMinorVersion == 2)); // Windows 8
|
||||
}
|
||||
|
||||
private:
|
||||
OSVERSIONINFO OSVersionInfo;
|
||||
bool ver_ok;
|
||||
#ifdef __X86__
|
||||
bool is_64bit_os;
|
||||
#endif
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-V:win_tool_help_t:730 Not all members of a class are initialized inside the constructor
|
||||
class win_tool_help_t
|
||||
{
|
||||
public:
|
||||
win_tool_help_t();
|
||||
bool ok() { return inited; }
|
||||
bool use_debug_break_process();
|
||||
bool debug_break_process(HANDLE process_handle);
|
||||
bool use_debug_detach_process();
|
||||
bool debug_detach_process(pid_t pid);
|
||||
|
||||
private:
|
||||
// function prototypes
|
||||
typedef HANDLE WINAPI CreateToolhelp32Snapshot_t(DWORD dwFlags, DWORD th32ProcessID);
|
||||
typedef BOOL WINAPI Process32First_t(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
|
||||
typedef BOOL WINAPI Process32Next_t(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
|
||||
typedef BOOL WINAPI Module32First_t(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
|
||||
typedef BOOL WINAPI Module32Next_t(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
|
||||
typedef BOOL WINAPI DebugActiveProcessStop_t(DWORD dwProcessID);
|
||||
typedef BOOL WINAPI DebugBreakProcess_t(HANDLE Process);
|
||||
typedef BOOL WINAPI CloseToolhelp32Snapshot_t(HANDLE hSnapshot);
|
||||
|
||||
// functions pointers
|
||||
CreateToolhelp32Snapshot_t *_CreateToolhelp32Snapshot;
|
||||
Process32First_t *_Process32First;
|
||||
Process32Next_t *_Process32Next;
|
||||
Module32First_t *_Module32First;
|
||||
Module32Next_t *_Module32Next;
|
||||
DebugActiveProcessStop_t *_DebugActiveProcessStop;
|
||||
DebugBreakProcess_t *_DebugBreakProcess;
|
||||
|
||||
bool inited;
|
||||
bool use_debug_break;
|
||||
|
||||
friend class toolhelp_snapshot_t;
|
||||
friend class process_snapshot_t;
|
||||
friend class module_snapshot_t;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class toolhelp_snapshot_t
|
||||
{
|
||||
public:
|
||||
inline toolhelp_snapshot_t(win_tool_help_t *tool);
|
||||
inline ~toolhelp_snapshot_t();
|
||||
inline bool ok();
|
||||
inline bool open(uint32 flags, pid_t pid);
|
||||
inline void close();
|
||||
inline uint32 last_err();
|
||||
protected:
|
||||
bool seterr(); // always returns 'false' for convenience
|
||||
win_tool_help_t *t;
|
||||
HANDLE h;
|
||||
uint32 last_error;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class process_snapshot_t: public toolhelp_snapshot_t
|
||||
{
|
||||
public:
|
||||
inline process_snapshot_t(win_tool_help_t *tool);
|
||||
inline bool first(uint32 flags, LPPROCESSENTRY32 lppe);
|
||||
inline bool next(LPPROCESSENTRY32 lppe);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class module_snapshot_t: public toolhelp_snapshot_t
|
||||
{
|
||||
public:
|
||||
inline module_snapshot_t(win_tool_help_t *tool);
|
||||
inline bool first(uint32 flags, pid_t pid, LPMODULEENTRY32 lpme);
|
||||
inline bool next(LPMODULEENTRY32 lpme);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool win_tool_help_t::use_debug_break_process()
|
||||
{
|
||||
return use_debug_break && _DebugBreakProcess != NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool win_tool_help_t::debug_break_process(HANDLE process_handle)
|
||||
{
|
||||
return process_handle != INVALID_HANDLE_VALUE && _DebugBreakProcess(process_handle);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool win_tool_help_t::use_debug_detach_process()
|
||||
{
|
||||
return _DebugActiveProcessStop != NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool win_tool_help_t::debug_detach_process(pid_t pid)
|
||||
{
|
||||
return _DebugActiveProcessStop != NULL && _DebugActiveProcessStop(pid);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline process_snapshot_t::process_snapshot_t(win_tool_help_t *tool)
|
||||
: toolhelp_snapshot_t(tool)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool process_snapshot_t::first(uint32 flags, LPPROCESSENTRY32 lppe)
|
||||
{
|
||||
open(TH32CS_SNAPPROCESS | flags, 0);
|
||||
lppe->dwSize = sizeof(PROCESSENTRY32);
|
||||
if ( ok() && t->_Process32First(h, lppe) )
|
||||
{
|
||||
// ignore "System Process" (ID==0)
|
||||
return lppe->th32ProcessID != 0 || next(lppe);
|
||||
}
|
||||
return seterr();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool process_snapshot_t::next(LPPROCESSENTRY32 lppe)
|
||||
{
|
||||
while ( ok() )
|
||||
{
|
||||
if ( !t->_Process32Next(h, lppe) )
|
||||
break;
|
||||
// ignore "System Process" (ID==0)
|
||||
if ( lppe->th32ProcessID != 0 )
|
||||
return true;
|
||||
}
|
||||
return seterr();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline module_snapshot_t::module_snapshot_t(win_tool_help_t *tool)
|
||||
: toolhelp_snapshot_t(tool)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool module_snapshot_t::first(uint32 flags, pid_t pid, LPMODULEENTRY32 lpme)
|
||||
{
|
||||
wow64_state_t state = check_wow64_pid(pid);
|
||||
flags |= state == WOW64_YES ? TH32CS_SNAPMODULE32 : 0;
|
||||
if ( !open(TH32CS_SNAPMODULE | flags, pid) )
|
||||
return false;
|
||||
lpme->dwSize = sizeof(MODULEENTRY32);
|
||||
if ( t->_Module32First(h, lpme) )
|
||||
return true;
|
||||
return seterr();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool module_snapshot_t::next(LPMODULEENTRY32 lpme)
|
||||
{
|
||||
if ( ok() )
|
||||
return false;
|
||||
if ( t->_Module32Next(h, lpme) )
|
||||
return true;
|
||||
seterr();
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline toolhelp_snapshot_t::toolhelp_snapshot_t(win_tool_help_t *tool)
|
||||
: t(tool), h(INVALID_HANDLE_VALUE), last_error(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline toolhelp_snapshot_t::~toolhelp_snapshot_t()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool toolhelp_snapshot_t::ok()
|
||||
{
|
||||
return h != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// // always returns 'false' for convenience
|
||||
inline bool toolhelp_snapshot_t::seterr()
|
||||
{
|
||||
last_error = GetLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// // always returns 'false' for convenience
|
||||
inline uint32 toolhelp_snapshot_t::last_err()
|
||||
{
|
||||
return last_error;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline bool toolhelp_snapshot_t::open(uint32 flags, pid_t pid)
|
||||
{
|
||||
if ( !t->ok() )
|
||||
return false;
|
||||
close();
|
||||
for ( int cnt=0; cnt < 5; cnt++ )
|
||||
{
|
||||
h = t->_CreateToolhelp32Snapshot(flags, pid);
|
||||
if ( h != INVALID_HANDLE_VALUE )
|
||||
return true;
|
||||
seterr();
|
||||
// MSDN: If the function fails with ERROR_BAD_LENGTH, retry
|
||||
// the function until it succeeds.
|
||||
if ( last_err() != ERROR_BAD_LENGTH
|
||||
|| (flags & (TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32)) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void toolhelp_snapshot_t::close()
|
||||
{
|
||||
if ( t->ok() && h != INVALID_HANDLE_VALUE )
|
||||
CloseHandle(h);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// convert Windows protection modes to IDA protection modes
|
||||
inline uchar win_prot_to_ida_perm(DWORD protection)
|
||||
{
|
||||
uchar perm = 0;
|
||||
|
||||
if ( protection & PAGE_READONLY )
|
||||
perm |= SEGPERM_READ;
|
||||
if ( protection & PAGE_READWRITE )
|
||||
perm |= SEGPERM_READ | SEGPERM_WRITE;
|
||||
if ( protection & PAGE_WRITECOPY )
|
||||
perm |= SEGPERM_READ | SEGPERM_WRITE;
|
||||
if ( protection & PAGE_EXECUTE )
|
||||
perm |= SEGPERM_EXEC;
|
||||
if ( protection & PAGE_EXECUTE_READ )
|
||||
perm |= SEGPERM_READ | SEGPERM_EXEC;
|
||||
if ( protection & PAGE_EXECUTE_READWRITE )
|
||||
perm |= SEGPERM_READ | SEGPERM_WRITE | SEGPERM_EXEC;
|
||||
if ( protection & PAGE_EXECUTE_WRITECOPY )
|
||||
perm |= SEGPERM_READ | SEGPERM_WRITE | SEGPERM_EXEC;
|
||||
|
||||
return perm;
|
||||
}
|
||||
|
||||
#endif // __NT__
|
||||
#endif // __TOOLHELP_HPP__
|
||||
619
idasdk75/dbg/win32/winbase_debmod.cpp
Normal file
619
idasdk75/dbg/win32/winbase_debmod.cpp
Normal file
@@ -0,0 +1,619 @@
|
||||
#include <windows.h>
|
||||
#include <ida.hpp>
|
||||
#include "winbase_debmod.h"
|
||||
|
||||
#ifndef __X86__
|
||||
#define IDA_ADDRESS_SIZE 8
|
||||
#else
|
||||
#define IDA_ADDRESS_SIZE 4
|
||||
#endif
|
||||
|
||||
const TCHAR kernel32_dll[] = TEXT("kernel32.dll");
|
||||
|
||||
typedef BOOL WINAPI GetProcessDEPPolicy_t(HANDLE hProcess, LPDWORD lpFlags, PBOOL lpPermanent);
|
||||
static GetProcessDEPPolicy_t *_GetProcessDEPPolicy = NULL;
|
||||
|
||||
typedef dep_policy_t WINAPI GetSystemDEPPolicy_t(void);
|
||||
static GetSystemDEPPolicy_t *_GetSystemDEPPolicy = NULL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
winbase_debmod_t::winbase_debmod_t(void)
|
||||
: is_wow64(WOW64_NONE),
|
||||
process_handle(INVALID_HANDLE_VALUE),
|
||||
dep_policy(dp_always_off),
|
||||
highdlls()
|
||||
{
|
||||
HMODULE k32 = GetModuleHandle(kernel32_dll);
|
||||
|
||||
if ( _GetProcessDEPPolicy == NULL )
|
||||
*(FARPROC*)&_GetProcessDEPPolicy = GetProcAddress(k32, TEXT("GetProcessDEPPolicy"));
|
||||
|
||||
if ( _GetSystemDEPPolicy == NULL )
|
||||
*(FARPROC*)&_GetSystemDEPPolicy = GetProcAddress(k32, TEXT("GetSystemDEPPolicy"));
|
||||
|
||||
if ( _GetSystemDEPPolicy != NULL )
|
||||
dep_policy = _GetSystemDEPPolicy();
|
||||
|
||||
win_tool_help = NULL;
|
||||
set_platform("win32");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Prepare new page protections for a breakpoint of BPTTYPE.
|
||||
// Use INPUT as starting page protections.
|
||||
// Return false in the case of failure.
|
||||
bool winbase_debmod_t::remove_page_protections(
|
||||
DWORD *p_input,
|
||||
bpttype_t bpttype,
|
||||
dep_policy_t dpolicy,
|
||||
HANDLE proc_handle)
|
||||
{
|
||||
// If PAGE_GUARD is already set, do not change anything, it is already ok
|
||||
DWORD input = *p_input;
|
||||
if ( (input & PAGE_GUARD) != 0 )
|
||||
return false;
|
||||
|
||||
// Convert between Unix permissions and Win32 page protections using this array:
|
||||
static const uchar win32_page_protections[] =
|
||||
{
|
||||
PAGE_NOACCESS, // 000
|
||||
PAGE_READONLY, // 001
|
||||
0xFF, // 010 WRITE_ONLY does not exist on win32
|
||||
PAGE_READWRITE, // 011
|
||||
PAGE_EXECUTE, // 100
|
||||
PAGE_EXECUTE_READ, // 101
|
||||
0xFF, // 110 EXECUTE_WRITE does not exist on win32
|
||||
PAGE_EXECUTE_READWRITE, // 111
|
||||
};
|
||||
uchar unix;
|
||||
// convert ..COPY page protections into their non-copy counterparts
|
||||
// this is the best thing we can do with them because they are automatically
|
||||
// converted by the system upon a write access
|
||||
if ( (input & PAGE_WRITECOPY) != 0 )
|
||||
{
|
||||
unix = 3; // rw
|
||||
}
|
||||
else if ( (input & PAGE_EXECUTE_WRITECOPY) != 0 )
|
||||
{
|
||||
unix = 7; // rwx
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( unix=0; unix < 8; unix++ )
|
||||
{
|
||||
uchar p = win32_page_protections[unix];
|
||||
if ( p != 0xFF && (input & p) != 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
QASSERT(622, unix < 8);
|
||||
|
||||
// convert bpttype into unix permissions
|
||||
int del = 0;
|
||||
if ( (bpttype & BPT_READ) != 0 )
|
||||
del |= 1;
|
||||
if ( (bpttype & BPT_WRITE) != 0 )
|
||||
del |= 2;
|
||||
if ( (bpttype & BPT_EXEC) != 0 )
|
||||
{
|
||||
del |= 4;
|
||||
// if DEP is disabled for this process then a program can
|
||||
// happily execute code in a read only area so we need to
|
||||
// remove *all* privileges, unfortunately
|
||||
if ( dpolicy != dp_always_on )
|
||||
{
|
||||
// on XP, GetProcessDEPPolicy returns DEP policy for current process (i.e. the debugger)
|
||||
// so we can't use it
|
||||
// assume that DEP is disabled by default
|
||||
DWORD flags = 0;
|
||||
BOOL permanent = 0;
|
||||
if ( _GetProcessDEPPolicy == NULL
|
||||
|| winver.is_strictly_xp()
|
||||
|| winver.is_GetProcessDEPPolicy_broken()
|
||||
|| _GetProcessDEPPolicy(proc_handle, &flags, &permanent) )
|
||||
{
|
||||
// flags == 0: DEP is disabled for the specified process.
|
||||
//
|
||||
// Remarks: if permanent == 0 and global DEP policy is OptIn
|
||||
// flags may be equal to 1 *but* having DEP disabled because,
|
||||
// in case the process called SetProcessDEPPolicy the
|
||||
// permanent argument would be 1, it seems to be a bug in the
|
||||
// documentation
|
||||
if ( (dpolicy == dp_opt_in && permanent == 0) || flags == 0 )
|
||||
del |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the access types to trigger on
|
||||
unix &= ~del;
|
||||
|
||||
// Handle WRITE_ONLY and EXECUTE_WRITE cases because win32 does not have them.
|
||||
// We use stricter page permissions for them. This means that there will
|
||||
// be more useless exceptions but we cannot do much about it.
|
||||
if ( unix == 2 || unix == 6 )
|
||||
unix = 0; // use PAGE_NOACCESS instead of WRITE_ONLY or EXECUTE_WRITE
|
||||
|
||||
uchar perm = win32_page_protections[unix];
|
||||
*p_input = (input & ~0xFF) | perm;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi winbase_debmod_t::dbg_enable_page_bpt(
|
||||
page_bpts_t::iterator p,
|
||||
bool enable)
|
||||
{
|
||||
pagebpt_data_t &bpt = p->second;
|
||||
if ( (bpt.old_prot != 0) == enable )
|
||||
return false; // already the desired state
|
||||
|
||||
debdeb("dbg_enable_page_bpt(%s): page_ea=%a, old_prot=0x%x, new_prot=0x%x\n", enable ? "true" : "false", bpt.page_ea, bpt.old_prot, bpt.new_prot);
|
||||
|
||||
DWORD old;
|
||||
DWORD prot = enable ? bpt.new_prot : bpt.old_prot;
|
||||
if ( !VirtualProtectEx(process_handle, (void*)(size_t)bpt.page_ea,
|
||||
bpt.real_len, prot, &old) )
|
||||
{
|
||||
deberr("VirtualProtectEx");
|
||||
// if the page disappeared while disabling a bpt, do not complain,
|
||||
// silently return success
|
||||
if ( enable )
|
||||
return false;
|
||||
old = 0;
|
||||
}
|
||||
|
||||
debdeb(" success! old=0x%x\n", old);
|
||||
|
||||
bpt.old_prot = enable ? old : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Should we generate a BREAKPOINT event because of page bpt?
|
||||
//lint -e{1746} could be made const reference
|
||||
bool should_fire_page_bpt(
|
||||
page_bpts_t::iterator p,
|
||||
ea_t ea,
|
||||
DWORD failed_access_type,
|
||||
ea_t pc,
|
||||
dep_policy_t dep_policy)
|
||||
{
|
||||
const pagebpt_data_t &bpt = p->second;
|
||||
if ( !interval::contains(bpt.ea, bpt.user_len, ea) )
|
||||
return false; // not in the user-defined interval
|
||||
|
||||
int bit;
|
||||
switch ( failed_access_type )
|
||||
{
|
||||
default:
|
||||
INTERR(623); //-V796 no break
|
||||
case EXCEPTION_READ_FAULT: // failed READ access
|
||||
// depending on the DEP policy we mark this access also
|
||||
// to be triggered in case of EXEC breakpoints
|
||||
bit = BPT_READ;
|
||||
if ( dep_policy != dp_always_on && bpt.type == BPT_EXEC && pc == ea )
|
||||
bit |= BPT_EXEC;
|
||||
break;
|
||||
case EXCEPTION_WRITE_FAULT: // failed WRITE access
|
||||
bit = BPT_WRITE;
|
||||
break;
|
||||
case EXCEPTION_EXECUTE_FAULT: // failed EXECUTE access
|
||||
bit = BPT_EXEC;
|
||||
break;
|
||||
}
|
||||
return (bpt.type & bit) != 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// returns 0-failure, 2-success
|
||||
int idaapi winbase_debmod_t::dbg_add_page_bpt(
|
||||
bpttype_t type,
|
||||
ea_t ea,
|
||||
int size)
|
||||
{
|
||||
// only one page breakpoint per page is permitted
|
||||
page_bpts_t::iterator p = find_page_bpt(ea, size);
|
||||
if ( p != page_bpts.end() )
|
||||
return 0; // another page bpt exists
|
||||
|
||||
// Find out the current page protections
|
||||
MEMORY_BASIC_INFORMATION meminfo;
|
||||
ea_t page_ea = calc_page_base(ea);
|
||||
if ( !VirtualQueryEx(process_handle, (void *)(size_t)page_ea,
|
||||
&meminfo, sizeof(meminfo)) )
|
||||
{
|
||||
deberr("VirtualQueryEx");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Make sure the page is loaded
|
||||
if ( (meminfo.State & MEM_FREE) != 0 )
|
||||
{
|
||||
deberr("%a: the page has not been allocated", page_ea);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// According to MSDN documentation for VirtualQueryEx
|
||||
// (...)
|
||||
// AllocationProtect
|
||||
// The memory protection option when the region was initially allocated. This member can be
|
||||
// one of the memory protection constants or 0 if the caller does not have access.
|
||||
//
|
||||
// Unfortunately, there is no more information about why it my happen so, for now, I'm just
|
||||
// returning an error.
|
||||
if ( meminfo.Protect == 0 )
|
||||
{
|
||||
deberr("%a: the page cannot be accessed", page_ea);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate new page protections
|
||||
int aligned_len = align_up((ea-page_ea)+size, MEMORY_PAGE_SIZE);
|
||||
int real_len = 0;
|
||||
DWORD prot = meminfo.Protect;
|
||||
if ( remove_page_protections(&prot, type, dep_policy, process_handle) )
|
||||
{ // We have to set new protections
|
||||
real_len = aligned_len;
|
||||
}
|
||||
|
||||
// Remember the new breakpoint
|
||||
p = page_bpts.insert(std::make_pair(page_ea, pagebpt_data_t())).first;
|
||||
pagebpt_data_t &bpt = p->second;
|
||||
bpt.ea = ea;
|
||||
bpt.user_len = size;
|
||||
bpt.page_ea = page_ea;
|
||||
bpt.aligned_len = aligned_len;
|
||||
bpt.real_len = real_len;
|
||||
bpt.old_prot = 0;
|
||||
bpt.new_prot = prot;
|
||||
bpt.type = type;
|
||||
|
||||
// for PAGE_GUARD pages, no need to change the permissions, everything is fine already
|
||||
if ( real_len == 0 )
|
||||
{
|
||||
bpt.old_prot = meminfo.Protect;
|
||||
return 2;
|
||||
}
|
||||
|
||||
return dbg_enable_page_bpt(p, true) ? 2 : 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// returns true if changed *protect (in other words, if we have to mask
|
||||
// the real page protections and return the original one)
|
||||
bool winbase_debmod_t::mask_page_bpts(
|
||||
ea_t startea,
|
||||
ea_t endea,
|
||||
uint32 *protect)
|
||||
{
|
||||
// if we have page breakpoints, what we return must be changed to show the
|
||||
// real segment privileges, instead of the new ones we applied for the bpt
|
||||
int newprot = 0;
|
||||
page_bpts_t::iterator p = page_bpts.begin();
|
||||
while ( p != page_bpts.end() )
|
||||
{
|
||||
pagebpt_data_t &pbd = p->second;
|
||||
if ( pbd.page_ea + pbd.real_len > startea )
|
||||
{
|
||||
if ( pbd.page_ea >= endea )
|
||||
break;
|
||||
if ( pbd.old_prot != 0 )
|
||||
{ // bpt has been written to the process memory
|
||||
if ( *protect == pbd.new_prot )
|
||||
{ // return the old protection, before setting the page bpt
|
||||
newprot = pbd.old_prot;
|
||||
}
|
||||
else
|
||||
{
|
||||
debdeb("mask_page_bpts: app changed our page protection for %a (expected: 0x%x, actual: 0x%x)\n", pbd.page_ea, pbd.new_prot, *protect);
|
||||
// page protection has been changed by the application
|
||||
DWORD prot = *protect;
|
||||
if ( prot == PAGE_WRITECOPY && pbd.new_prot == PAGE_READWRITE
|
||||
|| prot == PAGE_EXECUTE_WRITECOPY && pbd.new_prot == PAGE_EXECUTE_READWRITE )
|
||||
{
|
||||
// in some cases OS may restore WRITECOPY protection; do nothing in such cases since it works the same way for breakpoint purposes
|
||||
debdeb(" ignoring changes to WRITECOPY protection\n");
|
||||
}
|
||||
else if ( remove_page_protections(&prot, pbd.type, dep_policy, process_handle) )
|
||||
{
|
||||
pbd.new_prot = prot;
|
||||
pbd.old_prot = 0; // mark our bpt as non-written
|
||||
debdeb(" will re-set protection to 0x%x\n", pbd.new_prot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++p;
|
||||
}
|
||||
if ( newprot != 0 )
|
||||
{
|
||||
*protect = newprot;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Page breakpoints modify the page protections to induce access violations.
|
||||
// We must hide the modified page protections from IDA and report the original
|
||||
// page protections.
|
||||
// Second, the application may render a page bpt inactive by changing its page protections.
|
||||
// In this case we must report to IDA the new page protections and also reactivate
|
||||
// the page breakpoint.
|
||||
void winbase_debmod_t::verify_page_protections(
|
||||
meminfo_vec_t *areas,
|
||||
const win32_prots_t &prots)
|
||||
{
|
||||
QASSERT(624, areas->size() == prots.size());
|
||||
if ( page_bpts.empty() )
|
||||
return;
|
||||
|
||||
for ( int i = 0; i < areas->size(); i++ )
|
||||
{
|
||||
uint32 prot = prots[i];
|
||||
memory_info_t &a = areas->at(i);
|
||||
if ( mask_page_bpts(a.start_ea, a.end_ea, &prot) )
|
||||
a.perm = win_prot_to_ida_perm(prot);
|
||||
}
|
||||
|
||||
// reactivate all disabled page bpts, if any
|
||||
enable_page_bpts(true);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#ifndef __X86__
|
||||
wow64_state_t winbase_debmod_t::check_wow64_process()
|
||||
{
|
||||
if ( is_wow64 == WOW64_NONE )
|
||||
{
|
||||
is_wow64 = check_wow64_handle(process_handle);
|
||||
if ( is_wow64 > 0 )
|
||||
dmsg("WOW64 process has been detected (pid=%d)\n", pid);
|
||||
}
|
||||
return is_wow64;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool highdll_vec_t::has(eanat_t addr) const
|
||||
{
|
||||
for ( int i = 0; i < size(); ++i )
|
||||
if ( (*this)[i].has(addr) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool highdll_vec_t::add(eanat_t addr, size_t sz, HANDLE h)
|
||||
{
|
||||
if ( has(addr) )
|
||||
return false;
|
||||
|
||||
// check removed: on new win10 we can have above 4GB:
|
||||
// ntdll.dll, wow64.dll, wow64win.dll
|
||||
// QASSERT(1491, size() < 2);
|
||||
highdll_range_t &r = push_back();
|
||||
r.start = addr;
|
||||
r.end = addr + sz;
|
||||
r.handle = h;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool highdll_vec_t::add_high_module(
|
||||
eanat_t addr,
|
||||
size_t sz,
|
||||
HANDLE h)
|
||||
{
|
||||
if ( ea_t(addr) == addr )
|
||||
return false;
|
||||
add(addr, sz, h); //-V779 unreachable code
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool highdll_vec_t::del_high_module(HANDLE *h, eanat_t addr)
|
||||
{
|
||||
for ( int i = 0; i < size(); ++i )
|
||||
{
|
||||
const highdll_range_t &r = (*this)[i];
|
||||
if ( r.start == addr )
|
||||
{
|
||||
if ( h != NULL )
|
||||
*h = r.handle;
|
||||
erase(begin() + i);
|
||||
return ea_t(addr) != addr;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void idaapi winbase_debmod_t::dbg_term(void)
|
||||
{
|
||||
is_wow64 = WOW64_NONE;
|
||||
delete win_tool_help;
|
||||
win_tool_help = NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Check if we need to install a temporary breakpoint to workaround the
|
||||
// 'freely running after syscall' problem. Exactly, the problem is the
|
||||
// following: after single stepping over a "jmp far ptr" instruction in
|
||||
// wow64cpu.dll for a 32bits process under a 64bits OS (Win7), the trap flag
|
||||
// is lost. Probably, it's a bug in wow64cpu!CpuReturnFromSimulatedCode.
|
||||
//
|
||||
// So, if we find an instruction like "call large dword fs:XX" we add a
|
||||
// temporary breakpoint at the next instruction and re-enable tracing
|
||||
// when the breakpoint is reached.
|
||||
bool winbase_debmod_t::check_for_call_large(
|
||||
const debug_event_t *event,
|
||||
HANDLE handle)
|
||||
{
|
||||
if ( check_wow64_handle(handle) <= 0 )
|
||||
return false;
|
||||
uchar buf[3];
|
||||
if ( dbg_read_memory(event->ea, buf, 3, NULL) == 3 )
|
||||
{
|
||||
// is it the call large instruction?
|
||||
if ( memcmp(buf, "\x64\xFF\x15", 3) == 0 )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
|
||||
int idaapi winbase_debmod_t::get_process_bitness(int _pid)
|
||||
{
|
||||
if ( _pid != -1 && _pid != GetCurrentProcessId() )
|
||||
{
|
||||
if ( !winver.is_64bitOS() )
|
||||
return 4;
|
||||
switch ( check_wow64_pid(_pid) )
|
||||
{
|
||||
case WOW64_BAD: return 0; // bad process id
|
||||
case WOW64_YES: return 4; // wow64 process, 32bit
|
||||
case WOW64_NO: return 8; // regular 64bit process
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return IDA_ADDRESS_SIZE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *str_bitness(int addrsize)
|
||||
{
|
||||
switch ( addrsize )
|
||||
{
|
||||
case 8:
|
||||
return "[64]";
|
||||
case 4:
|
||||
return "[32]";
|
||||
default:
|
||||
return "[x]";
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// this function may correct pinfo->addrsize
|
||||
bool winbase_debmod_t::get_process_path(
|
||||
ext_process_info_t *pinfo,
|
||||
char *buf,
|
||||
size_t bufsize)
|
||||
{
|
||||
module_snapshot_t msnap(get_tool_help());
|
||||
MODULEENTRY32 me;
|
||||
if ( !msnap.first(TH32CS_SNAPMODULE, pinfo->pid, &me) )
|
||||
{
|
||||
if ( msnap.last_err() == ERROR_PARTIAL_COPY && pinfo->addrsize == 0 )
|
||||
{
|
||||
// MSDN: If the specified process is a 64-bit process and the caller is a
|
||||
// 32-bit process, error code is ERROR_PARTIAL_COPY
|
||||
pinfo->addrsize = 8;
|
||||
}
|
||||
qstrncpy(buf, pinfo->name.c_str(), bufsize);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
tchar_utf8(buf, me.szExePath, bufsize);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
win_tool_help_t *winbase_debmod_t::get_tool_help()
|
||||
{
|
||||
if ( win_tool_help == NULL )
|
||||
win_tool_help = new win_tool_help_t;
|
||||
return win_tool_help;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int winbase_debmod_t::get_process_addrsize(pid_t _pid)
|
||||
{
|
||||
int addrsize = get_process_bitness(_pid);
|
||||
return addrsize != 0 ? addrsize : IDA_ADDRESS_SIZE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{1762} could be made const [in fact it cannot be made const in x64 mode]
|
||||
bool winbase_debmod_t::is_ntdll_name(const char *path)
|
||||
{
|
||||
const char *base_name = qbasename(path);
|
||||
const char *ntdll_name = winver.is_NT()
|
||||
? "ntdll.dll" // NT
|
||||
: "kernel32.dll"; // 9X/Me and KERNEL32.DLL
|
||||
if ( strieq(base_name, ntdll_name) )
|
||||
return true;
|
||||
#ifndef __X86__
|
||||
if ( winver.is_NT()
|
||||
&& check_wow64_process() == WOW64_YES
|
||||
&& strieq(base_name, "ntdll32.dll") )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -esym(1762,winbase_debmod_t::build_process_ext_name) could be made const
|
||||
void winbase_debmod_t::build_process_ext_name(ext_process_info_t *pinfo)
|
||||
{
|
||||
char fullname[MAXSTR];
|
||||
if ( get_process_path(pinfo, fullname, sizeof(fullname))
|
||||
&& pinfo->addrsize == 0 )
|
||||
{
|
||||
// the WOW64 is optional on R2 x64 server
|
||||
pinfo->addrsize = IDA_ADDRESS_SIZE;
|
||||
}
|
||||
pinfo->ext_name = str_bitness(pinfo->addrsize);
|
||||
if ( !pinfo->ext_name.empty() )
|
||||
pinfo->ext_name += ' ';
|
||||
pinfo->ext_name += fullname;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi winbase_debmod_t::get_process_list(procvec_t *list, qstring *)
|
||||
{
|
||||
int mypid = GetCurrentProcessId();
|
||||
list->clear();
|
||||
|
||||
process_snapshot_t psnap(get_tool_help());
|
||||
PROCESSENTRY32 pe32;
|
||||
for ( bool ok = psnap.first(TH32CS_SNAPNOHEAPS, &pe32); ok; ok = psnap.next(&pe32) )
|
||||
{
|
||||
if ( pe32.th32ProcessID != mypid )
|
||||
{
|
||||
int addrsize = get_process_bitness(pe32.th32ProcessID);
|
||||
#ifndef __EA64__
|
||||
if ( addrsize > 4 )
|
||||
continue; // skip 64bit processes, we cannot debug them because ea_t is 32bit
|
||||
#endif
|
||||
ext_process_info_t pinfo;
|
||||
pinfo.pid = pe32.th32ProcessID;
|
||||
pinfo.addrsize = addrsize;
|
||||
tchar_utf8(&pinfo.name, pe32.szExeFile);
|
||||
build_process_ext_name(&pinfo);
|
||||
list->push_back(pinfo);
|
||||
}
|
||||
}
|
||||
return list->size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Returns the file name assciated with pid
|
||||
bool idaapi winbase_debmod_t::get_exec_fname(int _pid, char *buf, size_t bufsize)
|
||||
{
|
||||
ext_process_info_t pinfo;
|
||||
pinfo.pid = _pid;
|
||||
pinfo.name.qclear();
|
||||
return get_process_path(&pinfo, buf, bufsize);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
win_tool_help_t *winbase_debmod_t::win_tool_help = NULL;
|
||||
win_version_t winbase_debmod_t::winver;
|
||||
179
idasdk75/dbg/win32/winbase_debmod.h
Normal file
179
idasdk75/dbg/win32/winbase_debmod.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#ifndef __WINBASE_HPP__
|
||||
#define __WINBASE_HPP__
|
||||
|
||||
// Base class for win32 and windbg modules
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
using std::for_each;
|
||||
using std::pair;
|
||||
using std::make_pair;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#define BASE_DEBUGGER_MODULE pc_debmod_t
|
||||
#include "deb_pc.hpp"
|
||||
#include "pc_debmod.h"
|
||||
#define BPT_CODE_SIZE X86_BPT_SIZE
|
||||
#include "win32_util.hpp"
|
||||
|
||||
extern const TCHAR kernel32_dll[];
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// DEP policies
|
||||
enum dep_policy_t
|
||||
{
|
||||
dp_always_off,
|
||||
dp_always_on,
|
||||
dp_opt_in,
|
||||
dp_opt_out
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
enum attach_status_t
|
||||
{
|
||||
as_none, // no attach to process requested
|
||||
as_attaching, // waiting for CREATE_PROCESS_DEBUG_EVENT, indicating the process is attached
|
||||
as_breakpoint, // waiting for first breakpoint, indicating the process was properly initialized and suspended
|
||||
as_attached, // process was successfully attached
|
||||
as_detaching, // waiting for next get_debug_event() request, to return the process as detached
|
||||
as_attach_kernel, // attaching to kernel
|
||||
};
|
||||
|
||||
// vector of win32 page protections
|
||||
// we need this type because meminfo_t does not contain the original win32 protections
|
||||
// but we need them to verify page bpts
|
||||
typedef qvector<uint32> win32_prots_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// When debugging WOW64 processes with ida32 we have to take into account
|
||||
// ntdll.dll (and wow64*.dll), which are x64 files
|
||||
// that can be loaded into high addresses (above 4GB)
|
||||
// Since ea_t cannot represent such addresses,
|
||||
// we use our own type to remember the DLL boundaries
|
||||
|
||||
typedef size_t eanat_t;
|
||||
|
||||
struct highdll_range_t
|
||||
{
|
||||
eanat_t start;
|
||||
eanat_t end;
|
||||
HANDLE handle;
|
||||
highdll_range_t() : start(0), end(0), handle(INVALID_HANDLE_VALUE) {}
|
||||
bool has(eanat_t addr) const { return addr >= start && addr < end; }
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(highdll_range_t);
|
||||
|
||||
struct highdll_vec_t : protected qvector<highdll_range_t>
|
||||
{
|
||||
private:
|
||||
size_t num_ntdlls; // count of actual ntdll*.dll modules in the list
|
||||
public:
|
||||
typedef qvector<highdll_range_t> inherited;
|
||||
highdll_vec_t() : num_ntdlls(0) {}
|
||||
void clear() { inherited::clear(); num_ntdlls = 0; }
|
||||
size_t size() const { return inherited::size(); }
|
||||
size_t count_ntdlls() const { return num_ntdlls; }
|
||||
bool empty() const { return inherited::empty(); }
|
||||
// return false if there is already a dll with such an address
|
||||
bool add(eanat_t addr, size_t size, HANDLE h = INVALID_HANDLE_VALUE);
|
||||
bool add_ntdll(eanat_t addr, size_t size, HANDLE h = INVALID_HANDLE_VALUE)
|
||||
{
|
||||
bool ok = add(addr, size, h);
|
||||
if ( ok )
|
||||
num_ntdlls++;
|
||||
return ok;
|
||||
};
|
||||
// it returns true if the dll address doesn't fit in `ea_t`
|
||||
bool add_high_module(
|
||||
eanat_t addr,
|
||||
size_t size,
|
||||
HANDLE h = INVALID_HANDLE_VALUE);
|
||||
// it returns true if the dll address doesn't fit to `ea_t`
|
||||
bool del_high_module(HANDLE *h, eanat_t addr);
|
||||
bool has(eanat_t addr) const;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class winbase_debmod_t: public BASE_DEBUGGER_MODULE
|
||||
{
|
||||
typedef BASE_DEBUGGER_MODULE inherited;
|
||||
wow64_state_t is_wow64; // use check_wow64_process()
|
||||
|
||||
protected:
|
||||
HANDLE process_handle;
|
||||
dep_policy_t dep_policy;
|
||||
highdll_vec_t highdlls;
|
||||
// local functions
|
||||
bool mask_page_bpts(ea_t startea, ea_t endea, uint32 *protect);
|
||||
void verify_page_protections(meminfo_vec_t *areas, const win32_prots_t &prots);
|
||||
|
||||
winbase_debmod_t(void);
|
||||
|
||||
// overridden virtual functions
|
||||
bool idaapi dbg_enable_page_bpt(page_bpts_t::iterator p, bool enable);
|
||||
int idaapi dbg_add_page_bpt(bpttype_t type, ea_t ea, int size);
|
||||
bool check_for_call_large(const debug_event_t *event, HANDLE process_handle);
|
||||
#ifndef __X86__
|
||||
wow64_state_t check_wow64_process();
|
||||
#else
|
||||
wow64_state_t check_wow64_process() { return WOW64_NO; }
|
||||
#endif
|
||||
|
||||
int get_process_addrsize(pid_t pid);
|
||||
|
||||
bool is_ntdll_name(const char *path);
|
||||
|
||||
// return number of processes, -1 - not implemented
|
||||
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf) override;
|
||||
// return the file name assciated with pid
|
||||
virtual bool idaapi get_exec_fname(int pid, char *buf, size_t bufsize) newapi;
|
||||
// get process bitness: 32bit - 4, 64bit - 8, 0 - unknown
|
||||
virtual int idaapi get_process_bitness(int pid) newapi;
|
||||
|
||||
public:
|
||||
virtual void idaapi dbg_term(void) override;
|
||||
|
||||
static win_tool_help_t *get_tool_help();
|
||||
static win_version_t winver;
|
||||
|
||||
private:
|
||||
void build_process_ext_name(ext_process_info_t *pinfo);
|
||||
static bool get_process_path(
|
||||
ext_process_info_t *pinfo,
|
||||
char *buf,
|
||||
size_t bufsize);
|
||||
static bool remove_page_protections(
|
||||
DWORD *p_input,
|
||||
bpttype_t bpttype,
|
||||
dep_policy_t dpolicy,
|
||||
HANDLE proc_handle);
|
||||
|
||||
static win_tool_help_t *win_tool_help;
|
||||
};
|
||||
|
||||
bool should_fire_page_bpt(page_bpts_t::iterator p, ea_t ea, DWORD failed_access_type, ea_t pc, dep_policy_t dep_policy);
|
||||
|
||||
#ifdef _PE_H_
|
||||
bool read_pe_header(peheader_t *pe);
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
inline void tchar_utf8(qstring *buf, TCHAR *tchar)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
utf16_utf8(buf, tchar);
|
||||
#else
|
||||
acp_utf8(buf, tchar);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
inline void tchar_utf8(char *buf, TCHAR *tchar, size_t bufsize)
|
||||
{
|
||||
qstring utf8;
|
||||
tchar_utf8(&utf8, tchar);
|
||||
qstrncpy(buf, utf8.c_str(), bufsize);
|
||||
}
|
||||
|
||||
#endif
|
||||
125
idasdk75/defaults.mk
Normal file
125
idasdk75/defaults.mk
Normal file
@@ -0,0 +1,125 @@
|
||||
#############################################################################
|
||||
# versions and paths for various external libraries and utils
|
||||
|
||||
ifdef __NT__
|
||||
# The following variables may have been set by vcvars.bat. You may
|
||||
# also set them manually. The default installation directories are
|
||||
# defined below in case these variables are not set.
|
||||
# Note: the following paths use backslashes (and may also contain a
|
||||
# trailing backslash) in order to conform to the variables
|
||||
# exported by vcvars.bat.
|
||||
|
||||
# Visual C++ 2017 Install Directory
|
||||
VCINSTALLDIR ?= '$(PROGRAMFILES)\Microsoft Visual Studio\2017\Professional\VC\'
|
||||
|
||||
# Visual C++ 2017 Tools Version
|
||||
# Note: if this variable is not set, the default version is obtained
|
||||
# in allmake.mak under "Visual C++ 2017 Tools Version".
|
||||
# VCToolsVersion ?= '14.11.25503'
|
||||
|
||||
# Windows SDK Install Directory
|
||||
WindowsSdkDir ?= '$(PROGRAMFILES)\Windows Kits\10\'
|
||||
|
||||
# Windows SDK version
|
||||
# Note: if this variable is not set, the latest version is detected
|
||||
# in allmake.mak under "Windows SDK Version".
|
||||
# WindowsSDKVersion ?= '10.0.17134.0\'
|
||||
|
||||
# Microsoft SDK v7.1A is only used for the win32 debugger server for
|
||||
# Windows XP compatibility.
|
||||
MSSDK71_PATH = '$(PROGRAMFILES)/Microsoft SDKs/Windows/v7.1A'
|
||||
else ifdef __MAC__
|
||||
# oldest supported version of MacOSX
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.9
|
||||
endif
|
||||
|
||||
# Python
|
||||
PYTHON_VERSION_MAJOR?=3
|
||||
PYTHON_VERSION_MINOR?=4
|
||||
PYTHON_VERNAME=python$(PYTHON_VERSION_MAJOR).$(PYTHON_VERSION_MINOR)
|
||||
|
||||
# TODO clean this up
|
||||
ifdef __NT__
|
||||
ifneq (,$(wildcard /cygdrive/c/Program\ Files/Python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR)/python.exe))
|
||||
PYTHON_ROOT ?= C:/Program Files/Python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR)
|
||||
else
|
||||
ifeq ($(PYTHON_VERSION_MAJOR),2)
|
||||
PYTHON_VERSUF=-x64
|
||||
endif
|
||||
PYTHON_ROOT ?= $(SYSTEMDRIVE)/Python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR)$(PYTHON_VERSUF)
|
||||
endif
|
||||
PYTHON ?= "$(PYTHON_ROOT)/python.exe"
|
||||
else
|
||||
PYTHON ?= $(PYTHON_VERNAME)
|
||||
endif
|
||||
|
||||
# Qt
|
||||
QTVER?=5.6.3-x64
|
||||
|
||||
QTDIR-$(__LINUX__) = /usr/local/Qt/$(QTVER)/
|
||||
QTDIR-$(__MAC__) = /Users/Shared/Qt/$(QTVER)/
|
||||
QTDIR-$(__NT__) = $(SYSTEMDRIVE)/Qt/$(QTVER)/
|
||||
QTDIR ?= $(QTDIR-1)
|
||||
|
||||
ifdef __NT__
|
||||
ifdef NDEBUG
|
||||
QTSUFF=.dll
|
||||
else
|
||||
QTSUFF=d.dll
|
||||
endif
|
||||
QTLIBDIR=bin
|
||||
else ifdef __LINUX__
|
||||
QTPREF=lib
|
||||
QTSUFF=.so.5
|
||||
QTLIBDIR=lib
|
||||
endif
|
||||
|
||||
# SWiG
|
||||
ifeq ($(PYTHON_VERSION_MAJOR),3)
|
||||
SWIG_VERSION?=4.0.1
|
||||
ifdef __NT__
|
||||
SWIG_DIR_SUFFIX?=-py3-stable-abi-cygwin
|
||||
else
|
||||
SWIG_DIR_SUFFIX?=-py3-stable-abi
|
||||
endif
|
||||
else
|
||||
SWIG_VERSION?=4.0.0
|
||||
endif
|
||||
ifdef __NT__
|
||||
ifeq ($(PYTHON_VERSION_MAJOR),3)
|
||||
SWIG_DISTRIBUTION_HAS_UNIX_LAYOUT:=1
|
||||
endif
|
||||
else
|
||||
SWIG_DISTRIBUTION_HAS_UNIX_LAYOUT:=1
|
||||
endif
|
||||
|
||||
ifeq ($(SWIG_DISTRIBUTION_HAS_UNIX_LAYOUT),1)
|
||||
ifdef USE_CCACHE
|
||||
# we set CCACHE_DIR so as to not interfere with the system's ccache
|
||||
# and we set CCACHE_CPP2 to prevent SWiG from printing a bunch of
|
||||
# warnings due to re-using of the preprocessed source.
|
||||
SWIG?=CCACHE_DIR='$${HOME}/.ccache-swig' CCACHE_CPP2=1 $(SWIG_HOME)/bin/ccache-swig $(SWIG_HOME)/bin/swig
|
||||
else
|
||||
SWIG?=$(SWIG_HOME)/bin/swig
|
||||
endif
|
||||
SWIG_INCLUDES?=-I$(SWIG_HOME)/share/swig/$(SWIG_VERSION)/python -I$(SWIG_HOME)/share/swig/$(SWIG_VERSION)
|
||||
else
|
||||
SWIG?=$(SWIG_HOME)/swig.exe
|
||||
SWIG_INCLUDES?=-I$(SWIG_HOME)/Lib/python -I$(SWIG_HOME)/Lib
|
||||
endif
|
||||
|
||||
#############################################################################
|
||||
# keep all paths in unix format, with forward slashes
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# define: convert dos path to unix path by replacing backslashes by slashes
|
||||
unixpath=$(subst \,/,$(1))
|
||||
|
||||
PYTHON_ROOT :=$(call unixpath,$(PYTHON_ROOT))
|
||||
PYTHON :=$(call unixpath,$(PYTHON))
|
||||
SWIG :=$(call unixpath,$(SWIG))
|
||||
QTDIR :=$(call unixpath,$(QTDIR))
|
||||
endif
|
||||
|
||||
#############################################################################
|
||||
# http://stackoverflow.com/questions/16467718/how-to-print-out-a-variable-in-makefile
|
||||
.print-% : ; @echo $($*)
|
||||
21042
idasdk75/include/allins.hpp
Normal file
21042
idasdk75/include/allins.hpp
Normal file
File diff suppressed because it is too large
Load Diff
12
idasdk75/include/allow_deprecated.hpp
Normal file
12
idasdk75/include/allow_deprecated.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// this file should be included before calling deprecated functions
|
||||
// it should be included at the point where the definitions of deprecated
|
||||
// functions begin in the source file. this way a deprecated function may call
|
||||
// another deprecated function without raising a warning.
|
||||
|
||||
// deprecated functions may call each other
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
289
idasdk75/include/auto.hpp
Normal file
289
idasdk75/include/auto.hpp
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2020 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AUTO_HPP
|
||||
#define _AUTO_HPP
|
||||
#include <ida.hpp>
|
||||
|
||||
/*! \file auto.hpp
|
||||
|
||||
\brief Functions that work with the autoanalyzer queue.
|
||||
|
||||
The autoanalyzer works when IDA is not busy processing
|
||||
the user keystrokes. It has several queues, each queue having
|
||||
its own priority. The analyzer stops when all queues are empty.
|
||||
|
||||
A queue contains addresses or address ranges.
|
||||
The addresses are kept sorted by their values.
|
||||
The analyzer will process all addresses from the first queue, then
|
||||
switch to the second queue and so on.
|
||||
There are no limitations on the size of the queues.
|
||||
|
||||
This file also contains functions that deal with the IDA status
|
||||
indicator and the autoanalysis indicator.
|
||||
You may use these functions to change the indicator value.
|
||||
*/
|
||||
|
||||
typedef int atype_t; ///< identifies an autoanalysis queue - see \ref AU_
|
||||
|
||||
/// \defgroup AU_ Autoanalysis queues
|
||||
/// Names and priorities of the analyzer queues
|
||||
//@{
|
||||
const atype_t
|
||||
AU_NONE = 00, ///< placeholder, not used
|
||||
AU_UNK = 10, ///< 0: convert to unexplored
|
||||
AU_CODE = 20, ///< 1: convert to instruction
|
||||
AU_WEAK = 25, ///< 2: convert to instruction (ida decision)
|
||||
AU_PROC = 30, ///< 3: convert to procedure start
|
||||
AU_TAIL = 35, ///< 4: add a procedure tail
|
||||
AU_FCHUNK=38, ///< 5: find func chunks
|
||||
AU_USED = 40, ///< 6: reanalyze
|
||||
AU_TYPE = 50, ///< 7: apply type information
|
||||
AU_LIBF = 60, ///< 8: apply signature to address
|
||||
AU_LBF2 = 70, ///< 9: the same, second pass
|
||||
AU_LBF3 = 80, ///< 10: the same, third pass
|
||||
AU_CHLB = 90, ///< 11: load signature file (file name is kept separately)
|
||||
AU_FINAL=200; ///< 12: final pass
|
||||
//@}
|
||||
|
||||
|
||||
typedef int idastate_t; ///< IDA status indicator - see \ref st_
|
||||
|
||||
/// \defgroup st_ Status indicator states
|
||||
//@{
|
||||
const idastate_t
|
||||
// meaning
|
||||
st_Ready = 0, ///< READY: IDA is doing nothing
|
||||
st_Think = 1, ///< THINKING: Autoanalysis on, the user may press keys
|
||||
st_Waiting = 2, ///< WAITING: Waiting for the user input
|
||||
st_Work = 3; ///< BUSY: IDA is busy
|
||||
//@}
|
||||
|
||||
|
||||
/// Get current state of autoanalyzer.
|
||||
/// If auto_state == ::AU_NONE, IDA is currently not running the analysis
|
||||
/// (it could be temporarily interrupted to perform the user's requests, for example).
|
||||
|
||||
idaman atype_t ida_export get_auto_state(void);
|
||||
|
||||
|
||||
/// Set current state of autoanalyzer.
|
||||
/// \param new_state new state of autoanalyzer
|
||||
/// \return previous state
|
||||
|
||||
idaman atype_t ida_export set_auto_state(atype_t new_state);
|
||||
|
||||
|
||||
/// See ::get_auto_display
|
||||
struct auto_display_t
|
||||
{
|
||||
atype_t type = AU_NONE;
|
||||
ea_t ea = BADADDR;
|
||||
idastate_t state = st_Ready;
|
||||
};
|
||||
|
||||
/// Get structure which holds the autoanalysis indicator contents
|
||||
|
||||
idaman bool ida_export get_auto_display(auto_display_t *auto_display);
|
||||
|
||||
|
||||
/// Change autoanalysis indicator value.
|
||||
/// \param ea linear address being analyzed
|
||||
/// \param type autoanalysis type (see \ref AU_)
|
||||
|
||||
idaman void ida_export show_auto(ea_t ea, atype_t type=AU_NONE);
|
||||
|
||||
|
||||
/// Show an address on the autoanalysis indicator.
|
||||
/// The address is displayed in the form " @:12345678".
|
||||
/// \param ea - linear address to display
|
||||
|
||||
inline void show_addr(ea_t ea) { show_auto(ea); }
|
||||
|
||||
|
||||
/// Change IDA status indicator value
|
||||
/// \param st - new indicator status
|
||||
/// \return old indicator status
|
||||
|
||||
idaman idastate_t ida_export set_ida_state(idastate_t st);
|
||||
|
||||
|
||||
/// Is it allowed to create stack variables automatically?.
|
||||
/// This function should be used by IDP modules before creating stack vars.
|
||||
|
||||
inline bool may_create_stkvars(void)
|
||||
{
|
||||
return inf_should_create_stkvars() && get_auto_state() == AU_USED;
|
||||
}
|
||||
|
||||
|
||||
/// Is it allowed to trace stack pointer automatically?.
|
||||
/// This function should be used by IDP modules before tracing sp.
|
||||
|
||||
inline bool may_trace_sp(void)
|
||||
{
|
||||
if ( inf_should_trace_sp() )
|
||||
{
|
||||
atype_t auto_state = get_auto_state();
|
||||
return auto_state == AU_USED;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// Put range of addresses into a queue.
|
||||
/// 'start' may be higher than 'end', the kernel will swap them in this case.
|
||||
/// 'end' doesn't belong to the range.
|
||||
|
||||
idaman void ida_export auto_mark_range(ea_t start,ea_t end,atype_t type);
|
||||
|
||||
|
||||
/// Put single address into a queue. Queues keep addresses sorted.
|
||||
|
||||
inline void auto_mark(ea_t ea, atype_t type)
|
||||
{
|
||||
auto_mark_range(ea, ea+1, type);
|
||||
}
|
||||
|
||||
|
||||
/// Remove range of addresses from a queue.
|
||||
/// 'start' may be higher than 'end', the kernel will swap them in this case.
|
||||
/// 'end' doesn't belong to the range.
|
||||
|
||||
idaman void ida_export auto_unmark(ea_t start, ea_t end, atype_t type);
|
||||
|
||||
// Convenience functions
|
||||
|
||||
/// Plan to perform reanalysis
|
||||
inline void plan_ea(ea_t ea)
|
||||
{
|
||||
auto_mark(ea, AU_USED);
|
||||
}
|
||||
/// Plan to perform reanalysis
|
||||
inline void plan_range(ea_t sEA, ea_t eEA)
|
||||
{
|
||||
auto_mark_range(sEA, eEA, AU_USED);
|
||||
}
|
||||
/// Plan to make code
|
||||
inline void auto_make_code(ea_t ea)
|
||||
{
|
||||
auto_mark(ea, AU_CODE);
|
||||
}
|
||||
/// Plan to make code&function
|
||||
inline void auto_make_proc(ea_t ea)
|
||||
{
|
||||
auto_make_code(ea);
|
||||
auto_mark(ea, AU_PROC);
|
||||
}
|
||||
|
||||
/// Plan to reanalyze callers of the specified address.
|
||||
/// This function will add to ::AU_USED queue all instructions that
|
||||
/// call (not jump to) the specified address.
|
||||
/// \param ea linear address of callee
|
||||
/// \param noret !=0: the callee doesn't return, mark to undefine subsequent
|
||||
/// instructions in the caller. 0: do nothing.
|
||||
|
||||
idaman void ida_export reanalyze_callers(ea_t ea, bool noret);
|
||||
|
||||
|
||||
/// Delete all analysis info that IDA generated for for the given range
|
||||
|
||||
idaman void ida_export revert_ida_decisions(ea_t ea1, ea_t ea2);
|
||||
|
||||
|
||||
/// Plan to apply the callee's type to the calling point
|
||||
|
||||
idaman void ida_export auto_apply_type(ea_t caller, ea_t callee);
|
||||
|
||||
/// Plan to apply the tail_ea chunk to the parent
|
||||
/// \param tail_ea linear address of start of tail
|
||||
/// \param parent_ea linear address within parent. If BADADDR, automatically
|
||||
/// try to find parent via xrefs.
|
||||
|
||||
idaman void ida_export auto_apply_tail(ea_t tail_ea, ea_t parent_ea);
|
||||
|
||||
/// Analyze the specified range.
|
||||
/// Try to create instructions where possible.
|
||||
/// Make the final pass over the specified range if specified.
|
||||
/// This function doesn't return until the range is analyzed.
|
||||
/// \retval 1 ok
|
||||
/// \retval 0 Ctrl-Break was pressed
|
||||
|
||||
idaman int ida_export plan_and_wait(ea_t ea1, ea_t ea2, bool final_pass=true);
|
||||
|
||||
|
||||
/// Process everything in the queues and return true.
|
||||
/// \return false if the user clicked cancel.
|
||||
/// (the wait box must be displayed by the caller if desired)
|
||||
|
||||
idaman bool ida_export auto_wait(void);
|
||||
|
||||
|
||||
/// Process everything in the specified range and return true.
|
||||
/// \return number of autoanalysis steps made. -1 if the user clicked cancel.
|
||||
/// (the wait box must be displayed by the caller if desired)
|
||||
|
||||
idaman ssize_t ida_export auto_wait_range(ea_t ea1, ea_t ea2);
|
||||
|
||||
|
||||
/// Analyze one address in the specified range and return true.
|
||||
/// \return if processed anything. false means that there is nothing to
|
||||
/// process in the specified range.
|
||||
|
||||
idaman bool ida_export auto_make_step(ea_t ea1, ea_t ea2);
|
||||
|
||||
|
||||
/// Remove an address range (ea1..ea2) from queues ::AU_CODE, ::AU_PROC, ::AU_USED.
|
||||
/// To remove an address range from other queues use auto_unmark() function.
|
||||
/// 'ea1' may be higher than 'ea2', the kernel will swap them in this case.
|
||||
/// 'ea2' doesn't belong to the range.
|
||||
|
||||
idaman void ida_export auto_cancel(ea_t ea1, ea_t ea2);
|
||||
|
||||
|
||||
/// Are all queues empty?
|
||||
/// (i.e. has autoanalysis finished?).
|
||||
|
||||
idaman bool ida_export auto_is_ok(void);
|
||||
|
||||
|
||||
/// Peek into a queue 'type' for an address not lower than 'low_ea'.
|
||||
/// Do not remove address from the queue.
|
||||
/// \return the address or #BADADDR
|
||||
|
||||
idaman ea_t ida_export peek_auto_queue(ea_t low_ea, atype_t type);
|
||||
|
||||
|
||||
/// Retrieve an address from queues regarding their priority.
|
||||
/// Returns #BADADDR if no addresses not lower than 'lowEA' and less than
|
||||
/// 'highEA' are found in the queues.
|
||||
/// Otherwise *type will have queue type.
|
||||
|
||||
idaman ea_t ida_export auto_get(atype_t *type, ea_t lowEA, ea_t highEA);
|
||||
|
||||
|
||||
/// Try to create instruction
|
||||
/// \param ea linear address of callee
|
||||
/// \return the length of the instruction or 0
|
||||
|
||||
idaman int ida_export auto_recreate_insn(ea_t ea);
|
||||
|
||||
|
||||
/// Get autoanalyzer state
|
||||
|
||||
idaman bool ida_export is_auto_enabled(void);
|
||||
|
||||
|
||||
/// Temporarily enable/disable autoanalyzer. Not user-facing, but rather because
|
||||
/// IDA sometimes need to turn AA on/off regardless of inf.s_genflags:INFFL_AUTO
|
||||
/// \return old state
|
||||
|
||||
idaman bool ida_export enable_auto(bool enable);
|
||||
|
||||
|
||||
|
||||
#endif // _AUTO_HPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user