update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

View File

@@ -29,27 +29,27 @@
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug64|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release64|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -179,7 +179,8 @@
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<OpenMPSupport>false</OpenMPSupport>
<AdditionalIncludeDirectories>$(SolutionDir)idasdk75\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)idasdk76\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp14</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
@@ -191,7 +192,7 @@
<AdditionalOptions>/EXPORT:PLUGIN %(AdditionalOptions)</AdditionalOptions>
<DataExecutionPrevention>false</DataExecutionPrevention>
<EnableUAC>false</EnableUAC>
<AdditionalLibraryDirectories>$(SolutionDir)idasdk75\lib\x64_win_vc_64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(SolutionDir)idasdk76\lib\x64_win_vc_64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<ProjectReference>
<LinkLibraryDependencies>false</LinkLibraryDependencies>

Binary file not shown.

View File

@@ -1,823 +0,0 @@
#
# 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:

View File

@@ -1,294 +0,0 @@
#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 &regs,
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;
}
}

View File

@@ -1,66 +0,0 @@
#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 &regs, 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

View File

@@ -1,107 +0,0 @@
#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();
}

View File

@@ -1,213 +0,0 @@
#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;
}

View File

@@ -1,136 +0,0 @@
#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);

View File

@@ -1,906 +0,0 @@
#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

View File

@@ -1,34 +0,0 @@
/*
* 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

View File

@@ -1,62 +0,0 @@
/*
* 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

View File

@@ -1,857 +0,0 @@
//
// 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
};

View File

@@ -1,246 +0,0 @@
// 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();
}

View File

@@ -1,97 +0,0 @@
#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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +0,0 @@
#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

File diff suppressed because it is too large Load Diff

View File

@@ -1,741 +0,0 @@
#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 &regvals);
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,349 +0,0 @@
#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

File diff suppressed because it is too large Load Diff

View File

@@ -1,138 +0,0 @@
#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();
}

View File

@@ -1,149 +0,0 @@
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

View File

@@ -1,23 +0,0 @@
// 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 = "";

File diff suppressed because it is too large Load Diff

View File

@@ -1,546 +0,0 @@
#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

View File

@@ -1,26 +0,0 @@
<?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>

View File

@@ -1,25 +0,0 @@
<?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>

View File

@@ -1,203 +0,0 @@
#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.";

View File

@@ -1,72 +0,0 @@
/*
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"

View File

@@ -1,31 +0,0 @@
/*
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"

View File

@@ -1,164 +0,0 @@
#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();
}

View File

@@ -1,41 +0,0 @@
#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

View File

@@ -1,350 +0,0 @@
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,249 +0,0 @@
#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

View File

@@ -1,197 +0,0 @@
#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;
}

View File

@@ -1,304 +0,0 @@
#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 &regvals)
{
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;
}

View File

@@ -1,113 +0,0 @@
// 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)
{
}

View File

@@ -1,118 +0,0 @@
#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

View File

@@ -1,224 +0,0 @@
/*
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();
}

View File

@@ -1,58 +0,0 @@
#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

View File

@@ -1,174 +0,0 @@
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

View File

@@ -1,256 +0,0 @@
#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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,428 +0,0 @@
#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

View File

@@ -1,619 +0,0 @@
#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;

View File

@@ -1,179 +0,0 @@
#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

View File

@@ -1,125 +0,0 @@
#############################################################################
# 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 $($*)

File diff suppressed because it is too large Load Diff

View File

@@ -1,289 +0,0 @@
/*
* 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

File diff suppressed because it is too large Load Diff

View File

@@ -1,173 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef COMPRESS_HPP
#define COMPRESS_HPP
#include <diskio.hpp>
/*! \file compress.hpp
\brief Data compression functions
*/
/// Compress data.
/// This function depends on the value of legacy_idb, so it is not completely
/// thread safe. However, legacy_idb does not change its value.
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export zip_deflate(
void *ud,
ssize_t (idaapi *file_reader)(void *ud, void *buf, size_t size),
ssize_t (idaapi *file_writer)(void *ud, const void *buf, size_t size));
/// Uncompress data.
/// This function depends on the value of legacy_idb, so it is not completely
/// thread safe. However, legacy_idb does not change its value.
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export zip_inflate(
void *ud,
ssize_t (idaapi *file_reader)(void *ud, void *buf, size_t size),
ssize_t (idaapi *file_writer)(void *ud, const void *buf, size_t size));
/// Process zip file and enumerate all files stored in it
/// \param zipfile name of zip file
/// \param callback callback for each file. params:
/// - ud: user data
/// - offset: offset in the zip file
/// - method: compression method (\ref compression_methods)
/// - csize: compressed size
/// - ucsize: uncompressed size
/// - attributes: file attributes
/// \param ud user data
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export process_zipfile(
const char *zipfile,
int (idaapi *callback)(
void *ud,
qoff64_t offset,
int method,
uint64 csize,
uint64 ucsize,
uint32 attributes,
const char *filename),
void *ud = NULL);
/// Process zip file and enumerate all files stored in it
/// \param li input file
/// \param callback callback for each file. params:
/// - ud: user data
/// - offset: offset in the zip file
/// - method: compression method (\ref compression_methods)
/// - csize: compressed size
/// - ucsize: uncompressed size
/// - attributes: file attributes
/// \param ud user data
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export process_zip_linput(
linput_t *li,
int (idaapi *callback)(
void *ud,
qoff64_t offset,
int method,
uint64 csize,
uint64 ucsize,
uint32 attributes,
const char *filename),
void *ud = NULL);
/// Search for specified entry in zip file, and calls the
/// callback with it, if found.
/// \param zipfile name of zip file
/// \param entry entry in zip file. E.g., "path/to/entry.dat"
/// \param callback callback for each file. params:
/// - ud: user data
/// - offset: offset in the zip file
/// - method: compression method (\ref compression_methods)
/// - csize: compressed size
/// - ucsize: uncompressed size
/// - attributes: file attributes
/// \param ud user data
/// \param case_sensitive should the search be case sensitive?
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export process_zipfile_entry(
const char *zipfile,
const char *entry,
int (idaapi *callback)(
void *ud,
qoff64_t offset,
int method,
uint64 csize,
uint64 ucsize,
uint32 attributes,
const char *filename),
void *ud = NULL,
bool case_sensitive = true);
/// \defgroup PKZ_ Compression error codes
/// Returned by functions in compress.hpp
//@{
#define PKZ_OK 0
#define PKZ_ERRNO 1
#define PKZ_STREAM_ERROR 2
#define PKZ_DATA_ERROR 3
#define PKZ_MEM_ERROR 4
#define PKZ_BUF_ERROR 5
#define PKZ_VERSION_ERROR 6
#define PKZ_RERR 777 // read error
#define PKZ_WERR 778 // write error
//@}
/// \defgroup compression_methods Compression methods
/// passed as 'method' parameter to callback functions in compress.hpp
//@{
#define STORED 0
#define SHRUNK 1
#define REDUCED1 2
#define REDUCED2 3
#define REDUCED3 4
#define REDUCED4 5
#define IMPLODED 6
#define TOKENIZED 7
#define DEFLATED 8
#define NUM_METHODS 9 /* index of last method + 1 */
//@}
extern bool legacy_idb; ///< for old idb files
/// Upon closing outer linput, perform one of these actions
enum linput_close_code_t
{
LOC_CLOSE, ///< close the inner linput
LOC_UNMAKE, ///< unmake the inner linput
LOC_KEEP, ///< do nothing
};
/// Create a linput to read a compressed input stream
/// \param in linput with compressed data, seeked to the stream beginning
/// \param insize size of compressed data. -1 - unknown
/// \param loc what to do upon closing the resulting linput
/// \return linput that can be used to read uncompressed data.
/// NULL if any error (no more linput descriptors).
idaman THREAD_SAFE linput_t *ida_export create_zip_linput(
linput_t *in,
ssize_t insize=-1,
linput_close_code_t loc=LOC_CLOSE);
#endif

View File

@@ -1,543 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _CONFIG_HPP
#define _CONFIG_HPP
//-----------------------------------------------------------------------
/// \defgroup IDPOPT_T Option value types
/// Passed as 'value_type' parameter to ::set_options_t callbacks
//@{
#define IDPOPT_STR 1 ///< string constant (char *)
#define IDPOPT_NUM 2 ///< number (uval_t *)
#define IDPOPT_BIT 3 ///< bit, yes/no (int *)
#define IDPOPT_I64 5 ///< 64bit number (int64 *)
#define IDPOPT_CST 6 ///< lexer (lexer_t*)
///< Custom type, starting with a '{'
///< Values of this type should be handled by
///< ::set_options_t callbacks. E.g.,:
///< \code
///< ERROR_STRINGS =
///< {
///< {0, "Unknown error"},
///< {1, "Missing filename"},
///< {5, "Out-of-memory"}
///< }
///< \endcode
///< For values of this type, the data that will
///< be passed as the callback's 'value' parameter
///< is the lexer instance that is being used
///< to parse the configuration file.
///< You can use \ref parse_json() (see parsejson.hpp)
///< to parse JSON-format data
///< NB: the '{' is already consumed by the parser,
///< so you need to push it again if it's a part of the JSON object
//@}
/// \defgroup IDPOPT_RET Option result codes
/// Predefined return values for ::set_options_t callbacks
//@{
#define IDPOPT_OK NULL ///< ok
#define IDPOPT_BADKEY ((char*)1) ///< illegal keyword
#define IDPOPT_BADTYPE ((char*)2) ///< illegal type of value
#define IDPOPT_BADVALUE ((char*)3) ///< illegal value (bad range, for example)
//@}
/// Callback - called when a config directive is processed in IDA.
/// Also see read_config_file() and processor_t::set_idp_options
/// \param keyword keyword encountered in IDA.CFG/user config file.
/// if NULL, then an interactive dialog form should be displayed
/// \param value_type type of value of the keyword - one of \ref IDPOPT_T
/// \param value pointer to value
/// \param idb_loaded true if the ev_oldfile/ev_newfile events have been generated?
/// \return one of \ref IDPOPT_RET, otherwise a pointer to an error message
typedef const char *(idaapi set_options_t)(
const char *keyword,
int value_type,
const void *value,
bool idb_loaded);
/// \defgroup IDAOPT_PRIO Option priority
/// Specifies the priority of a configuration option. Since options may
/// be specified in different way, and applied in various orders, we need
/// option priorities.
/// Normally the default priority option does not overwrite the existing value
/// whereas the high priority one does.
/// High priority options may be stored in the database to be available
/// in the next session.
//@{
#define IDPOPT_PRI_DEFAULT 1 ///< default priority - taken from config file
#define IDPOPT_PRI_HIGH 2 ///< high priority - received from UI or a script function
//@}
//-------------------------------------------------------------------------
/// Parse the value type for the value token 'value'.
/// This is mostly used for converting from values that a cfgopt_handler_t
/// receives, into data that callbacks
/// - processor_t::set_idp_options
/// - debugger_t::set_dbg_options
/// expect.
///
/// Plugins that wish to use options shouldn't rely on this,
/// and use the cfgopt_t utility instead.
///
/// \param out parsed data
/// \param lx the lexer in use
/// \param value the value token
/// \return true if guessing didn't lead to an error, false otherwise.
/// note that even if 'true' is returned, it doesn't mean the
/// type could be guessed: merely that no syntax error occurred.
class lexer_t;
struct token_t;
idaman bool ida_export parse_config_value(
idc_value_t *out,
lexer_t *lx,
const token_t &value);
//-------------------------------------------------------------------------
typedef const char *(idaapi cfgopt_handler_t)(
lexer_t *lx,
const token_t &keyword,
const token_t &value);
//-------------------------------------------------------------------------
typedef const char *(idaapi cfgopt_handler2_t)(
lexer_t *lx,
const token_t &keyword,
const token_t &value,
int64 param1,
int64 param2);
//-------------------------------------------------------------------------
typedef const char *(idaapi cfgopt_handler3_t)(
lexer_t *lx,
const token_t &keyword,
const token_t &value,
int64 param1,
int64 param2,
void *obj);
//-----------------------------------------------------------------------
/// used by cfgopt_t. You shouldn't have to deal with those directly.
#define IDPOPT_NUM_INT (0)
#define IDPOPT_NUM_CHAR (1 << 24)
#define IDPOPT_NUM_SHORT (2 << 24)
#define IDPOPT_NUM_RANGE (1 << 26)
#define IDPOPT_NUM_UNS (1 << 27)
#define IDPOPT_BIT_UINT 0
#define IDPOPT_BIT_UCHAR (1 << 24)
#define IDPOPT_BIT_USHORT (2 << 24)
#define IDPOPT_BIT_BOOL (3 << 24)
#define IDPOPT_STR_QSTRING (1 << 24)
#define IDPOPT_STR_LONG (1 << 25)
#define IDPOPT_I64_RANGES (1 << 24)
#define IDPOPT_I64_UNS (1 << 25)
#define IDPOPT_CST_PARAMS (1 << 24)
#define IDPOPT_MBROFF (1 << 18)
//-------------------------------------------------------------------------
struct cfgopt_t;
idaman const char *ida_export cfgopt_t__apply(
const cfgopt_t *_this,
int vtype,
const void *vdata);
idaman const char *ida_export cfgopt_t__apply2(
const cfgopt_t *_this,
int vtype,
const void *vdata,
void *obj);
//-------------------------------------------------------------------------
// cfgopt_t objects are suitable for being statically initialized, and
// passed to 'read_config_file'.
//
// E.g.,
// ---
// static const cfgopt_t g_opts[] =
// {
// cfgopt_t("AUTO_UNDEFINE", &auto_undefine, -1, 1),
// cfgopt_t("NOVICE", &novice, true),
// cfgopt_t("EDITOR", editor_buf, sizeof(editor_buf)),
// cfgopt_t("SCREEN_PALETTE", set_screen_palette), // specific handler for SCREEN_PALETTE
// };
//
// ...
//
// read_config_file("myfile", g_opts, qnumber(g_opts), other_handler)
// ---
//
// NOTES:
// * so-called 'long' strings (the default) can span on multiple lines,
// and are terminated by a ';'
struct cfgopt_t
{
const char *name;
union
{
void *ptr;
size_t mbroff; // offset of a structure member
cfgopt_handler_t *hnd; // to avoid reinterpret_cast and gcc's error:
cfgopt_handler2_t *hnd2; // "a reinterpret_cast is not a constant expression"
cfgopt_handler3_t *hnd3; //
};
int flags;
struct num_range_t
{
constexpr num_range_t(int64 _min, int64 _max) : minval(_min), maxval(_max) {}
int64 minval;
int64 maxval;
};
struct params_t
{
constexpr params_t(int64 _p1, int64 _p2) : p1(_p1), p2(_p2) {}
int64 p1;
int64 p2;
};
union
{
size_t buf_size;
num_range_t num_range;
uint32 bit_flags;
params_t params;
void *mbroff_obj;
};
// IDPOPT_STR
constexpr cfgopt_t(const char *_n, char *_p, size_t _sz, bool _long = true)
: name(_n), ptr(_p), flags(IDPOPT_STR | (_long ? IDPOPT_STR_LONG : 0)), buf_size(_sz)
{}
constexpr cfgopt_t(const char *_n, qstring *_p, bool _long = true)
: name(_n), ptr(_p), flags(IDPOPT_STR | IDPOPT_STR_QSTRING | (_long ? IDPOPT_STR_LONG : 0)), buf_size(0)
{}
// IDPOPT_NUM
constexpr cfgopt_t(const char *_n, int *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM), buf_size(0) {}
constexpr cfgopt_t(const char *_n, uint *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS), buf_size(0) {}
constexpr cfgopt_t(const char *_n, char *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_CHAR), buf_size(0) {}
constexpr cfgopt_t(const char *_n, uchar *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_CHAR), buf_size(0) {}
constexpr cfgopt_t(const char *_n, short *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_SHORT), buf_size(0) {}
constexpr cfgopt_t(const char *_n, ushort *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_SHORT), buf_size(0) {}
// IDPOPT_NUM + ranges
constexpr cfgopt_t(const char *_n, int *_p, int _min, int _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_RANGE), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, uint *_p, uint _min, uint _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_RANGE), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, char *_p, char _min, char _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_CHAR | IDPOPT_NUM_RANGE), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, uchar *_p, uchar _min, uchar _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_CHAR | IDPOPT_NUM_RANGE), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, short *_p, short _min, short _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_RANGE | IDPOPT_NUM_SHORT), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, ushort *_p, ushort _min, ushort _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_RANGE | IDPOPT_NUM_SHORT), num_range(_min, _max) {}
// IDPOPT_BIT
constexpr cfgopt_t(const char *_n, bool *_p, bool _flags) : name(_n), ptr(_p), flags(IDPOPT_BIT | IDPOPT_BIT_BOOL), bit_flags(_flags) {}
constexpr cfgopt_t(const char *_n, uchar *_p, uchar _flags) : name(_n), ptr(_p), flags(IDPOPT_BIT | IDPOPT_BIT_UCHAR), bit_flags(_flags) {}
constexpr cfgopt_t(const char *_n, ushort *_p, ushort _flags) : name(_n), ptr(_p), flags(IDPOPT_BIT | IDPOPT_BIT_USHORT), bit_flags(_flags) {}
constexpr cfgopt_t(const char *_n, uint32 *_p, uint32 _flags) : name(_n), ptr(_p), flags(IDPOPT_BIT), bit_flags(_flags) {}
// IDPOPT_I64
constexpr cfgopt_t(const char *_n, int64 *_p) : name(_n), ptr(_p), flags(IDPOPT_I64), buf_size(0) {}
constexpr cfgopt_t(const char *_n, uint64 *_p) : name(_n), ptr(_p), flags(IDPOPT_I64 | IDPOPT_NUM_UNS), buf_size(0) {}
// IDPOPT_I64 + ranges
constexpr cfgopt_t(const char *_n, int64 *_p, int64 _min, int64 _max)
: name(_n), ptr(_p), flags(IDPOPT_I64 | IDPOPT_I64_RANGES), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, uint64 *_p, uint64 _min, uint64 _max)
: name(_n), ptr(_p), flags(IDPOPT_I64 | IDPOPT_I64_UNS | IDPOPT_I64_RANGES), num_range(int64(_min), int64(_max)) {}
// IDPOPT_CST
constexpr cfgopt_t(const char *_n, cfgopt_handler_t *_p)
: name(_n), hnd(_p), flags(IDPOPT_CST), buf_size(0) {}
// IDPOPT_CST + params
constexpr cfgopt_t(const char *_n, cfgopt_handler2_t *_p, int64 _p1=0, int64 _p2=0)
: name(_n), hnd2(_p), flags(IDPOPT_CST | IDPOPT_CST_PARAMS), params(_p1, _p2) {}
// configuration option based on the offset of a structure member
// IDPOPT_STR
template<class T>
constexpr cfgopt_t(const char *_n, qstring T:: *, size_t _mbroff, bool _long = true)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF | IDPOPT_STR | IDPOPT_STR_QSTRING | (_long ? IDPOPT_STR_LONG : 0)),
buf_size(0)
{}
#define CFGOPT_QS(nm, cfgt, cfgm, _long) \
cfgopt_t(nm, &cfgt::cfgm, qoffsetof(cfgt, cfgm), _long)
#define CFGOPT_INNER_QS(nm, cfgt, cfgm, mt, mf, _long) \
cfgopt_t(nm, &mt::mf, qoffsetof(cfgt, cfgm) + qoffsetof(mt, mf), _long)
// IDPOPT_NUM
#define CTR_CFGOPT(ctrtype, ctrflags) \
template<class T> \
constexpr cfgopt_t(const char *_n, ctrtype T:: *, size_t _mbroff) \
: name(_n), \
mbroff(_mbroff), \
flags(IDPOPT_MBROFF|IDPOPT_NUM|ctrflags), \
buf_size(0) \
{}
CTR_CFGOPT(int, 0)
CTR_CFGOPT(uint, IDPOPT_NUM_UNS)
CTR_CFGOPT(char, IDPOPT_NUM_CHAR)
CTR_CFGOPT(uchar, IDPOPT_NUM_UNS|IDPOPT_NUM_CHAR)
CTR_CFGOPT(short, IDPOPT_NUM_SHORT)
CTR_CFGOPT(ushort, IDPOPT_NUM_SHORT|IDPOPT_NUM_UNS)
#undef CTR_CFGOPT
#define CFGOPT_N(nm, cfgt, cfgm) \
cfgopt_t(nm, &cfgt::cfgm, qoffsetof(cfgt, cfgm))
#define CFGOPT_INNER_N(nm, cfgt, cfgm, mt, mf) \
cfgopt_t(nm, &mt::mf, qoffsetof(cfgt, cfgm) + qoffsetof(mt, mf))
// IDPOPT_NUM + ranges
#define CTR_CFGOPT(ctrtype, ctrflags) \
template<class T> \
constexpr cfgopt_t(const char *_n, ctrtype T:: *, size_t _mbroff, int64 _min, int64 _max) \
: name(_n), \
mbroff(_mbroff), \
flags(IDPOPT_MBROFF|IDPOPT_NUM|IDPOPT_NUM_RANGE|ctrflags), \
num_range(_min, _max) \
{}
CTR_CFGOPT(int, 0)
CTR_CFGOPT(uint, IDPOPT_NUM_UNS)
CTR_CFGOPT(char, IDPOPT_NUM_CHAR)
CTR_CFGOPT(uchar, IDPOPT_NUM_UNS|IDPOPT_NUM_CHAR)
CTR_CFGOPT(short, IDPOPT_NUM_SHORT)
CTR_CFGOPT(ushort, IDPOPT_NUM_SHORT|IDPOPT_NUM_UNS)
#undef CTR_CFGOPT
#define CFGOPT_R(nm, cfgt, cfgm, min, max) \
cfgopt_t(nm, &cfgt::cfgm, qoffsetof(cfgt, cfgm), min, max)
#define CFGOPT_INNER_R(nm, cfgt, cfgm, mt, mf, min, max) \
cfgopt_t(nm, &mt::mf, qoffsetof(cfgt, cfgm) + qoffsetof(mt, mf), min, max)
// IDPOPT_BIT
#define CTR_CFGOPT(ctrtype, ctrflags) \
template<class T> \
constexpr cfgopt_t(const char *_n, ctrtype T:: *, size_t _mbroff, ctrtype _flags) \
: name(_n), \
mbroff(_mbroff), \
flags(IDPOPT_MBROFF|IDPOPT_BIT|ctrflags), \
bit_flags(_flags) \
{}
CTR_CFGOPT(bool, IDPOPT_BIT_BOOL);
CTR_CFGOPT(uchar, IDPOPT_BIT_UCHAR);
CTR_CFGOPT(ushort, IDPOPT_BIT_USHORT);
CTR_CFGOPT(uint32, 0);
#undef CTR_CFGOPT
#define CFGOPT_B(nm, cfgt, cfgm, _flags) \
cfgopt_t(nm, &cfgt::cfgm, qoffsetof(cfgt, cfgm), _flags)
#define CFGOPT_INNER_B(nm, cfgt, cfgm, mt, mf, _flags) \
cfgopt_t(nm, &mt::mf, qoffsetof(cfgt, cfgm) + qoffsetof(mt, mf), _flags)
// IDPOPT_I64
template<class T>
constexpr cfgopt_t(const char *_n, int64 T:: *, size_t _mbroff)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF|IDPOPT_I64),
buf_size(0)
{}
template<class T>
constexpr cfgopt_t(const char *_n, uint64 T:: *, size_t _mbroff)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF|IDPOPT_I64|IDPOPT_NUM_UNS),
buf_size(0)
{}
// IDPOPT_I64 + ranges
template<class T>
constexpr cfgopt_t(const char *_n, int64 T:: *, size_t _mbroff, int64 _min, int64 _max)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF|IDPOPT_I64|IDPOPT_I64_RANGES),
num_range(_min, _max)
{}
template<class T>
constexpr cfgopt_t(const char *_n, uint64 T:: *, size_t _mbroff, uint64 _min, uint64 _max)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF|IDPOPT_I64|IDPOPT_I64_UNS|IDPOPT_I64_RANGES),
num_range(int64(_min), int64(_max))
{}
// IDPOPT_CST + params
constexpr cfgopt_t(const char *_n, cfgopt_handler3_t *_p, int64 _p1=0, int64 _p2=0)
: name(_n), hnd3(_p), flags(IDPOPT_MBROFF|IDPOPT_CST), params(_p1, _p2) {}
int type() const { return flags & 0xf; }
int qualifier() const { return flags & 0xf000000; }
const char *apply(int vtype, const void *vdata, void *obj=nullptr) const
{
return cfgopt_t__apply2(this, vtype, vdata, obj);
}
};
/// Parse the input, and apply options.
///
/// \param input input file name, or string
/// \param is_file is input a string, or a file name
/// \param opts options destcriptions
/// \param nopts the number of entries present in the 'opts' array
/// \param defhdlr a handler to be called, if a directive couldn't be found in 'opts'
/// \param defines a list of preprocessor identifiers to define (so it is
/// possible to use #ifdef checks in the file.)
/// NB: the actual identifier defined by the parser will be
/// surrounded with double underscores (e.g., passing 'FOO'
/// will result in '__FOO__' being defined)
/// Additionally, the parser will also define a similar macro
/// with the current processor name (e.g., __ARM__)
/// \param ndefines the number of defines in the list
/// \param obj see cfgopt_t constructor based on the offset of a structure member
/// \return true if parsing finished without errors, false if there was a
/// syntax error, callback returned an error, or no file was found
/// at all.
idaman bool ida_export read_config(
const char *input,
bool is_file,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = NULL,
const char *const *defines = NULL,
size_t ndefines = 0);
idaman bool ida_export read_config2(
const char *input,
bool is_file,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = nullptr,
const char *const *defines = nullptr,
size_t ndefines = 0,
void *obj = nullptr);
inline bool read_config_file2(
const char *filename,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = nullptr,
const char *const *defines = nullptr,
size_t ndefines = 0,
void *obj = nullptr)
{
return read_config2(filename, true, opts, nopts, defhdlr, defines, ndefines, obj);
}
/// Search for all IDA system files with the given name.
/// This function will search, in that order, for the following files:
/// -# %IDADIR%/cfg/<file>
/// -# for each directory 'ONEDIR' in %IDAUSR%: %ONEDIR%/cfg/<file>
///
/// For each directive in each of those files, the same processing as
/// that of read_config will be performed.
inline bool read_config_file(
const char *filename,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = NULL,
const char *const *defines = NULL,
size_t ndefines = 0)
{
return read_config(filename, true, opts, nopts, defhdlr, defines, ndefines);
}
/// For each directive in 'string', the same processing as that of
/// read_config will be performed.
inline bool read_config_string(
const char *string,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = NULL,
const char *const *defines = NULL,
size_t ndefines = 0)
{
return read_config(string, false, opts, nopts, defhdlr, defines, ndefines);
}
/// Process one or more config directive(s).
/// \param directive the directives to process
/// \param priority priority \ref IDPOPT_RET
/// In the case of errors this function displays a message and exits.
idaman void ida_export process_config_directive(
const char *directive,
int priority=IDPOPT_PRI_HIGH);
/// Register array of config options.
/// This function can be used by a plugin to register the config options.
/// After registering an option, it becomes usable by the
/// process_config_directive() function.
/// \param opts array of config options
/// \param nopts number of options to install. 0 means uninstall
/// \param cb callback that will be invoked upon changing a config option
/// \param obj see cfgopt_t constructor based on the offset of a structure member
/// \return success
typedef void idaapi config_changed_cb_t(const cfgopt_t &opt, int vtype, const void *vdata);
idaman bool ida_export register_cfgopts(
const cfgopt_t opts[],
size_t nopts,
config_changed_cb_t cb=nullptr,
void *obj=nullptr);
/// Get one of config parameters defined by CC_PARMS in ida.cfg.
/// All parameters for all compilers are stored in local map during last read
/// of ida.cfg - this function just returns previously stored parameter value for
/// given compiler (NULL if no such parameter)
idaman const char *ida_export cfg_get_cc_parm(comp_t compid, const char *name);
/// Get header path config parameter from ida.cfg.
/// Also see cfg_get_cc_parm()
inline const char *cfg_get_cc_header_path(comp_t compid)
{
return cfg_get_cc_parm(compid, "HEADER_PATH");
}
/// Get predefined macros config parameter from ida.cfg.
/// Also see cfg_get_cc_parm()
inline const char *cfg_get_cc_predefined_macros(comp_t compid)
{
return cfg_get_cc_parm(compid, "PREDEFINED_MACROS");
}
#endif // _CONFIG_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -1,269 +0,0 @@
/*
* CPP/D/Swift Demangler.
* Copyright (c) 2000-2018 by Iouri Kharon.
* E-mail: yjh@styx.cabel.net
*
* ALL RIGHTS RESERVED.
*
*/
#ifndef _DEMANGLE_HPP
#define _DEMANGLE_HPP
// int32 result code
#define ME_INTERR -1 // Internal error
#define ME_PARAMERR -2 // Input parameters are wrong
#define ME_ILLSTR -3 // Incorrectly mangled name
#define ME_SMALLANS -4 // Output buffer is too small
// This code is possible only with the 'old' calling
// form. With the new calling form the output buffer
// will have '...' as the last characters and the
// result code or'ed with the sign bit
#define ME_FRAME -5 // Partial demanging is possible (the input name has
// unrecognized suffix)
#define ME_NOCOMP -6 // Could not determine the compiler
#define ME_ERRAUTO -7 // Specified compiler is impossible for the input name
#define ME_NOHASHMEM -8 // Out of internal indexes-most likely bad input name
#define ME_NOSTRMEM -9 // Out of internal buffers (can't be!:)
#define ME_NOERROR_LIMIT -10 // Lowest error number. Lower values
// signal about the truncated output name
// (the output buffer is too small)
#define M_PRCMSK 0x0000000F // If = 0, then data
#define MT_DEFAULT 0x00000001 // 1 - default (for watcom/gnu only this)
#define MT_CDECL 0x00000002 // 2 - __cdecl
#define MT_PASCAL 0x00000003 // 3 - __pascal
#define MT_STDCALL 0x00000004 // 4 - __stdcall
#define MT_FASTCALL 0x00000005 // 5 - __fastcall
#define MT_THISCALL 0x00000006 // 6 - __thiscall [ms & bc => pragma only]
#define MT_FORTRAN 0x00000007 // 7 - __fortran
#define MT_SYSCALL 0x00000008 // 8 - __syscall [without ms]
#define MT_INTERRUPT 0x00000009 // 9 - __interrupt (only with __cdecl!)
#define MT_MSFASTCALL 0x0000000A // A - __msfastcall (bc)
#define MT_CLRCALL 0x0000000B // B - __clrcall (vc7)
#define MT_DMDCALL 0x0000000C // C - __dcall (dm D language abi)
#define MT_VECTORCALL 0x0000000D // D - __vectorcall (vc13)
#define MT_REGCALL 0x0000000E // E - __regcall (icl, clang)
// reserved
#define MT_LOCALNAME 0x0000000F // f - might be function or data. Currently
// is used only for bc - as the
// identifier for local pascal labels
#define M_SAVEREGS 0x00000010 // For functions with "__saveregs"
#define M_CLASS 0x000000E0 // 0 - no keyword (not a member field)
#define MT_PUBLIC 0x00000020 // 1 - public
#define MT_PRIVATE 0x00000040 // 2 - private
#define MT_PROTECT 0x00000060 // 3 - protected
#define MT_MEMBER 0x00000080 // 4 - undetermined (bc/wat/gcc)
#define MT_VTABLE 0x000000A0 // 5 - vtable (bc/gnu)
#define MT_RTTI 0x000000C0 // 6 - typeinfo table (gcc3), witness table (Swift)
// reserved
#define M_PARMSK 0x0000FF00 // Parameter number mask (excluding ellipsis)
// 255 - >= 255
#define MT_PARSHF 8 // shift to PARMSK
#define MT_PARMAX 0xFF // Number limiter
// ATT: when CC is __vectorcall and mode is 'C'
// real argscount is unknown. This number is
// total sizeof of all arguments divided to
// sizeof of defptr
#define M_ELLIPSIS 0x00010000 // The function _certainly_ has '...'
#define MT_VOIDARG 0x0001FF00 // If = 0, the func(void), i.e. no parameters
#define M_STATIC 0x00020000 // static
// gcc3 - static data in a function
// might be encountered in object files and
// (possibly) in binaries with debug info
#define M_VIRTUAL 0x00040000 // virtual
// NOTE: for (D) not virtual -- this (counted!)
#define M_AUTOCRT 0x00080000 // Most likely "autogenerated" function (data)
// NOTE: +M_STATIC => "__linkproc__" (bc)
#define M_TYPMASK 0x00700000 // Special functions (0-regular function)
#define MT_OPERAT 0x00100000 // 1 - operator
#define MT_CONSTR 0x00200000 // 2 - constructor
#define MT_DESTR 0x00300000 // 3 - destructor
#define MT_CASTING 0x00400000 // 4 - type conversion
#define MT_CLRCDTOR 0x00500000 // 5 - delphi2010 CLR ctor/dtor for packages
// reserved
#define M_TRUNCATE 0x00800000 // Name was truncated by the compiler (bc/va)
#define M_THUNK 0x01000000 // [thunk]:
#define M_ANONNSP 0x02000000 // ms => Anonymous Namespace for field
// gc3 => Item placed in Anonymous namespace
// wat => anonymous_enum
// bc => + TMPLNAM = PascalTemplate (for DCC)
// If separate - "automatic" except_t
// from CBuilder for "external" variables
// or a template for global object
// constructor/destructor tables (for CBuilder
// as well)
#define M_TMPLNAM 0x04000000 // ms => template name (?)
// wat =>
// bc => template name => its description table
// gc3 => any template funciton/data
#define M_DBGNAME 0x08000000 // ms => CV:
// wat => xxxx: (T?xxxx-form)
// bc => old pascal format (capitalized)
// gc3 => unicode symbols or 'vendor-extension'
// qualifiers are present
#define M_COMPILER 0x70000000 // Compiler mask (0-unknown)
#define MT_MSCOMP 0x10000000 // 1 - microsoft/symantec
#define MT_BORLAN 0x20000000 // 2 - borland
#define MT_WATCOM 0x30000000 // 3 - watcom
#define MT_OTHER 0x40000000 // 4 - digital mars D language (start: _D)
// - apple Swift language (start: [_]_T)
// !!! The following definitions must be last and in this order!
#define MT_GNU 0x50000000 // 5 - GNU - (over VA for autodetection)
#define MT_GCC3 0x60000000 // 6 - gcc-v3
// In the short form this answer is possible
// for GNU/VA as well, but gcc3 can be
// explicitly requested only with it.
// Autodetection works but not very reliable.
#define MT_VISAGE 0x70000000 // 7 - Visual Age - never autodetected
// In the short form this answer means VA
// or GNU. In the automatic mode GNU will
// be used!
//---------------------------------------------------------------------------
// Flags to inhibit different parts of the demangled name
#define MNG_PTRMSK 0x7 // Memory model mask
// DO NOT change order in this group (PtrType)
#define MNG_DEFNEAR 0x0 // inhibit near, display everything else
#define MNG_DEFNEARANY 0x1 // inhibit near/__ptr64, display everything else
#define MNG_DEFFAR 0x2 // inhibit far, display everything else
#define MNG_NOPTRTYP16 0x3 // inhibit everything (disables vc7-extensions)
#define MNG_DEFHUGE 0x4 // inhibit huge, display everything else
#define MNG_DEFPTR64 0x5 // inhibit __pt64, display everything else
// ATT: in 64bit must be + MNG_NOTYPE|MNG_NOCALLC
#define MNG_DEFNONE 0x6 // display everything
#define MNG_NOPTRTYP 0x7 // inhibit everything
//
#define MNG_NODEFINIT 0x00000008 // Inhibit everything except the main name
// This flag is not recommended
// for __fastcall/__stdcall GCC3 names
// because there is a high probablity of
// incorrect demangling. Use it only when
// you are sure that the input is a
// cygwin/mingw function name
//
#define MNG_NOUNDERSCORE 0x00000010 // Inhibit underscores in __ccall, __pascal... +
#define MNG_NOTYPE 0x00000020 // Inhibit callc&based
#define MNG_NORETTYPE 0x00000040 // Inhibit return type of functions
#define MNG_NOBASEDT 0x00000080 // Inhibit base types
// NOTE: also inhibits "__linkproc__"
// NOTE: -"- 'implicit self types' (Swift)
#define MNG_NOCALLC 0x00000100 // Inhibit __pascal/__ccall/etc
// NOTE: also inhibits "extern (cc)" (D)
#define MNG_NOPOSTFC 0x00000200 // Inhibit postfix const
#define MNG_NOSCTYP 0x00000400 // Inhibit public/private/protected
// NOTE: also inhibits in/out/lazy for args (D)
// NOTE: -"- dynamic/super/override/... (Swift)
#define MNG_NOTHROW 0x00000800 // Inhibit throw description
// NOTE: also inhibits all funcattr (D)
#define MNG_NOSTVIR 0x00001000 // Inhibit "static" & "virtual"
// NOTE: also inhibits (D) top-level procs (<=)
#define MNG_NOECSU 0x00002000 // Inhibit class/struct/union/enum[/D:typedef]
#define MNG_NOCSVOL 0x00004000 // Inhibit const/volatile/restrict
// NOTE: also inhibits __unaligned (vc)
// NOTE: also inhibits transaction_safe(gcc)
// NOTE: also inhibits shared/immutable (D)
// NOTE: also inhibits prefix/postfix/infix/inout (Swift)
#define MNG_NOCLOSUR 0x00008000 // Inhibit __closure for borland
// 'reabstract thunk' description (Swift)
#define MNG_NOUNALG 0x00010000 // Inhibit __unaligned (see NOCSVOL)
// NOTE: also inhibit transaction_safe (see NOCSVOL)
#define MNG_NOMANAGE 0x00020000 // Inhibit __pin/__box/__gc for ms(.net)
// NOTE: also inhibit archetype/witness (Swift)
// NOTE: also ingibit [abi:xxxx] (gcc3)
#define MNG_NOMODULE 0x00040000 // Inhibit module names (Swift)
// 0x00080000
//++++++
#define MNG_SHORT_S 0x00100000 // signed (int) is displayed as s(int)
#define MNG_SHORT_U 0x00200000 // unsigned (int) is displayed as u(int)
#define MNG_ZPT_SPACE 0x00400000 // Display space after comma in the arglist
// NOTE: also spaces in name:type pair (Swift)
// and around Swift return clause ->
#define MNG_DROP_IMP 0x00800000 // Inhibit __declspec(dllimport)
//
// 0x01000000
#define MNG_IGN_ANYWAY 0x02000000 // Ingore '_nn' at the end of name
#define MNG_IGN_JMP 0x04000000 // Ingore 'j_' at the beginning of name
#define MNG_MOVE_JMP 0x08000000 // Move 'j_' prefix to the demangled name
// If both MNG_IGN_JMP and MNG_MOVE_JMP
// are set then move the prefix only if
// the name was not truncated
//
#define MNG_COMPILER_MSK 0x70000000 // Compiler mask (0-autodetect)
#define MNG_SHORT_FORM (MNG_NOTYPE|MNG_NORETTYPE|MNG_NOPOSTFC|MNG_NOPTRTYP \
| MNG_NOSCTYP|MNG_NOTHROW|MNG_NOSTVIR|MNG_NOECSU|MNG_NOCLOSUR \
| MNG_SHORT_U|MNG_DROP_IMP|MNG_NOUNALG|MNG_NOMANAGE \
| MNG_IGN_JMP|MNG_MOVE_JMP|MNG_IGN_ANYWAY)
#define MNG_LONG_FORM (MNG_ZPT_SPACE | MNG_IGN_JMP | MNG_IGN_ANYWAY | MNG_NOPTRTYP)
// The description of the following symbol is in the notes
#define MNG_CALC_VALID (MNG_COMPILER_MSK|MNG_IGN_JMP|MNG_IGN_ANYWAY)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#ifndef H2ASH
#if !defined(NO_OBSOLETE_FUNCS) || defined(__DEFINE_DEMANGLE__)
typedef int32 ida_export demangler_t(
char *answer,
uint answer_length,
const char *str,
uint32 disable_mask);
idaman demangler_t demangle;
#endif
// If answer_length == 0 then no demangling is performed neither. The function
// will check if demangling is possible and what compiler is used to mangle
// the name. If the name cannot be demangled then the function will return 0.
// NOTE: the answer MT_MSCOMP+1 means __msfastcall
// (or borland class name with "_4" suffix) and the demangling is possible
// either as MS (__fastcall) or as bc (__msfastcall)
// NOTE: the answer MT_GCC3+1 means POSSIBLE mingw/cygwin with
// __stdcall/__fastcall but it might also mean ms-stdcall.
// In essense it means that the demangler cannot determine the compiler
// precisely.
// It also means that the demangling is possible in the gcc3 mode
// ONLY when the compiler is explicitly set to gcc3 and MNG_NODEFINIT
// bit is not set.
// If answer == NULL then the demangler will return check if the demangling
// is possible and only return the flags.
// In this case answer_length should be enough to hold the demangled name.
// NOTE: If int32(answer_length) < 0 then the demangler will calcuate the
// the number of purged bytes for the given name. In this case
// disable_mask may contain only bits included in MNG_CALC_VALID,
// and -answer_length must be equal to the register size (e.g.
// sizeof(uint16/uint32/uint64)). The value of the register size
// is used to check the numeric value in the ms stdcall/fastcall
// encoding (it is used in the gcc mode too).
// if return value <= 0 - no purged bytes or valid information.
// If (value & 1) != 0 - ms stdcall (definite npurged is value-1.
// If (value & 1) == 0 - 'encoded' counter (not implemented yet).
// If answer != NULL (and answer_length != 0) - perform demangling and fill out.
// NOTE: if int32(answer_length) < 0 then the buffer size will be -answer_length
// but 'answer' is interpreted not as a pointer to the output buffer but
// as a pointer to pointer to the output buffer (char**).
// In this case if the function succeeds,a pointer to the answer end
// will be returned in the pointer (like stpcpy). In this form 'answer'
// cannot be NULL and *(char**)answer cannot be NULL.
// answer_length must be greater than 9 for the 'truncated' answer.
typedef int mangled_name_type_t;
const mangled_name_type_t MANGLED_CODE = 0;
const mangled_name_type_t MANGLED_DATA = 1;
const mangled_name_type_t MANGLED_UNKNOWN = 2;
idaman mangled_name_type_t ida_export get_mangled_name_type(const char *name);
#endif // H2ASH
#endif // _DEMANGLE_HPP

View File

@@ -1,621 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _DISKIO_HPP
#define _DISKIO_HPP
#include <stdio.h>
/*! \file diskio.hpp
\brief File I/O functions for IDA
You should not use standard C file I/O functions in modules.
Use functions from this header, pro.h and fpro.h instead.
This file also declares a call_system() function.
*/
//-------------------------------------------------------------------------
// S E A R C H F O R F I L E S
//-------------------------------------------------------------------------
/// Get IDA directory (if subdir==NULL)
/// or the specified subdirectory (see \ref SUBDIR)
idaman THREAD_SAFE const char *ida_export idadir(const char *subdir);
/// Search for IDA system file.
/// This function searches for a file in:
/// -# each directory specified by %IDAUSR%
/// -# ida directory [+ subdir]
/// and returns the first match.
/// \param[out] buf buffer for file name
/// \param bufsize size of output buffer
/// \param filename name of file to search
/// \param subdir if specified, the file is looked for in the specified subdirectory
/// of the ida directory first (see \ref SUBDIR)
/// \return NULL if not found, otherwise a pointer to full file name.
idaman THREAD_SAFE char *ida_export getsysfile(
char *buf,
size_t bufsize,
const char *filename,
const char *subdir);
/// \defgroup SUBDIR IDA subdirectories
/// Passed as 'subdir' parameter to idadir(), getsysfile(), and others.
//@{
#define CFG_SUBDIR "cfg"
#define IDC_SUBDIR "idc"
#define IDS_SUBDIR "ids"
#define IDP_SUBDIR "procs"
#define LDR_SUBDIR "loaders"
#define SIG_SUBDIR "sig"
#define TIL_SUBDIR "til"
#define PLG_SUBDIR "plugins"
#define THM_SUBDIR "themes"
//@}
/// Get user ida related directory.
/// \code
/// - if $IDAUSR is defined:
/// - the first element in $IDAUSR
/// - else
/// - default user directory ($HOME/.idapro or %APPDATA%Hex-Rays/IDA Pro)
/// \endcode
idaman THREAD_SAFE const char *ida_export get_user_idadir(void);
/// Get list of directories in which to find a specific IDA resource
/// (see \ref SUBDIR). The order of the resulting list is as follows:
/// \code
/// - [$IDAUSR/subdir (0..N entries)]
/// - $IDADIR/subdir
/// \endcode
/// \param[out] dirs output vector for directory names
/// \param subdir name of the resource to list
/// \param flags \ref IDA_SUBDIR_ bits
/// \return number of directories appended to 'dirs'
idaman THREAD_SAFE int ida_export get_ida_subdirs(qstrvec_t *dirs, const char *subdir, int flags=0);
/// \defgroup IDA_SUBDIR_ Subdirectory modification flags
/// Passed as 'flags' parameter to get_ida_subdirs()
//@{
#define IDA_SUBDIR_IDP 0x0001 ///< append the processor name as a subdirectory
#define IDA_SUBDIR_IDADIR_FIRST 0x0002 ///< $IDADIR/subdir will be first, not last
#define IDA_SUBDIR_ONLY_EXISTING 0x0004 ///< only existing directories will be present
//@}
/// Get a folder location by CSIDL (see \ref CSIDL).
/// Path should be of at least MAX_PATH size
idaman THREAD_SAFE bool ida_export get_special_folder(char *buf, size_t bufsize, int csidl);
/// \defgroup CSIDL Common CSIDLs
/// Passed as 'csidl' parameter to get_special_folder()
//@{
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
#endif
#ifndef CSIDL_LOCAL_APPDATA
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
#ifndef CSIDL_PROGRAM_FILES
#define CSIDL_PROGRAM_FILES 0x0026
#endif
#ifndef CSIDL_PROGRAM_FILES_COMMON
#define CSIDL_PROGRAM_FILES_COMMON 0x002b
#endif
#ifndef CSIDL_PROGRAM_FILESX86
#define CSIDL_PROGRAM_FILESX86 0x002a
#endif
//@}
/// Enumerate files in the specified directory.
/// \param[out] answer buffer to contain the file name for which
/// file_enumerator_t::visit_file returns non-zero value
/// (may be NULL)
/// \param answer_size size of 'answer'
/// \param path directory to enumerate files in
/// \param fname mask of file names to enumerate
/// \param fv file_enumerator_t::visit_file function called for each file
/// - file: full file name (with path)
/// - if returns non-zero value, the enumeration
/// is stopped and the return code is
/// is returned to the caller.
/// the callback function
/// \return zero or the code returned by 'func'
struct file_enumerator_t
{
virtual int visit_file(const char *file) = 0;
DEFINE_VIRTUAL_DTOR(file_enumerator_t)
};
idaman THREAD_SAFE int ida_export enumerate_files2(
char *answer,
size_t answer_size,
const char *path,
const char *fname,
file_enumerator_t &fv);
//-------------------------------------------------------------------------
// O P E N / R E A D / W R I T E / C L O S E F I L E S
//-------------------------------------------------------------------------
/// \name Open/Read/Write/Close Files
/// There are two sets of "open file" functions.
/// The first set tries to open a file and returns success or failure.
/// The second set is "open or die": if the file cannot be opened
/// then the function will display an error message and exit.
//@{
/// Open a new file for write in text mode, deny write.
/// If a file exists, it will be removed.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenWT(const char *file);
/// Open a new file for write in binary mode, deny read/write.
/// If a file exists, it will be removed.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenWB(const char *file);
/// Open a file for read in text mode, deny none.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenRT(const char *file);
/// Open a file for read in binary mode, deny none.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenRB(const char *file);
/// Open a file for read/write in binary mode, deny write.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenM(const char *file);
/// Open a file for append in text mode, deny none.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenA(const char *file);
/// Open a file for read in binary mode or die, deny none.
/// If a file cannot be opened, this function displays a message and exits.
idaman THREAD_SAFE FILE *ida_export openR(const char *file);
/// Open a file for read in text mode or die, deny none.
/// If a file cannot be opened, this function displays a message and exits.
idaman THREAD_SAFE FILE *ida_export openRT(const char *file);
/// Open a file for read/write in binary mode or die, deny write.
/// If a file cannot be opened, this function displays a message and exits.
idaman THREAD_SAFE FILE *ida_export openM(const char *file);
//@}
//-------------------------------------------------------------------------
// F I L E S I Z E / D I S K S P A C E
//-------------------------------------------------------------------------
/// Get length of file in bytes.
/// \param fp pointer to file
idaman THREAD_SAFE uint64 ida_export qfsize(FILE *fp);
/// Change size of file or die.
/// If an error occurs, this function displays a message and exits.
/// \param fp pointer to file
/// \param size new size of file
idaman THREAD_SAFE void ida_export echsize(FILE *fp, uint64 size);
/// Get free disk space in bytes.
/// \param path name of any directory on the disk to get information about
idaman THREAD_SAFE uint64 ida_export get_free_disk_space(const char *path);
//-------------------------------------------------------------------------
// I / O P O R T D E F I N I T I O N S F I L E
//-------------------------------------------------------------------------
/// Describes an I/O port bit
struct ioport_bit_t
{
qstring name; ///< name of the bit
qstring cmt; ///< comment
};
DECLARE_TYPE_AS_MOVABLE(ioport_bit_t);
typedef qvector<ioport_bit_t> ioport_bits_t;
/// Describes an I/O port
struct ioport_t
{
ea_t address; ///< address of the port
qstring name; ///< name of the port
qstring cmt; ///< comment
ioport_bits_t bits; ///< bit names
void *userdata; ///< arbitrary data. initialized to NULL.
ioport_t()
: address(0), userdata(NULL)
{
}
};
DECLARE_TYPE_AS_MOVABLE(ioport_t);
typedef qvector<ioport_t> ioports_t;
/// Read i/o port definitions from a config file.
///
/// Each device definition in the input file begins with a line like this:
///
/// \v{.devicename}
///
/// After it go the port definitions in this format:
///
/// \v{portname address}
///
/// The bit definitions (optional) are represented like this:
///
/// \v{portname.bitname bitnumber}
///
/// Lines beginning with a space are ignored.
/// comment lines should be started with ';' character.
///
/// The default device is specified at the start of the file:
///
/// \v{.default device_name}
///
/// \note It is permissible to have a symbol mapped to several addresses
/// but all addresses must be unique.
/// \param[out] ports output vector
/// \param device contains device name to load. If default_device[0] == 0
/// then the default device is determined by .default directive
/// in the config file.
/// \param file config file name
/// \param callback callback to call when the input line can't be parsed normally.
/// - line: input line to parse
/// - returns error message. if NULL, then the line is parsed ok.
/// \return -1 on error or size of vector
idaman THREAD_SAFE ssize_t ida_export read_ioports(
ioports_t *ports,
qstring *device,
const char *file,
const char *(idaapi *callback)(
const ioports_t &ports,
const char *line)=NULL);
struct ioports_fallback_t
{
// returns success or fills ERRBUF with an error message
virtual bool handle(qstring *errbuf, const ioports_t &ports, const char *line) = 0;
};
idaman THREAD_SAFE ssize_t ida_export read_ioports2(
ioports_t *ports,
qstring *device,
const char *file,
ioports_fallback_t *callback=nullptr);
/// Allow the user to choose the ioport device.
/// \param[in,out] device in: contains default device name. If default_device[0] == 0
/// then the default device is determined by .default directive
/// in the config file.
/// out: the selected device name
/// \param file config file name
/// \param parse_params if present (non NULL), then defines a callback which
/// will be called for all lines not starting with a dot (.)
/// This callback may parse these lines are prepare a simple
/// processor parameter string. This string will be displayed
/// along with the device name.
/// If it returns #IOPORT_SKIP_DEVICE, then the current
/// device will not be included in the list.
/// \retval true the user selected a device, its name is in 'device'
/// \retval false the selection was cancelled. if device=="NONE" upon return,
/// then no devices were found in the configuration file
idaman THREAD_SAFE bool ida_export choose_ioport_device(
qstring *_device,
const char *file,
const char *(idaapi *parse_params)(
qstring *buf,
const char *line)=NULL);
struct choose_ioport_parser_t
{
/// \retval true and fill PARAM with a displayed string
/// \retval false and empty PARAM to skip the current device
/// \retval false and fill PARAM with an error message
virtual bool parse(qstring *param, const char *line) = 0;
};
idaman THREAD_SAFE bool ida_export choose_ioport_device2(
qstring *_device,
const char *file,
choose_ioport_parser_t *parse_params);
/// See 'parse_params' parameter to choose_ioport_device()
#define IOPORT_SKIP_DEVICE ((const char *)(-1))
/// Find ioport in the array of ioports
idaman THREAD_SAFE const ioport_t *ida_export find_ioport(const ioports_t &ports, ea_t address);
/// Find ioport bit in the array of ioports
idaman THREAD_SAFE const ioport_bit_t *ida_export find_ioport_bit(const ioports_t &ports, ea_t address, size_t bit);
//-------------------------------------------------------------------------
// S Y S T E M S P E C I F I C C A L L S
//-------------------------------------------------------------------------
/// Execute a operating system command.
/// This function suspends the interface (Tvision), runs the command
/// and redraws the screen.
/// \param command command to execute. If NULL, an interactive shell is activated
/// \return the error code returned by system() call
idaman THREAD_SAFE int ida_export call_system(const char *command);
//-------------------------------------------------------------------------
// L O A D E R I N P U T S O U R C E F U N C T I O N S
//-------------------------------------------------------------------------
/// \name Loader Input Source
/// Starting with v4.8 IDA can load and run remote files.
/// In order to do that, we replace the FILE* in the loader modules
/// with an abstract input source (linput_t). The source might be linked to
/// a local or remote file.
//@{
class linput_t; ///< loader input source
/// linput types
enum linput_type_t
{
LINPUT_NONE, ///< invalid linput
LINPUT_LOCAL, ///< local file
LINPUT_RFILE, ///< remote file (\dbg{open_file}, \dbg{read_file})
LINPUT_PROCMEM, ///< debugged process memory (read_dbg_memory())
LINPUT_GENERIC ///< generic linput
};
/// Read the input source.
/// If failed, inform the user and ask him if he wants to continue.
/// If he does not, this function will not return (loader_failure() will be called).
/// This function may be called only from loaders!
idaman void ida_export lread(linput_t *li, void *buf, size_t size);
/// Read the input source.
/// \return number of read bytes or -1
idaman ssize_t ida_export qlread(linput_t *li, void *buf, size_t size);
/// Read one line from the input source.
/// \return NULL if failure, otherwise 's'
idaman char *ida_export qlgets(char *s, size_t len, linput_t *li);
/// Read one character from the input source.
/// \return EOF if failure, otherwise the read character
idaman int ida_export qlgetc(linput_t *li);
/// Read multiple bytes and swap if necessary.
/// \param li input file
/// \param buf pointer to output buffer
/// \param size number of bytes to read
/// \param mf big endian?
/// \retval 0 ok
/// \retval -1 failure
idaman int ida_export lreadbytes(linput_t *li, void *buf, size_t size, bool mf);
/// Helper to define lread2bytes(), lread4bytes(), etc
#define DEF_LREADBYTES(read, type, size) \
/*! \brief Read a value from linput - also see lreadbytes() */ \
inline int idaapi read(linput_t *li, type *res, bool mf) \
{ return lreadbytes(li, res, size, mf); }
DEF_LREADBYTES(lread2bytes, int16, 2)
DEF_LREADBYTES(lread2bytes, uint16, 2)
DEF_LREADBYTES(lread4bytes, int32, 4)
DEF_LREADBYTES(lread4bytes, uint32, 4)
DEF_LREADBYTES(lread8bytes, int64, 8)
DEF_LREADBYTES(lread8bytes, uint64, 8)
#undef DEF_LREADBYTES
/// Read a zero-terminated string from the input.
/// If fpos == -1 then no seek will be performed.
idaman char *ida_export qlgetz(
linput_t *li,
int64 fpos,
char *buf,
size_t bufsize);
/// Get the input source size
idaman int64 ida_export qlsize(linput_t *li);
/// Set input source position.
/// \return the new position (not 0 as fseek!)
idaman qoff64_t ida_export qlseek(linput_t *li, qoff64_t pos, int whence=SEEK_SET);
/// Get input source position
inline qoff64_t idaapi qltell(linput_t *li) { return qlseek(li, 0, SEEK_CUR); }
/// Open loader input
idaman linput_t *ida_export open_linput(const char *file, bool remote);
/// Close loader input
idaman THREAD_SAFE void ida_export close_linput(linput_t *li);
/// Get FILE* from the input source.
/// If the input source is linked to a remote file, then return NULL.
/// Otherwise return the underlying FILE*
/// Please do not use this function if possible.
idaman THREAD_SAFE FILE *ida_export qlfile(linput_t *li);
/// Convert FILE * to input source.
/// Used for temporary linput_t objects - call unmake_linput() to free
/// the slot after the use.
idaman THREAD_SAFE linput_t *ida_export make_linput(FILE *fp);
/// Free an linput_t object (also see make_linput())
idaman THREAD_SAFE void ida_export unmake_linput(linput_t *li);
/// Generic linput class - may be used to create a linput_t instance for
/// any data source
struct generic_linput_t
{
/// \name Warning
/// The following two fields must be filled before calling create_generic_linput()
//@{
uint64 filesize; ///< input file size
uint32 blocksize; ///< preferred block size to work with
///< read/write sizes will be in multiples of this number.
///< for example, 4096 is a nice value
///< blocksize 0 means that the filesize is unknown.
///< the internal cache will be disabled in this case.
///< also, seeks from the file end will fail.
///< blocksize=-1 means error.
//@}
virtual ssize_t idaapi read(qoff64_t off, void *buffer, size_t nbytes) = 0;
DEFINE_VIRTUAL_DTOR(generic_linput_t)
};
/// Create a generic linput
/// \param gl linput description.
/// this object will be destroyed by close_linput()
/// using "delete gl;"
idaman THREAD_SAFE linput_t *ida_export create_generic_linput(generic_linput_t *gl);
/// Trivial memory linput
idaman THREAD_SAFE linput_t *ida_export create_bytearray_linput(const uchar *start, size_t size);
/// Create a linput for process memory.
/// This linput will use read_dbg_memory() to read data.
/// \param start starting address of the input
/// \param size size of the memory area to represent as linput
/// if unknown, may be passed as 0
idaman linput_t *ida_export create_memory_linput(ea_t start, asize_t size);
/// Get linput type
inline THREAD_SAFE linput_type_t idaapi get_linput_type(linput_t *li)
{
return *(linput_type_t *)li;
}
/// Object that will free an linput_t at destruction-time
typedef janitor_t<linput_t*> linput_janitor_t;
/// Free the linput_t
template <> inline linput_janitor_t::~janitor_t()
{
close_linput(resource);
}
//---------------------------------------------------------------------------
/// Helper class - adapts linput to be used in extract_... functions
/// as a data supplier (see kernwin.hpp)
class linput_buffer_t
{
public:
linput_buffer_t(linput_t *linput, int64 size=0): li(linput), lsize(size) {}
ssize_t read(void *buf, size_t n)
{
return qlread(li, buf, n);
}
bool eof()
{
if ( lsize == 0 )
lsize = qlsize(li);
return qltell(li) >= lsize;
}
protected:
linput_t *li;
private:
int64 lsize;
};
//@}
// -------------------------------------------------------------------------
#ifndef NO_OBSOLETE_FUNCS
idaman DEPRECATED THREAD_SAFE FILE *ida_export ecreate(const char *file);
idaman DEPRECATED THREAD_SAFE void ida_export eclose(FILE *fp);
idaman DEPRECATED THREAD_SAFE void ida_export eread(FILE *fp, void *buf, size_t size);
idaman DEPRECATED THREAD_SAFE void ida_export ewrite(FILE *fp, const void *buf, size_t size);
idaman DEPRECATED THREAD_SAFE void ida_export eseek(FILE *fp, qoff64_t pos);
idaman DEPRECATED THREAD_SAFE int ida_export enumerate_files(
char *answer,
size_t answer_size,
const char *path,
const char *fname,
int (idaapi*func)(const char *file,void *ud),
void *ud=NULL);
#endif
#endif // _DISKIO_HPP

View File

@@ -1,106 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _ENTRY_HPP
#define _ENTRY_HPP
/*! \file entry.hpp
\brief Functions that deal with entry points
Exported functions are considered as entry points as well.
IDA maintains list of entry points to the program.
Each entry point:
- has an address
- has a name
- may have an ordinal number
*/
/// Get number of entry points
idaman size_t ida_export get_entry_qty(void);
/// \defgroup AEF_ entry flags
/// Passed as 'flags' parameter to add_entry(ea_t, const char *, int)
//@{
#define AEF_UTF8 0x0 ///< the name is given in UTF-8 (default)
#define AEF_IDBENC 0x1 ///< the name is given in the IDB encoding;
///< non-ASCII bytes will be decoded accordingly
///< Specifying AEF_IDBENC also implies AEF_NODUMMY
#define AEF_NODUMMY 0x2 ///< automatically prepend the name with '_' if
///< it begins with a dummy suffix. See also AEF_IDBENC
//@}
/// Add an entry point to the list of entry points.
/// \param ord ordinal number
/// if ordinal number is equal to 'ea' then ordinal is not used
/// \param ea linear address
/// \param name name of entry point. If the specified location already
/// has a name, the old name will be appended to the regular
/// comment. If name == NULL, then the old name will be retained.
/// \param makecode should the kernel convert bytes at the entry point
/// to instruction(s)
/// \param flags See AEF_*
/// \return success (currently always true)
idaman bool ida_export add_entry(uval_t ord, ea_t ea, const char *name, bool makecode, int flags=AEF_UTF8);
/// Get ordinal number of an entry point.
/// \param idx internal number of entry point. Should be
/// in the range 0..get_entry_qty()-1
/// \return ordinal number or 0.
idaman uval_t ida_export get_entry_ordinal(size_t idx);
/// Get entry point address by its ordinal
/// \param ord ordinal number of entry point
/// \return address or #BADADDR
idaman ea_t ida_export get_entry(uval_t ord);
/// Get name of the entry point by its ordinal.
/// \param buf output buffer, may be NULL
/// \param ord ordinal number of entry point
/// \return size of entry name or -1
idaman ssize_t ida_export get_entry_name(qstring *buf, uval_t ord);
/// Rename entry point.
/// \param ord ordinal number of the entry point
/// \param name name of entry point. If the specified location already
/// has a name, the old name will be appended to a repeatable
/// comment.
/// \param flags See AEF_*
/// \return success
idaman bool ida_export rename_entry(uval_t ord, const char *name, int flags=AEF_UTF8);
/// Set forwarder name for ordinal.
/// \param ord ordinal number of the entry point
/// \param name forwarder name for entry point.
/// \param flags See AEF_*
/// \return success
idaman bool ida_export set_entry_forwarder(uval_t ord, const char *name, int flags=AEF_UTF8);
/// Get forwarder name for the entry point by its ordinal.
/// \param buf output buffer, may be NULL
/// \param ord ordinal number of entry point
/// \return size of entry forwarder name or -1
idaman ssize_t ida_export get_entry_forwarder(qstring *buf, uval_t ord);
#endif // _ENTRY_HPP

View File

@@ -1,371 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
* Enums and bitfields
* Bitfields will be abbreviated as "bf".
*
*/
#ifndef _ENUM_HPP
#define _ENUM_HPP
#include <nalt.hpp>
/*! \file enum.hpp
\brief Assembly level enum management
Enums and bitfields are represented as ::enum_t.
*/
typedef tid_t enum_t; ///< Enums and bitfields
typedef uval_t bmask_t; ///< unsigned value that describes a bitmask
///< a bit mask is 32/64 bits.
#define DEFMASK (bmask_t(-1)) ///< default bitmask
typedef uval_t const_t; ///< members of enums
/// Max number of identical constants allowed for one enum type
const uchar MAX_ENUM_SERIAL = 255;
/// Get number of declared ::enum_t types
idaman size_t ida_export get_enum_qty(void);
/// Get enum by its index in the list of enums (0..get_enum_qty()-1).
idaman enum_t ida_export getn_enum(size_t idx);
/// Get the index in the list of enums
idaman uval_t ida_export get_enum_idx(enum_t id);
/// Get enum by name
idaman enum_t ida_export get_enum(const char *name);
/// Is enum a bitfield?
/// (otherwise - plain enum, no bitmasks except for #DEFMASK are allowed)
idaman bool ida_export is_bf(enum_t id);
/// Is enum collapsed?
idaman bool ida_export is_enum_hidden(enum_t id);
/// Collapse enum
idaman bool ida_export set_enum_hidden(enum_t id, bool hidden);
/// Does enum come from type library?
idaman bool ida_export is_enum_fromtil(enum_t id);
/// Specify that enum comes from a type library
idaman bool ida_export set_enum_fromtil(enum_t id, bool fromtil);
/// Is a ghost copy of a local type?
idaman bool ida_export is_ghost_enum(enum_t id);
/// Specify that enum is a ghost copy of a local type
idaman bool ida_export set_enum_ghost(enum_t id, bool ghost);
/// Get name of enum
idaman ssize_t ida_export get_enum_name(qstring *out, enum_t id);
/// Get name of enum
/// \param[out] out buffer to hold the name
/// \param id enum id
/// \param flags \ref ENFL_
idaman ssize_t ida_export get_enum_name2(qstring *out, enum_t id, int flags=0);
/// \defgroup ENFL_ Enum name flags
/// Passed as 'flags' parameter to get_enum_name()
//@{
#define ENFL_REGEX 0x0001 ///< apply regular expressions to beautify the name
//@}
inline qstring get_enum_name(tid_t id, int flags=0)
{
qstring name;
get_enum_name2(&name, id, flags);
return name;
}
/// Get the width of a enum element
/// allowed values: 0 (unspecified),1,2,4,8,16,32,64
idaman size_t ida_export get_enum_width(enum_t id);
/// See comment for get_enum_width()
idaman bool ida_export set_enum_width(enum_t id, int width);
/// Get enum comment
idaman ssize_t ida_export get_enum_cmt(qstring *buf, enum_t id, bool repeatable);
/// Get the number of the members of the enum
idaman size_t ida_export get_enum_size(enum_t id);
/// Get flags determining the representation of the enum.
/// (currently they define the numeric base: octal, decimal, hex, bin) and signness.
idaman flags_t ida_export get_enum_flag(enum_t id);
/// Get a reference to an enum member by its name
idaman const_t ida_export get_enum_member_by_name(const char *name);
/// Get value of an enum member
idaman uval_t ida_export get_enum_member_value(const_t id);
/// Get the parent enum of an enum member
idaman enum_t ida_export get_enum_member_enum(const_t id);
/// Get bitmask of an enum member
idaman bmask_t ida_export get_enum_member_bmask(const_t id);
/// Find an enum member by enum, value and bitmask
/// \note if serial -1, return a member with any serial
idaman const_t ida_export get_enum_member(enum_t id, uval_t value, int serial, bmask_t mask);
/// \name Access to all used bitmasks in an enum
//@{
/// Get first bitmask in the enum (bitfield)
///
/// \param enum_id id of enum (bitfield)
/// \return the smallest bitmask for enum, or DEFMASK
///
idaman bmask_t ida_export get_first_bmask(enum_t id);
/// Get last bitmask in the enum (bitfield)
///
/// \param enum_id id of enum
/// \return the biggest bitmask for enum, or DEFMASK
idaman bmask_t ida_export get_last_bmask(enum_t id);
/// Get next bitmask in the enum (bitfield)
///
/// \param enum_id id of enum
/// \param value the current bitmask
/// \return value of a bitmask with value higher than the specified value, or DEFMASK
idaman bmask_t ida_export get_next_bmask(enum_t id, bmask_t bmask);
/// Get prev bitmask in the enum (bitfield)
///
/// \param enum_id id of enum
/// \param value the current bitmask
/// \return value of a bitmask with value lower than the specified value, or DEFMASK
idaman bmask_t ida_export get_prev_bmask(enum_t id, bmask_t bmask);
//@}
/// \name Access to all enum members with specified bitmask
/// \note these functions return values, not ::const_t!
//@{
idaman uval_t ida_export get_first_enum_member(enum_t id, bmask_t bmask=DEFMASK);
idaman uval_t ida_export get_last_enum_member(enum_t id, bmask_t bmask=DEFMASK);
idaman uval_t ida_export get_next_enum_member(enum_t id, uval_t value, bmask_t bmask=DEFMASK);
idaman uval_t ida_export get_prev_enum_member(enum_t id, uval_t value, bmask_t bmask=DEFMASK);
//@}
/// Get name of an enum member by const_t
idaman ssize_t ida_export get_enum_member_name(qstring *out, const_t id);
/// Get enum member's comment
idaman ssize_t ida_export get_enum_member_cmt(qstring *buf, const_t id, bool repeatable);
/// \name Access to all enum members with specified value and mask
/// A sample loop looks like this:
/// \code
/// const_t main_cid;
/// uchar serial;
/// for ( const_t cid=main_cid=get_first_serial_enum_member(&serial, id, v, mask);
/// cid != BADNODE;
/// cid = get_next_serial_enum_member(&serial, main_cid) )
/// {
/// ...
/// }
/// \endcode
/// The 'out_serial' argument of get_first_serial_enum_member/get_last_serial_enum_member can be NULL.
/// The 'in_out_serial' is required for the other functions.
//@{
idaman const_t ida_export get_first_serial_enum_member(uchar *out_serial, enum_t id, uval_t value, bmask_t bmask);
idaman const_t ida_export get_last_serial_enum_member(uchar *out_serial, enum_t id, uval_t value, bmask_t bmask);
idaman const_t ida_export get_next_serial_enum_member(uchar *in_out_serial, const_t first_cid);
idaman const_t ida_export get_prev_serial_enum_member(uchar *in_out_serial, const_t first_cid);
//@}
/// Enum member visitor - see for_all_enum_members().
/// Derive your visitor from this class.
struct enum_member_visitor_t
{
/// Implements action to take when enum member is visited.
/// \return nonzero to stop the iteration
virtual int idaapi visit_enum_member(const_t cid, uval_t value) = 0;
};
/// Visit all members of a given enum
idaman int ida_export for_all_enum_members(enum_t id, enum_member_visitor_t &cv);
/// Get serial number of an enum member
idaman uchar ida_export get_enum_member_serial(const_t cid);
/// Get corresponding type ordinal number
idaman int32 ida_export get_enum_type_ordinal(enum_t id);
/// Set corresponding type ordinal number
idaman void ida_export set_enum_type_ordinal(enum_t id, int32 ord);
//--------------------------------------------------------------------------
// MANIPULATION
/// Add new enum type.
/// - if idx==#BADADDR then add as the last idx
/// - if name==NULL then generate a unique name "enum_%d"
idaman enum_t ida_export add_enum(size_t idx, const char *name, flags_t flag);
/// Delete an enum type
idaman void ida_export del_enum(enum_t id);
/// Set serial number of enum.
/// Also see get_enum_idx().
idaman bool ida_export set_enum_idx(enum_t id, size_t idx);
/// Set 'bitfield' bit of enum (i.e. convert it to a bitfield)
idaman bool ida_export set_enum_bf(enum_t id, bool bf);
/// Set name of enum type
idaman bool ida_export set_enum_name(enum_t id,const char *name);
/// Set comment for enum type
idaman bool ida_export set_enum_cmt(enum_t id,const char *cmt,bool repeatable);
/// Set data representation flags
idaman bool ida_export set_enum_flag(enum_t id, flags_t flag);
/// Add member to enum type.
/// \return 0 if ok, otherwise one of \ref ENUM_MEMBER_
idaman int ida_export add_enum_member(
enum_t id,
const char *name,
uval_t value,
bmask_t bmask=DEFMASK);
/// \defgroup ENUM_MEMBER_ Add enum member result codes
/// Return values for add_enum_member()
//@{
#define ENUM_MEMBER_ERROR_NAME 1 ///< already have member with this name (bad name)
#define ENUM_MEMBER_ERROR_VALUE 2 ///< already have 256 members with this value
#define ENUM_MEMBER_ERROR_ENUM 3 ///< bad enum id
#define ENUM_MEMBER_ERROR_MASK 4 ///< bad bmask
#define ENUM_MEMBER_ERROR_ILLV 5 ///< bad bmask and value combination (~bmask & value != 0)
//@}
/// Delete member of enum type
idaman bool ida_export del_enum_member(enum_t id, uval_t value, uchar serial, bmask_t bmask);
/// Set name of enum member
idaman bool ida_export set_enum_member_name(const_t id, const char *name);
/// Set comment for enum member
inline bool set_enum_member_cmt(const_t id, const char *cmt, bool repeatable)
{
return set_enum_cmt(id, cmt, repeatable);
}
/// Is bitmask one bit?
inline THREAD_SAFE bool is_one_bit_mask(bmask_t mask)
{
return (mask & (mask-1)) == 0;
}
/// \name Work with the bitmask name & comment
//@{
idaman bool ida_export set_bmask_name(enum_t id, bmask_t bmask, const char *name);
idaman ssize_t ida_export get_bmask_name(qstring *out, enum_t id, bmask_t bmask);
idaman bool ida_export set_bmask_cmt(enum_t id, bmask_t bmask, const char *cmt, bool repeatable);
idaman ssize_t ida_export get_bmask_cmt(qstring *buf, enum_t id, bmask_t bmask, bool repeatable);
//@}
#endif // _ENUM_HPP

View File

@@ -1,96 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _ERR_H
#define _ERR_H
#include <errno.h>
/*! \file err.h
\brief Thread safe functions that deal with error codes
*/
/// Print error message to stderr (analog of perror)
idaman THREAD_SAFE AS_PRINTF(1, 0) void ida_export vqperror(const char *format, va_list va);
/// Get error description string.
/// if _qerrno=-1, get_qerrno() will be used
idaman THREAD_SAFE const char *ida_export qstrerror(error_t _qerrno);
/// A convenience function to generate error messages (returns "header: error message")
idaman THREAD_SAFE char *ida_export get_errdesc(const char *header, error_t _qerrno=-1);
/// Get error message for MS Windows error codes
idaman THREAD_SAFE char *ida_export winerr(int code);
/// errno or GetLastError() depending on the system.
idaman THREAD_SAFE int ida_export qerrcode(int new_code=-1);
/// Get error string corresponding to qerrcode().
/// if code == -1, then qerrcode() will be called.
idaman const char *ida_export qerrstr(int code=-1);
#ifdef __cplusplus
/// See vqperror()
THREAD_SAFE AS_PRINTF(1, 2) inline void qperror(const char *format, ...)
{
va_list va;
va_start(va, format);
vqperror(format, va);
va_end(va);
}
/// See set_qerrno()
THREAD_SAFE inline void set_errno(int code)
{
errno = code;
set_qerrno(eOS);
}
#endif
// Internal functions
/// \cond
// n=0..3
idaman THREAD_SAFE void ida_export set_error_data(int n, size_t data);
idaman THREAD_SAFE void ida_export set_error_string(int n, const char *str);
idaman THREAD_SAFE size_t ida_export get_error_data(int n);
idaman THREAD_SAFE const char *ida_export get_error_string(int n);
#define QPRM_TYPE(t,n,x) set_error_data(n-1, t(x))
#define QPRM_CHAR(n,x) QPRM_TYPE(char,n,x)
#define QPRM_SHORT(n,x) QPRM_TYPE(short,n,x)
#define QPRM_INT(n,x) QPRM_TYPE(int,n,x)
#define QPRM_INT32(n,x) QPRM_TYPE(int32,n,x)
#define QPRM_UCHAR(n,x) QPRM_TYPE(uchar,n,x)
#define QPRM_USHORT(n,x) QPRM_TYPE(ushort,n,x)
#define QPRM_UINT(n,x) QPRM_TYPE(uint,n,x)
#define QPRM_UINT32(n,x) QPRM_TYPE(uint32,n,x)
#define QPRM(n,x) set_error_string(n-1, x)
/// \endcond
#endif

View File

@@ -1,67 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
* EXE-file header layout
*
*/
#ifndef __EXEHDR_H
#define __EXEHDR_H
#pragma pack(push, 1)
struct exehdr
{
uint16 exe_ident;
#define EXE_ID 0x5A4D // 'MZ'
#define EXE_ID2 0x4D5A // 'ZM' (DOS works with this also)
uint16 PartPag;
uint16 PageCnt;
uint16 ReloCnt;
uint16 HdrSize;
uint16 MinMem;
uint16 MaxMem;
uint16 ReloSS;
uint16 ExeSP;
uint16 ChkSum;
uint16 ExeIP;
uint16 ReloCS;
uint16 TablOff;
uint16 Overlay;
/*
uint16 res[4]; // Reserved words
uint16 oemid; // OEM identifier (for e_oeminfo)
uint16 oeminfo; // OEM information; e_oemid specific
uint16 res2[10]; // Reserved words
uint32 lfanew; // File address of new exe header
*/
int32 CalcEXE_Length(void)
{
int32 len = PageCnt * 512L - HdrSize * 16;
if ( PartPag != 0 )
len -= 512 - PartPag;
return len;
}
void CalcEXE_Pages(int32 len)
{
PartPag = uint16(len % 512);
PageCnt = uint16(len / 512);
if ( PartPag != 0 )
PageCnt++;
}
};
struct exehdr_full: exehdr
{
uint16 res[4]; // Reserved words
uint16 oemid; // OEM identifier (for e_oeminfo)
uint16 oeminfo; // OEM information; e_oemid specific
uint16 res2[10]; // Reserved words
uint32 lfanew; // File address of new exe header
};
#define PSPsize 0x100
#define PE_PTROFF 0x3C
#pragma pack(pop)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,512 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef FIXUP_HPP
#define FIXUP_HPP
#include <nalt.hpp>
#include <segment.hpp>
/*! \file fixup.hpp
\brief Functions that deal with fixup information
A loader should setup fixup information using set_fixup().
*/
//--------------------------------------------------------------------------
/// Fixup information structure
typedef uint16 fixup_type_t; ///< see \ref fixup_type_t
/// \defgroup fixup_type_t Types of fixups
/// Fixup may be of standard or custom type. Standard types fall into
/// range 1..FIXUP_CUSTOM-1 and custom types fall into range
/// FIXUP_CUSTOM..MAX_UINT16.
/// \note Fixup type 0 is unused.
/// \name Fixup standard types
//@{
#define FIXUP_OFF8 13 ///< 8-bit offset
#define FIXUP_OFF16 1 ///< 16-bit offset
#define FIXUP_SEG16 2 ///< 16-bit base--logical segment base (selector)
#define FIXUP_PTR16 3 ///< 32-bit long pointer (16-bit base:16-bit
///< offset)
#define FIXUP_OFF32 4 ///< 32-bit offset
#define FIXUP_PTR32 5 ///< 48-bit pointer (16-bit base:32-bit offset)
#define FIXUP_HI8 6 ///< high 8 bits of 16bit offset
#define FIXUP_HI16 7 ///< high 16 bits of 32bit offset
#define FIXUP_LOW8 8 ///< low 8 bits of 16bit offset
#define FIXUP_LOW16 9 ///< low 16 bits of 32bit offset
#define V695_FIXUP_VHIGH 10 ///< obsolete
#define V695_FIXUP_VLOW 11 ///< obsolete
#define FIXUP_OFF64 12 ///< 64-bit offset
//#define FIXUP_ 0xE
#define FIXUP_CUSTOM 0x8000 ///< start of the custom types range
//@}
/// Is fixup processed by processor module?
inline THREAD_SAFE bool is_fixup_custom(fixup_type_t type)
{
return (type & FIXUP_CUSTOM) != 0;
}
/// \defgroup FIXUPF_ Fixup flags
/// Used by fixup_data_t
//@{
/// fixup is relative to the linear address `base'. Otherwise fixup is
/// relative to the start of the segment with `sel' selector.
#define FIXUPF_REL 0x0001
/// target is a location (otherwise - segment).
/// Use this bit if the target is a symbol rather than an offset from the
/// beginning of a segment.
#define FIXUPF_EXTDEF 0x0002
/// fixup is ignored by IDA
/// - disallows the kernel to convert operands
/// - this fixup is not used during output
#define FIXUPF_UNUSED 0x0004
/// fixup was not present in the input file
#define FIXUPF_CREATED 0x0008
/// additional flags. The bits from this mask are not stored in the database
/// and can be used by the loader at its discretion.
#define FIXUPF_LOADER_MASK 0xF0000000
//@}
struct fixup_handler_t;
struct fixup_data_t
{
protected:
fixup_type_t type; // fixup type
uint32 flags; // FIXUPF_... bits
uval_t base; // base for relative fixups
public:
sel_t sel; ///< selector of the target segment.
///< BADSEL means an absolute (zero based) target.
///< \sa FIXUPF_REL
ea_t off; ///< target offset
///< \note The target is calculated as
///< `get_base() + off`.
adiff_t displacement; ///< displacement (offset from the target)
public:
fixup_data_t()
: type(0),
flags(0),
base(0),
sel(BADSEL),
off(0),
displacement(0) {}
fixup_data_t(fixup_type_t type_, uint32 flags_ = 0)
: type(type_),
flags(flags_),
base(0),
sel(BADSEL),
off(0),
displacement(0) {}
/// Fixup type \ref fixup_type_t
fixup_type_t get_type(void) const { return type; }
void set_type(fixup_type_t type_) { type = type_; }
void set_type_and_flags(fixup_type_t type_, uint32 flags_ = 0)
{
type = type_;
flags = flags_;
}
bool is_custom(void) const; ///< \ref is_fixup_custom()
/// Fixup flags \ref FIXUPF_
uint32 get_flags() const { return flags; }
bool is_extdef(void) const { return (flags & FIXUPF_EXTDEF) != 0; }
void set_extdef(void) { flags |= FIXUPF_EXTDEF; }
void clr_extdef(void) { flags &= ~FIXUPF_EXTDEF; }
bool is_unused(void) const { return (flags & FIXUPF_UNUSED) != 0; }
void set_unused(void) { flags |= FIXUPF_UNUSED; }
void clr_unused(void) { flags &= ~FIXUPF_UNUSED; }
/// Is fixup relative?
bool has_base(void) const { return (flags & FIXUPF_REL) != 0; }
/// Is fixup artificial?
bool was_created(void) const { return (flags & FIXUPF_CREATED) != 0; }
/// Get base of fixup.
/// \note The target is calculated as `get_base() + off`.
/// \sa FIXUPF_REL
ea_t get_base() const
{
return has_base() ? base : sel != BADSEL ? sel2ea(sel) : 0;
}
/// Set base of fixup.
/// The target should be set before a call of this function.
void set_base(ea_t new_base)
{
ea_t target = get_base() + off;
flags |= FIXUPF_REL;
base = new_base;
off = target - base;
}
void set_sel(const segment_t *seg)
{
sel = seg == NULL ? BADSEL : seg->sel;
}
/// Set selector of fixup to the target.
/// The target should be set before a call of this function.
void set_target_sel()
{
ea_t target = get_base() + off;
set_sel(getseg(target));
flags &= ~FIXUPF_REL;
base = 0; // just in case
off = target - get_base();
}
void set(ea_t source) const; ///< \ref set_fixup()
bool get(ea_t source); ///< \ref get_fixup()
/// \ref get_fixup_handler()
const fixup_handler_t *get_handler() const;
/// \ref get_fixup_desc()
const char *get_desc(qstring *buf, ea_t source) const;
// TODO rewrite to the inline implementation which uses
// fixup_handler_t::size
int calc_size() const; ///< \ref calc_fixup_size()
uval_t get_value(ea_t ea) const; ///< \ref get_fixup_value()
bool patch_value(ea_t ea) const; ///< \ref patch_fixup_value()
};
/// Get fixup information
idaman bool ida_export get_fixup(fixup_data_t *fd, ea_t source);
/// Check that a fixup exists at the given address
inline bool exists_fixup(ea_t source)
{
return get_fixup(NULL, source);
}
/// Set fixup information. You should fill ::fixup_data_t and call this
/// function and the kernel will remember information in the database.
/// \param source the fixup source address, i.e. the address modified by
/// the fixup
/// \param fd fixup data
idaman void ida_export set_fixup(ea_t source, const fixup_data_t &fd);
/// Delete fixup information
idaman void ida_export del_fixup(ea_t source);
/// \name Enumerate addresses with fixup information:
//@{
/// Get the first address with fixup information
///
/// \return the first address with fixup information, or BADADDR
idaman ea_t ida_export get_first_fixup_ea(void);
/// Find next address with fixup information
///
/// \param ea current address
/// \return the next address with fixup information, or BADADDR
idaman ea_t ida_export get_next_fixup_ea(ea_t ea);
/// Find previous address with fixup information
///
/// \param ea current address
/// \return the previous address with fixup information, or BADADDR
idaman ea_t ida_export get_prev_fixup_ea(ea_t ea);
//@}
/// Get handler of standard or custom fixup
idaman const fixup_handler_t * ida_export get_fixup_handler(fixup_type_t type);
/// Use fixup information for an address.
/// This function converts item_ea flags to offsets/segments.
/// For undefined bytes, you may set item_ea == fixup_ea. In this case this
/// function will create an item (byte, word, dword) there.
/// \param item_ea start address of item to modify
/// \param fixup_ea address of fixup record
/// \param n number of operand. may be 0, 1, 2, or OPND_ALL
/// \param is_macro is the instruction at 'item_ea' a macro?
/// if yes, then partial fixups (HIGH, LOW) won't be applied
/// \retval false no fixup at fixup_ea or it has #FIXUPF_UNUSED flag
/// \retval true ok, the fixup information was applied
idaman bool ida_export apply_fixup(ea_t item_ea, ea_t fixup_ea, int n, bool is_macro);
/// Get the operand value.
/// This function get fixup bytes from data or an instruction at `ea' and
/// convert them to the operand value (maybe partially).
/// It is opposite in meaning to the `patch_fixup_value()`.
/// For example, FIXUP_HI8 read a byte at `ea' and shifts it left by 8 bits,
/// or AArch64's custom fixup BRANCH26 get low 26 bits of the insn at `ea'
/// and shifts it left by 2 bits.
/// This function is mainly used to get a relocation addend.
/// \param ea address to get fixup bytes from, the size of the fixup
/// bytes depends on the fixup type.
/// \sa fixup_handler_t::size
/// \param type fixup type
/// \retval operand value
idaman uval_t ida_export get_fixup_value(ea_t ea, fixup_type_t type);
/// Patch the fixup bytes.
/// This function updates data or an instruction at `ea' to the fixup bytes.
/// For example, FIXUP_HI8 updates a byte at `ea' to the high byte of
/// `fd->off', or AArch64's custom fixup BRANCH26 updates low 26 bits of the
/// insn at `ea' to the value of `fd->off' shifted right by 2.
/// \param ea address where data are changed, the size of the changed data
/// depends on the fixup type.
/// \sa fixup_handler_t::size
/// \param fd fixup data
/// \retval false the fixup bytes do not fit (e.g. `fd->off' is greater
/// than 0xFFFFFFC for BRANCH26). The database is changed
/// even in this case.
idaman bool ida_export patch_fixup_value(ea_t ea, const fixup_data_t &fd);
/// Get FIXUP description comment.
idaman const char *ida_export get_fixup_desc(
qstring *buf,
ea_t source,
const fixup_data_t &fd);
/// Calculate size of fixup in bytes (the number of bytes the fixup patches)
/// \retval -1 means error
idaman int ida_export calc_fixup_size(fixup_type_t type);
//--------------------------------------------------------------------------
// inline implementation
inline bool fixup_data_t::is_custom(void) const
{
return is_fixup_custom(type);
}
inline void fixup_data_t::set(ea_t source) const
{
set_fixup(source, *this);
}
inline bool fixup_data_t::get(ea_t source)
{
return get_fixup(this, source);
}
inline const char *fixup_data_t::get_desc(qstring *buf, ea_t source) const
{
return get_fixup_desc(buf, source, *this);
}
inline int fixup_data_t::calc_size() const
{
return calc_fixup_size(type);
}
inline uval_t fixup_data_t::get_value(ea_t ea) const
{
return get_fixup_value(ea, type);
}
inline bool fixup_data_t::patch_value(ea_t ea) const
{
return patch_fixup_value(ea, *this);
}
inline const fixup_handler_t *fixup_data_t::get_handler() const
{
return get_fixup_handler(type);
}
/// \name Custom fixups
/// Processor modules and plugins may register custom fixup handlers. File
/// loaders should use find_custom_fixup() function to find the handler
/// created by the processor module. The custom fixup handlers will be
/// unregistered automatically before the database gets closed.
//@{
//--------------------------------------------------------------------------
/// Implements the core behavior of a custom fixup
struct fixup_handler_t
{
int32 cbsize; ///< size of this structure
const char *name; ///< Format name, must be unique
uint32 props; ///< \ref FHF_
/// \defgroup FHF_ Fixup handler properties
/// Used by fixup_handler_t::props
//@{
#define FHF_VERIFY 0x0001 ///< verify that the value fits into WIDTH
///< bits. If this property is not set we
///< just truncate the value.
#define FHF_CODE 0x0002 ///< verify that ITEM_EA in std_apply() points
///< to an instruction.
#define FHF_FORCE_CODE 0x0004 ///< if ITEM_EA in std_apply() points to an
///< unknown item, then convert it to code.
///< this property is valid only with FHF_CODE.
#define FHF_ABS_OPVAL 0x0008 ///< create absolute refinfo in std_apply()
///< because the operand also has the absolute
///< value (usually for o_near operands)
//@}
/// \defgroup fh_options Tuning options
//@{
uint8 size; ///< size in bytes
uint8 width; ///< number of significant bits before shifting
uint8 shift; ///< number of bits to shift right before patching.
///< The following should be true:
///< `width - shift <= size * 8'
uint8 rsrv4; // reserved
uint32 reftype; ///< reference info type and flags,
///< std_apply() produces an offset of this type
//@}
/// Apply a fixup: take it into account while analyzing the file.
/// Usually it consists of converting the operand into an offset expression.
/// \sa apply_fixup()
/// If this callback is not specified then std_apply() is used.
bool (idaapi *apply)(
const fixup_handler_t *fh,
ea_t item_ea,
ea_t fixup_ea,
int opnum,
bool is_macro,
const fixup_data_t &fd);
/// Get the operand value.
/// This callback is called from get_fixup_value().
/// \sa get_fixup_value()
/// If this callback is not specified then std_get_value() is used.
uval_t (idaapi *get_value)(const fixup_handler_t *fh, ea_t ea);
/// Patch the fixup bytes.
/// This callback is called from patch_fixup_value() or after changing the
/// fixup (e.g. after it was moved from one location to another).
/// If this callback is not specified then std_patch_value() is used.
/// \sa patch_fixup_value()
/// \retval false the fixup bytes do not fit. The database is changed
/// even in this case.
bool (idaapi *patch_value)(
const fixup_handler_t *fh,
ea_t ea,
const fixup_data_t &fd);
};
/// \name std_apply()
/// This internal function takes \ref fh_options and \ref FHF_ to convert
/// the fixup to an offset.
/// \name std_patch_value()
/// This internal function takes \ref fh_options and \ref FHF_ to determine
/// how to patch the bytes.
/// 1) it verifies that the fixup value fits to the fixup_handler_t::width
/// bits if the FHF_VERIFY property is specified,
/// 2) it discards bits that do not fit,
/// 3) it shifts the result right by fixup_handler_t::shift bits,
/// 4) it puts the result to the rightmost bits of fixup_handler_t::size
/// bytes at the given address.
/// For example, FIXUP_HI8 uses size = 1, and width = 16, and shift = 8, and
/// property FHF_VERIFY, or AArch64's custom fixup BRANCH26 uses size = 4,
/// and width = 28, and shift = 2, and property FHF_VERIFY.
/// \name std_get_value()
/// This internal function takes \ref fh_options to determine how to get the
/// operand value.
/// It is opposite in meaning to the `std_patch_value()`.
/// 1) it gets the fixup_handler_t::size bytes at the given address,
/// 2) it shifts the result left by fixup_handler_t::shift bits,
/// 3) it returns the rightmost fixup_handler_t::width bits as a signed
/// value.
/// Register a new custom fixup.
/// This function must be called by a processor module or plugin, but not
/// by a file loader. File loaders should use find_custom_fixup() function
/// to find the handler created by the processor module.
/// \return id of the new custom fixup handler with FIXUP_CUSTOM bit set or
/// 0 (e.g. when the custom fixup handler with the same name was
/// already registered).
idaman fixup_type_t ida_export register_custom_fixup(
const fixup_handler_t *cfh);
/// Unregister a new custom fixup format. Should be called by the processor
/// module before the database gets closed.
idaman bool ida_export unregister_custom_fixup(fixup_type_t type);
/// Get id of a custom fixup handler.
/// \param name name of the custom fixup handler
/// \return id with FIXUP_CUSTOM bit set or 0
idaman fixup_type_t ida_export find_custom_fixup(const char *name);
//@}
//--------------------------------------------------------------------------
/// Collect fixup records for the specified range.
/// Partially overlapping records will be reported too.
/// \return success (false means no fixup info have been found)
struct fixup_info_t
{
ea_t ea;
fixup_data_t fd;
};
DECLARE_TYPE_AS_MOVABLE(fixup_info_t);
typedef qvector<fixup_info_t> fixups_t;
idaman bool ida_export get_fixups(fixups_t *out, ea_t ea, asize_t size);
/// Does the specified address range contain any fixup information?
inline bool contains_fixups(ea_t ea, asize_t size)
{
return get_fixups(NULL, ea, size);
}
/// Relocate the bytes with fixup information once more (generic function).
/// This function may be called from loader_t::move_segm() if it suits the goal.
/// If loader_t::move_segm is not defined then this function will be called
/// automatically when moving segments or rebasing the entire program.
/// Special parameter values (from = BADADDR, size = 0, to = delta) are used
/// when the function is called from rebase_program(delta).
idaman void ida_export gen_fix_fixups(ea_t from, ea_t to, asize_t size);
#endif // FIXUP_HPP

View File

@@ -1,223 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __FPRO_H
#define __FPRO_H
#include <pro.h>
#include <stdio.h>
/*! \file fpro.h
\brief System independent counterparts of FILE* related functions from Clib
You should not use C standard I/O functions in your modules.
The reason: Each module compiled with Borland
(and statically linked to Borland's library) will host a copy of
the FILE * information.
So, if you open a file in the plugin and pass the handle to the
kernel, the kernel will not be able to use it.
If you really need to use the standard functions, define USE_STANDARD_FILE_FUNCTIONS.
In this case do not mix them with q... functions.
*/
#if !defined(USE_STANDARD_FILE_FUNCTIONS) && !defined(__CODE_CHECKER__)
#undef stdin
#undef stdout
#undef stderr
#undef fgetc
#undef fputc
#define stdin dont_use_stdin ///< use gets()
#define stdout dont_use_stdout ///< use qprintf()
#define stderr dont_use_stderr ///< use qeprintf()
#define fopen dont_use_fopen ///< use qfopen()
#define fread dont_use_fread ///< use qfread()
#define fwrite dont_use_fwrite ///< use qfwrite()
#define ftell dont_use_ftell ///< use qftell()
#define fseek dont_use_fseek ///< use qfseek()
#define fclose dont_use_fclose ///< use qfclose()
#define fflush dont_use_fflush ///< use qflush()
#define fputc dont_use_fputc ///< use qfputc()
#define fgetc dont_use_fgetc ///< use qfgetc()
#define fgets dont_use_fgets ///< use qfgets()
#define fputs dont_use_fputs ///< use qfputs()
#define vfprintf dont_use_vfprintf ///< use qvfprintf()
#define vfscanf dont_use_vfscanf ///< use qvfscanf()
#define fprintf dont_use_fprintf ///< use qfprintf()
#define fscanf dont_use_fscanf ///< use qfscanf()
#endif
/// \name File I/O
/// The following functions work just like their counterparts from Clib,
/// only they are safer, system independent, and they set qerrno (see get_qerrno()).
//@{
idaman THREAD_SAFE FILE *ida_export qfopen(const char *file, const char *mode);
idaman THREAD_SAFE ssize_t ida_export qfread(FILE *fp, void *buf, size_t n);
idaman THREAD_SAFE ssize_t ida_export qfwrite(FILE *fp, const void *buf, size_t n);
idaman THREAD_SAFE qoff64_t ida_export qftell(FILE *fp);
idaman THREAD_SAFE int ida_export qfseek(FILE *fp, qoff64_t offset, int whence);
idaman THREAD_SAFE int ida_export qfclose(FILE *fp);
idaman THREAD_SAFE int ida_export qflush(FILE *fp);
idaman THREAD_SAFE int ida_export qfputc(int chr, FILE *fp);
idaman THREAD_SAFE int ida_export qfgetc(FILE *fp);
idaman THREAD_SAFE char *ida_export qfgets(char *s, size_t len, FILE *fp);
idaman THREAD_SAFE int ida_export qfputs(const char *s, FILE *fp);
idaman FILE *ida_export qtmpfile(void);
idaman THREAD_SAFE int ida_export qunlink(const char *fname);
idaman THREAD_SAFE int ida_export qaccess(const char *fname, int mode);
idaman THREAD_SAFE char *ida_export qgets(char *line, size_t linesize);
idaman THREAD_SAFE AS_PRINTF(2, 0) int ida_export qvfprintf(FILE *fp, const char *format, va_list va);
idaman THREAD_SAFE AS_PRINTF(1, 0) int ida_export qvprintf(const char *format, va_list va);
idaman THREAD_SAFE AS_PRINTF(1, 0) int ida_export qveprintf(const char *format, va_list va);
idaman THREAD_SAFE AS_SCANF(2, 0) int ida_export qvfscanf(FILE *fp, const char *format, va_list va);
#ifdef __cplusplus
THREAD_SAFE AS_PRINTF(2, 3) inline int qfprintf(FILE *fp, const char *format, ...)
{
va_list va;
va_start(va, format);
int code = qvfprintf(fp, format, va);
va_end(va);
return code;
}
THREAD_SAFE AS_PRINTF(1, 2) inline int qprintf(const char *format, ...)
{
va_list va;
va_start(va, format);
int code = qvprintf(format, va);
va_end(va);
return code;
}
THREAD_SAFE AS_PRINTF(1, 2) inline int qeprintf(const char *format, ...)
{
va_list va;
va_start(va, format);
int code = qveprintf(format, va);
va_end(va);
return code;
}
THREAD_SAFE AS_SCANF(2, 3) inline int qfscanf(FILE *fp, const char *format, ...)
{
va_list va;
va_start(va, format);
int code = qvfscanf(fp, format, va);
va_end(va);
return code;
}
#endif
//@}
/// Read line from file (the newline is removed from the output buffer)
/// \param buf output buffer
/// \param fp pointer to file
/// \return -1 or length of line
idaman THREAD_SAFE ssize_t ida_export qgetline(qstring *buf, FILE *fp);
/// Rename a file: 'newname' may exist, and will be deleted
idaman THREAD_SAFE int ida_export qrename(const char *oldfname, const char *newfname);
/// Move a file - more powerful version of qrename
/// \retval 0 success
/// \retval -1 system error
/// \retval else a combination of flags to be given for successful move
idaman THREAD_SAFE int ida_export qmove(const char *oldfname, const char *newfname, uint32 flags);
enum
{
QMOVE_CROSS_FS = 0x01, // UNIX: allow moving between different filesystem
QMOVE_OVERWRITE = 0x02, // Overwrite existing file
QMOVE_OVR_RO = 0x04, // Overwrite file even if it is write-protected
};
/// Copy a file.
/// \param from source file name
/// \param to destination file name
/// \param overwrite overwrite output if it exists?
/// \param cb user callback. return false to abort the copy loop
/// \param ud user data passed back to cb
/// \param flags reserved (should be zero)
/// \retval -1 input file not found
/// \retval -2 output file not writable
/// \retval -3 output file already exists while overwrite is false
/// \retval -4 write failure
/// \retval -5 interrupted from the callback
idaman THREAD_SAFE int ida_export qcopyfile(
const char *from,
const char *to,
bool overwrite = true,
bool (idaapi *cb)(uint64 pos, uint64 total, void *ud)=NULL,
void *ud = NULL,
int flags = 0);
/// Get temporary file name.
/// Returns absolute path, includes directory, and uses TEMP/TMP vars.
idaman char *ida_export qtmpnam(char *buf, size_t bufsize);
/// File janitor: will close a file at destruction-time
typedef janitor_t<FILE*> file_janitor_t;
template <> inline file_janitor_t::~janitor_t()
{
qfclose(resource);
}
/// \name readbytes/writebytes
/// Add-ins for 2..32 byte read/writes.
/// \param fp pointer to file
/// \param res value read from file
/// \param size size of value in bytes (1..32)
/// \param mostfirst is MSB first? (0/1)
/// \retval 0 All these functions return 0 on success
//@{
idaman THREAD_SAFE int ida_export freadbytes(FILE *fp,void *res,int size,int mostfirst);
idaman THREAD_SAFE int ida_export fwritebytes(FILE *fp,const void *l,int size,int mostfirst);
#ifdef __cplusplus
#define DEF_FREADBYTES(read, write, type, size) \
inline THREAD_SAFE int read(FILE *fp, type *res, bool mostfirst) \
{ return freadbytes(fp, res, size, mostfirst); } \
inline THREAD_SAFE int write(FILE *fp, const type *res, bool mostfirst) \
{ return fwritebytes(fp, res, size, mostfirst); }
DEF_FREADBYTES(fread2bytes, fwrite2bytes, int16, 2)
DEF_FREADBYTES(fread2bytes, fwrite2bytes, uint16, 2)
DEF_FREADBYTES(fread4bytes, fwrite4bytes, int32, 4)
DEF_FREADBYTES(fread4bytes, fwrite4bytes, uint32, 4)
DEF_FREADBYTES(fread8bytes, fwrite8bytes, longlong, 8)
DEF_FREADBYTES(fread8bytes, fwrite8bytes, ulonglong, 8)
#else
#define fread2bytes(fp,v,mf) freadbytes(fp,v,2,mf)
#define fwrite2bytes(fp,v,mf) fwritebytes(fp,v,2,mf)
#define fread4bytes(fp,v,mf) freadbytes(fp,v,4,mf)
#define fwrite4bytes(fp,v,mf) fwritebytes(fp,v,4,mf)
#define fread8bytes(fp,v,mf) freadbytes(fp,v,8,mf)
#define fwrite8bytes(fp,v,mf) fwritebytes(fp,v,8,mf)
#endif
//@}
#if !defined(feof) || !defined(ferror)
// If feof() and ferror() are not macros, we cannot use them
// Fortunately, for borland and vc they are macros, so there is no problem
// GCC defines them as functions: I have no idea whether they will work or not
// Anyway we remove the error directive from this file
// so the plugins can be compiled with gcc
//#error feof or ferror are not macros!
#endif
#endif

View File

@@ -1,577 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _FRAME_HPP
#define _FRAME_HPP
#include <idp.hpp>
/*! \file frame.hpp
\brief Routines to manipulate function stack frames, stack
variables, register variables and local labels.
The frame is represented as a structure:
<pre>
+------------------------------------------------+
| function arguments |
+------------------------------------------------+
| return address (isn't stored in func_t) |
+------------------------------------------------+
| saved registers (SI, DI, etc - func_t::frregs) |
+------------------------------------------------+ <- typical BP
| | |
| | | func_t::fpd
| | |
| | <- real BP
| local variables (func_t::frsize) |
| |
| |
+------------------------------------------------+ <- SP
</pre>
To access the structure of a function frame, use:
- get_struc() (use func_t::frame as structure ID)
- get_frame(const func_t *pfn)
- get_frame(ea_t ea)
*/
class struc_t;
class member_t;
class op_t;
// We need to trace value of SP register. For this we introduce
// an array of SP register change points.
// SP register change point
//
// NOTE: To manipulate/modify stack points, please use the specialized
// functions provided below in this file (stack pointer change points)
struct stkpnt_t
{
ea_t ea; // linear address
sval_t spd; // here we keep a cumulative difference from [BP-frsize]
DECLARE_COMPARISONS(stkpnt_t)
{
if ( ea < r.ea )
return -1;
if ( ea > r.ea )
return 1;
return 0;
}
};
DECLARE_TYPE_AS_MOVABLE(stkpnt_t);
// we declare a struct to be able to forward declare it in other files
struct stkpnts_t : public qvector<stkpnt_t>
{
DECLARE_COMPARISONS(stkpnts_t) { return compare_containers(*this, r); }
};
//--------------------------------------------------------------------------
// F R A M E M A N I P U L A T I O N
//--------------------------------------------------------------------------
/// Add function frame.
/// \param pfn pointer to function structure
/// \param frsize size of function local variables
/// \param frregs size of saved registers
/// \param argsize size of function arguments range which will be purged upon return.
/// this parameter is used for __stdcall and __pascal calling conventions.
/// for other calling conventions please pass 0.
/// \retval 1 ok
/// \retval 0 failed (no function, frame already exists)
idaman bool ida_export add_frame(
func_t *pfn,
sval_t frsize,
ushort frregs,
asize_t argsize);
/// Delete a function frame.
/// \param pfn pointer to function structure
/// \return success
idaman bool ida_export del_frame(func_t *pfn);
/// Set size of function frame.
/// Note: The returned size may not include all stack arguments. It does so
/// only for __stdcall and __fastcall calling conventions. To get the entire
/// frame size for all cases use get_struc_size(get_frame(pfn)).
/// \param pfn pointer to function structure
/// \param frsize size of function local variables
/// \param frregs size of saved registers
/// \param argsize size of function arguments that will be purged
/// from the stack upon return
/// \return success
idaman bool ida_export set_frame_size(
func_t *pfn,
asize_t frsize,
ushort frregs,
asize_t argsize);
/// Get full size of a function frame.
/// This function takes into account size of local variables + size of
/// saved registers + size of return address + number of purged bytes.
/// The purged bytes correspond to the arguments of the functions with
/// __stdcall and __fastcall calling conventions.
/// \param pfn pointer to function structure, may be NULL
/// \return size of frame in bytes or zero
idaman asize_t ida_export get_frame_size(const func_t *pfn);
/// Get size of function return address.
/// \param pfn pointer to function structure, can't be NULL
idaman int ida_export get_frame_retsize(const func_t *pfn);
/// Parts of a frame
enum frame_part_t
{
FPC_ARGS,
FPC_RETADDR,
FPC_SAVREGS,
FPC_LVARS,
};
/// Get offsets of the frame part in the frame.
/// \param range pointer to the output buffer with the frame part
/// start/end(exclusive) offsets, can't be NULL
/// \param pfn pointer to function structure, can't be NULL
/// \param part frame part
idaman void ida_export get_frame_part(range_t *range, const func_t *pfn, frame_part_t part);
/// Get starting address of arguments section
inline ea_t frame_off_args(const func_t *pfn)
{
range_t range;
get_frame_part(&range, pfn, FPC_ARGS);
return range.start_ea;
}
/// Get starting address of return address section
inline ea_t frame_off_retaddr(const func_t *pfn)
{
range_t range;
get_frame_part(&range, pfn, FPC_RETADDR);
return range.start_ea;
}
/// Get starting address of saved registers section
inline ea_t frame_off_savregs(const func_t *pfn)
{
range_t range;
get_frame_part(&range, pfn, FPC_SAVREGS);
return range.start_ea;
}
/// Get start address of local variables section
inline ea_t frame_off_lvars(const func_t *pfn)
{
range_t range;
get_frame_part(&range, pfn, FPC_LVARS);
return range.start_ea;
}
/// Does the given offset lie within the arguments section?
inline bool processor_t::is_funcarg_off(const func_t *pfn, uval_t frameoff) const
{
range_t args;
get_frame_part(&args, pfn, FPC_ARGS);
return stkup()
? frameoff < args.end_ea
: frameoff >= args.start_ea;
}
/// Does the given offset lie within the local variables section?
inline sval_t processor_t::lvar_off(const func_t *pfn, uval_t frameoff) const
{
range_t lvars;
get_frame_part(&lvars, pfn, FPC_LVARS);
return stkup()
? frameoff - lvars.start_ea
: lvars.end_ea - frameoff;
}
/// Get pointer to function frame.
/// \param pfn pointer to function structure
idaman struc_t *ida_export get_frame(const func_t *pfn);
/// Get pointer to function frame.
/// \param ea any address in the function
inline struc_t *get_frame(ea_t ea) { return get_frame(get_func(ea)); }
/// Convert struct offsets into fp-relative offsets.
/// This function converts the offsets inside the struc_t object
/// into the frame pointer offsets (for example, EBP-relative).
inline sval_t soff_to_fpoff(func_t *pfn, uval_t soff)
{
return soff - pfn->frsize + pfn->fpd;
}
/// Update frame pointer delta.
/// \param pfn pointer to function structure
/// \param fpd new fpd value.
/// cannot be bigger than the local variable range size.
/// \return success
idaman bool ida_export update_fpd(func_t *pfn, asize_t fpd);
/// Set the number of purged bytes for a function or data item (funcptr).
/// This function will update the database and plan to reanalyze items
/// referencing the specified address. It works only for processors
/// with #PR_PURGING bit in 16 and 32 bit modes.
/// \param ea address of the function of item
/// \param nbytes number of purged bytes
/// \param override_old_value may overwrite old information about purged bytes
/// \return success
idaman bool ida_export set_purged(ea_t ea, int nbytes, bool override_old_value);
/// Get function by its frame id.
/// \warning this function works only with databases created by IDA > 5.6
/// \param frame_id id of the function frame
/// \return start address of the function or #BADADDR
idaman ea_t ida_export get_func_by_frame(tid_t frame_id);
//--------------------------------------------------------------------------
// S T A C K V A R I A B L E S
//--------------------------------------------------------------------------
/// Get pointer to stack variable.
/// \param actval actual value used to fetch stack variable
/// this pointer may point to 'v'
/// \param insn the instruction
/// \param x reference to instruction operand
/// \param v immediate value in the operand (usually x.addr)
/// \return NULL or ptr to stack variable
idaman member_t *ida_export get_stkvar(
sval_t *actval,
const insn_t &insn,
const op_t &x,
sval_t v);
/// Automatically add stack variable if doesn't exist.
/// Processor modules should use insn_t::create_stkvar().
/// \param insn the instruction
/// \param x reference to instruction operand
/// \param v immediate value in the operand (usually x.addr)
/// \param flags \ref STKVAR_1
/// \return success
idaman bool ida_export add_stkvar(const insn_t &insn, const op_t &x, sval_t v, int flags);
/// \defgroup STKVAR_1 Add stkvar flags
/// Passed as 'flags' parameter to add_stkvar()
//@{
#define STKVAR_VALID_SIZE 0x0001 ///< x.dtyp contains correct variable type
///< (for insns like 'lea' this bit must be off)
///< in general, dr_O references do not allow
///< to determine the variable size
//@}
/// Define/redefine a stack variable.
/// \param pfn pointer to function
/// \param name variable name, NULL means autogenerate a name
/// \param off offset of the stack variable in the frame.
/// negative values denote local variables, positive - function arguments.
/// \param flags variable type flags (byte_flag() for a byte variable, for example)
/// \param ti additional type information (like offsets, structs, etc)
/// \param nbytes number of bytes occupied by the variable
/// \return success
idaman bool ida_export define_stkvar(
func_t *pfn,
const char *name,
sval_t off,
flags_t flags,
const opinfo_t *ti,
asize_t nbytes);
/// Build automatic stack variable name.
/// \param buf pointer to buffer
/// \param pfn pointer to function (can't be NULL!)
/// \param v value of variable offset
/// \return length of stack variable name or -1
idaman ssize_t ida_export build_stkvar_name(
qstring *buf,
const func_t *pfn,
sval_t v);
/// Calculate offset of stack variable in the frame structure.
/// \param pfn pointer to function (can't be NULL!)
/// \param insn the instruction
/// \param n number of operand: (0..#UA_MAXOP-1)
/// -1 if error, return #BADADDR
/// \return #BADADDR if some error (issue a warning if stack frame is bad)
idaman ea_t ida_export calc_stkvar_struc_offset(
func_t *pfn,
const insn_t &insn,
int n);
/// Find and delete wrong frame info.
/// Namely, we delete:
/// - unreferenced stack variable definitions
/// - references to dead stack variables (i.e. operands displayed in red)
/// these operands will be untyped and most likely displayed in hex.
/// We also plan to reanalyze instruction with the stack frame references
/// \param pfn pointer to the function
/// \param should_reanalyze callback to determine which instructions to reanalyze
/// \return number of deleted definitions
idaman int ida_export delete_wrong_frame_info(
func_t *pfn,
bool idaapi should_reanalyze(const insn_t &insn));
//--------------------------------------------------------------------------
// R E G I S T E R V A R I A B L E S
//--------------------------------------------------------------------------
/// \defgroup regvar Register variables
/// Definition of ::regvar_t and related functions
//@{
/// A register variable allows the user to rename a general processor register
/// to a meaningful name.
/// IDA doesn't check whether the target assembler supports the register renaming.
/// All register definitions will appear at the beginning of the function.
struct regvar_t : public range_t
{
char *canon; ///< canonical register name (case-insensitive)
char *user; ///< user-defined register name
char *cmt; ///< comment to appear near definition
};
DECLARE_TYPE_AS_MOVABLE(regvar_t);
/// Define a register variable.
/// \param pfn function in which the definition will be created
/// \param ea1,ea2 range of addresses within the function where the definition
/// will be used
/// \param canon name of a general register
/// \param user user-defined name for the register
/// \param cmt comment for the definition
/// \return \ref REGVAR_ERROR_
idaman int ida_export add_regvar(
func_t *pfn,
ea_t ea1,
ea_t ea2,
const char *canon,
const char *user,
const char *cmt);
/// \defgroup REGVAR_ERROR_ Register variable error codes
/// Return values for functions in described in \ref regvar
//@{
#define REGVAR_ERROR_OK 0 ///< all ok
#define REGVAR_ERROR_ARG (-1) ///< function arguments are bad
#define REGVAR_ERROR_RANGE (-2) ///< the definition range is bad
#define REGVAR_ERROR_NAME (-3) ///< the provided name(s) can't be accepted
//@}
/// Find a register variable definition (powerful version).
/// One of 'canon' and 'user' should be NULL.
/// If both 'canon' and 'user' are NULL it returns the first regvar
/// definition in the range.
/// \param pfn function in question
/// \param ea1,ea2 range of addresses to search.
/// ea1==BADADDR means the entire function
/// \param canon name of a general register
/// \param user user-defined name for the register
/// \return NULL-not found, otherwise ptr to regvar_t
idaman regvar_t *ida_export find_regvar(func_t *pfn, ea_t ea1, ea_t ea2, const char *canon, const char *user);
/// Find a register variable definition.
/// \param pfn function in question
/// \param ea current address
/// \param canon name of a general register
/// \return NULL-not found, otherwise ptr to regvar_t
inline regvar_t *find_regvar(func_t *pfn, ea_t ea, const char *canon)
{
return find_regvar(pfn, ea, ea+1, canon, NULL);
}
/// Is there a register variable definition?
/// \param pfn function in question
/// \param ea current address
inline bool has_regvar(func_t *pfn, ea_t ea)
{
return find_regvar(pfn, ea, ea+1, NULL, NULL) != NULL;
}
/// Rename a register variable.
/// \param pfn function in question
/// \param v variable to rename
/// \param user new user-defined name for the register
/// \return \ref REGVAR_ERROR_
idaman int ida_export rename_regvar(func_t *pfn, regvar_t *v, const char *user);
/// Set comment for a register variable.
/// \param pfn function in question
/// \param v variable to rename
/// \param cmt new comment
/// \return \ref REGVAR_ERROR_
idaman int ida_export set_regvar_cmt(func_t *pfn, regvar_t *v, const char *cmt);
/// Delete a register variable definition.
/// \param pfn function in question
/// \param ea1,ea2 range of addresses within the function where the definition holds
/// \param canon name of a general register
/// \return \ref REGVAR_ERROR_
idaman int ida_export del_regvar(func_t *pfn, ea_t ea1, ea_t ea2, const char *canon);
//@} regvar
//--------------------------------------------------------------------------
// S P R E G I S T E R C H A N G E P O I N T S
//--------------------------------------------------------------------------
/// Add automatic SP register change point.
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address where SP changes.
/// usually this is the end of the instruction which
/// modifies the stack pointer (\cmd{ea}+\cmd{size})
/// \param delta difference between old and new values of SP
/// \return success
idaman bool ida_export add_auto_stkpnt(func_t *pfn, ea_t ea, sval_t delta);
/// Add user-defined SP register change point.
/// \param ea linear address where SP changes
/// \param delta difference between old and new values of SP
/// \return success
idaman bool ida_export add_user_stkpnt(ea_t ea, sval_t delta);
/// Delete SP register change point.
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address
/// \return success
idaman bool ida_export del_stkpnt(func_t *pfn, ea_t ea);
/// Get difference between the initial and current values of ESP.
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address of an instruction
/// \return 0 or the difference, usually a negative number.
/// returns the sp-diff before executing the instruction.
idaman sval_t ida_export get_spd(func_t *pfn, ea_t ea);
/// Get effective difference between the initial and current values of ESP.
/// This function returns the sp-diff used by the instruction.
/// The difference between get_spd() and get_effective_spd() is present only
/// for instructions like "pop [esp+N]": they modify sp and use the modified value.
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address
/// \return 0 or the difference, usually a negative number
idaman sval_t ida_export get_effective_spd(func_t *pfn, ea_t ea);
/// Get modification of SP made at the specified location
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address
/// \return 0 if the specified location doesn't contain a SP change point.
/// otherwise return delta of SP modification.
idaman sval_t ida_export get_sp_delta(func_t *pfn, ea_t ea);
/// Recalculate SP delta for an instruction that stops execution.
/// The next instruction is not reached from the current instruction.
/// We need to recalculate SP for the next instruction.
///
/// This function will create a new automatic SP register change
/// point if necessary. It should be called from the emulator (emu.cpp)
/// when auto_state == ::AU_USED if the current instruction doesn't pass
/// the execution flow to the next instruction.
/// \param cur_ea linear address of the current instruction
/// \retval 1 new stkpnt is added
/// \retval 0 nothing is changed
idaman bool ida_export recalc_spd(ea_t cur_ea);
/// An xref to an argument or variable located in a function's stack frame
struct xreflist_entry_t
{
ea_t ea; ///< Location of the insn referencing the stack frame member
uchar opnum; ///< Number of the operand of that instruction
uchar type; ///< The type of xref (::cref_t & ::dref_t)
DECLARE_COMPARISONS(xreflist_entry_t)
{
int code = ::compare(ea, r.ea);
if ( code == 0 )
{
code = ::compare(type, r.type);
if ( code == 0 )
code = ::compare(opnum, r.opnum);
}
return code;
}
};
DECLARE_TYPE_AS_MOVABLE(xreflist_entry_t);
typedef qvector<xreflist_entry_t> xreflist_t; ///< vector of xrefs to variables in a function's stack frame
/// Fill 'out' with a list of all the xrefs made from function 'pfn', to
/// the argument or variable 'mptr' in 'pfn's stack frame.
/// \param out the list of xrefs to fill.
/// \param pfn the function to scan.
/// \param mptr the argument/variable in pfn's stack frame.
idaman void ida_export build_stkvar_xrefs(xreflist_t *out, func_t *pfn, const member_t *mptr);
#ifndef NO_OBSOLETE_FUNCS
idaman DEPRECATED ea_t ida_export get_min_spd_ea(func_t *pfn);
idaman DEPRECATED int ida_export delete_unreferenced_stkvars(func_t *pfn);
idaman DEPRECATED int ida_export delete_wrong_stkvar_ops(func_t *pfn);
#endif
#endif // _FRAME_HPP

View File

@@ -1,950 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef FUNCS_HPP
#define FUNCS_HPP
#include <range.hpp>
#include <bytes.hpp>
/*! \file funcs.hpp
\brief Routines for working with functions within the disassembled program.
This file also contains routines for working with library signatures
(e.g. FLIRT).
Each function consists of function chunks. At least one function chunk
must be present in the function definition - the function entry chunk.
Other chunks are called function tails. There may be several of them
for a function.
A function tail is a continuous range of addresses.
It can be used in the definition of one or more functions.
One function using the tail is singled out and called the tail owner.
This function is considered as 'possessing' the tail.
get_func() on a tail address will return the function possessing the tail.
You can enumerate the functions using the tail by using ::func_parent_iterator_t.
Each function chunk in the disassembly is represented as an "range" (a range
of addresses, see range.hpp for details) with characteristics.
A function entry must start with an instruction (code) byte.
*/
struct stkpnt_t; // #include <frame.hpp>
struct regvar_t; // #include <frame.hpp>
struct llabel_t; // #include <frame.hpp>
class insn_t; // #include <ua.hpp>
/// Register argument description.
/// regargs are destroyed when the full function type is determined.
struct regarg_t
{
int reg;
type_t *type;
char *name;
};
//------------------------------------------------------------------------
/// A function is a set of continuous ranges of addresses with characteristics
class func_t : public range_t
{
public:
uint64 flags; ///< \ref FUNC_
/// \defgroup FUNC_ Function flags
/// Used by func_t::flags
//@{
#define FUNC_NORET 0x00000001 ///< Function doesn't return
#define FUNC_FAR 0x00000002 ///< Far function
#define FUNC_LIB 0x00000004 ///< Library function
#define FUNC_STATICDEF 0x00000008 ///< Static function
#define FUNC_FRAME 0x00000010 ///< Function uses frame pointer (BP)
#define FUNC_USERFAR 0x00000020 ///< User has specified far-ness
///< of the function
#define FUNC_HIDDEN 0x00000040 ///< A hidden function chunk
#define FUNC_THUNK 0x00000080 ///< Thunk (jump) function
#define FUNC_BOTTOMBP 0x00000100 ///< BP points to the bottom of the stack frame
#define FUNC_NORET_PENDING 0x00200 ///< Function 'non-return' analysis must be performed.
///< This flag is verified upon func_does_return()
#define FUNC_SP_READY 0x00000400 ///< SP-analysis has been performed.
///< If this flag is on, the stack
///< change points should not be not
///< modified anymore. Currently this
///< analysis is performed only for PC
#define FUNC_FUZZY_SP 0x00000800 ///< Function changes SP in untraceable way,
///< for example: and esp, 0FFFFFFF0h
#define FUNC_PROLOG_OK 0x00001000 ///< Prolog analysis has be performed
///< by last SP-analysis
#define FUNC_PURGED_OK 0x00004000 ///< 'argsize' field has been validated.
///< If this bit is clear and 'argsize'
///< is 0, then we do not known the real
///< number of bytes removed from
///< the stack. This bit is handled
///< by the processor module.
#define FUNC_TAIL 0x00008000 ///< This is a function tail.
///< Other bits must be clear
///< (except #FUNC_HIDDEN).
#define FUNC_LUMINA 0x00010000 ///< Function info is provided by Lumina.
//@}
/// Is a far function?
bool is_far(void) const { return (flags & FUNC_FAR) != 0; }
/// Does function return?
bool does_return(void) const { return (flags & FUNC_NORET) == 0; }
/// Has SP-analysis been performed?
bool analyzed_sp(void) const { return (flags & FUNC_SP_READY) != 0; }
/// Needs prolog analysis?
bool need_prolog_analysis(void) const { return (flags & FUNC_PROLOG_OK) == 0; }
#ifndef SWIG
union
{
/// attributes of a function entry chunk
struct
{
#endif // SWIG
//
// Stack frame of the function. It is represented as a structure:
//
// +------------------------------------------------+
// | function arguments |
// +------------------------------------------------+
// | return address (isn't stored in func_t) |
// +------------------------------------------------+
// | saved registers (SI, DI, etc - func_t::frregs) |
// +------------------------------------------------+ <- typical BP
// | | |
// | | | func_t::fpd
// | | |
// | | <- real BP
// | local variables (func_t::frsize) |
// | |
// | |
// +------------------------------------------------+ <- SP
//
uval_t frame; ///< netnode id of frame structure - see frame.hpp
asize_t frsize; ///< size of local variables part of frame in bytes.
///< If #FUNC_FRAME is set and #fpd==0, the frame pointer
///< (EBP) is assumed to point to the top of the local
///< variables range.
ushort frregs; ///< size of saved registers in frame. This range is
///< immediately above the local variables range.
asize_t argsize; ///< number of bytes purged from the stack
///< upon returning
asize_t fpd; ///< frame pointer delta. (usually 0, i.e. realBP==typicalBP)
///< use update_fpd() to modify it.
bgcolor_t color; ///< user defined function color
// the following fields should not be accessed directly:
uint32 pntqty; ///< number of SP change points
stkpnt_t *points; ///< array of SP change points.
///< use ...stkpnt...() functions to access this array.
int regvarqty; ///< number of register variables (-1-not read in yet)
///< use find_regvar() to read register variables
regvar_t *regvars; ///< array of register variables.
///< this array is sorted by: start_ea.
///< use ...regvar...() functions to access this array.
int llabelqty; ///< number of local labels
llabel_t *llabels; ///< local labels.
///< this array shouldn't be accessed directly; name.hpp
///< functions should be used instead.
int regargqty; ///< number of register arguments.
///< During analysis IDA tries to guess the register
///< arguments. It stores store the guessing outcome
///< in this field. As soon as it determines the final
///< function prototype, regargqty is set to zero.
regarg_t *regargs; ///< unsorted array of register arguments.
///< use ...regarg...() functions to access this array.
///< regargs are destroyed when the full function
///< type is determined.
int tailqty; ///< number of function tails
range_t *tails; ///< array of tails, sorted by ea.
///< use func_tail_iterator_t to access function tails.
#ifndef SWIG
};
/// attributes of a function tail chunk
struct
{
#endif // SWIG
ea_t owner; ///< the address of the main function possessing this tail
int refqty; ///< number of referers
ea_t *referers; ///< array of referers (function start addresses).
///< use func_parent_iterator_t to access the referers.
#ifndef SWIG
};
};
#endif // SWIG
func_t(ea_t start=0, ea_t end=0, flags_t f=0)
: range_t(start, end), flags(f|FUNC_NORET_PENDING), frame(BADNODE),
frsize(0), frregs(0), argsize(0), fpd(0), color(DEFCOLOR),
pntqty(0), points(nullptr),
regvarqty(0), regvars(nullptr),
llabelqty(0), llabels(nullptr),
regargqty(0), regargs(nullptr),
tailqty(0), tails(nullptr)
{
}
};
DECLARE_TYPE_AS_MOVABLE(func_t);
/// Does function describe a function entry chunk?
inline bool is_func_entry(const func_t *pfn) { return pfn != nullptr && (pfn->flags & FUNC_TAIL) == 0; }
/// Does function describe a function tail chunk?
inline bool is_func_tail(const func_t *pfn) { return pfn != nullptr && (pfn->flags & FUNC_TAIL) != 0; }
/// Lock function pointer
/// Locked pointers are guaranteed to remain valid until they are unlocked.
/// Ranges with locked pointers cannot be deleted or moved.
idaman void ida_export lock_func_range(const func_t *pfn, bool lock);
/// Helper class to lock a function pointer so it stays valid
class lock_func
{
const func_t *pfn;
public:
lock_func(const func_t *_pfn) : pfn(_pfn)
{
lock_func_range(pfn, true);
}
~lock_func(void)
{
lock_func_range(pfn, false);
}
};
/// Is the function pointer locked?
idaman bool ida_export is_func_locked(const func_t *pfn);
//--------------------------------------------------------------------
// F U N C T I O N S
//--------------------------------------------------------------------
/// Get pointer to function structure by address.
/// \param ea any address in a function
/// \return ptr to a function or nullptr.
/// This function returns a function entry chunk.
idaman func_t *ida_export get_func(ea_t ea);
/// Get the containing tail chunk of 'ea'.
/// \retval -1 means 'does not contain ea'
/// \retval 0 means the 'pfn' itself contains ea
/// \retval >0 the number of the containing function tail chunk
idaman int ida_export get_func_chunknum(func_t *pfn, ea_t ea);
/// Does the given function contain the given address?
inline bool func_contains(func_t *pfn, ea_t ea)
{
return get_func_chunknum(pfn, ea) >= 0;
}
/// Do two addresses belong to the same function?
inline bool is_same_func(ea_t ea1, ea_t ea2)
{
func_t *pfn = get_func(ea1);
return pfn != nullptr && func_contains(pfn, ea2);
}
/// Get pointer to function structure by number.
/// \param n number of function, is in range 0..get_func_qty()-1
/// \return ptr to a function or nullptr.
/// This function returns a function entry chunk.
idaman func_t *ida_export getn_func(size_t n);
/// Get total number of functions in the program
idaman size_t ida_export get_func_qty(void);
/// Get ordinal number of a function.
/// \param ea any address in the function
/// \return number of function (0..get_func_qty()-1).
/// -1 means 'no function at the specified address'.
idaman int ida_export get_func_num(ea_t ea);
/// Get pointer to the previous function.
/// \param ea any address in the program
/// \return ptr to function or nullptr if previous function doesn't exist
idaman func_t *ida_export get_prev_func(ea_t ea);
/// Get pointer to the next function.
/// \param ea any address in the program
/// \return ptr to function or nullptr if next function doesn't exist
idaman func_t *ida_export get_next_func(ea_t ea);
/// Get function ranges.
/// \param ranges buffer to receive the range info
/// \param pfn ptr to function structure
/// \return end address of the last function range (BADADDR-error)
idaman ea_t ida_export get_func_ranges(rangeset_t *ranges, func_t *pfn);
/// Get function comment.
/// \param buf buffer for the comment
/// \param pfn ptr to function structure
/// \param repeatable get repeatable comment?
/// \return size of comment or -1
/// In fact this function works with function chunks too.
idaman ssize_t ida_export get_func_cmt(qstring *buf, const func_t *pfn, bool repeatable);
/// Set function comment.
/// This function works with function chunks too.
/// \param pfn ptr to function structure
/// \param cmt comment string, may be multiline (with '\n').
/// Use empty str ("") to delete comment
/// \param repeatable set repeatable comment?
idaman bool ida_export set_func_cmt(const func_t *pfn, const char *cmt, bool repeatable);
/// Update information about a function in the database (::func_t).
/// You must not change the function start and end addresses using this function.
/// Use set_func_start() and set_func_end() for it.
/// \param pfn ptr to function structure
/// \return success
idaman bool ida_export update_func(func_t *pfn);
/// Add a new function.
/// If the fn->end_ea is #BADADDR, then IDA will try to determine the
/// function bounds by calling find_func_bounds(..., #FIND_FUNC_DEFINE).
/// \param pfn ptr to filled function structure
/// \return success
idaman bool ida_export add_func_ex(func_t *pfn);
/// Add a new function.
/// If the function end address is #BADADDR, then IDA will try to determine
/// the function bounds by calling find_func_bounds(..., #FIND_FUNC_DEFINE).
/// \param ea1 start address
/// \param ea2 end address
/// \return success
inline bool add_func(ea_t ea1, ea_t ea2=BADADDR)
{
func_t fn(ea1, ea2);
return add_func_ex(&fn);
}
/// Delete a function.
/// \param ea any address in the function entry chunk
/// \return success
idaman bool ida_export del_func(ea_t ea);
/// Move function chunk start address.
/// \param ea any address in the function
/// \param newstart new end address of the function
/// \return \ref MOVE_FUNC_
idaman int ida_export set_func_start(ea_t ea, ea_t newstart);
/// \defgroup MOVE_FUNC_ Function move result codes
/// Return values for set_func_start()
//@{
#define MOVE_FUNC_OK 0 ///< ok
#define MOVE_FUNC_NOCODE 1 ///< no instruction at 'newstart'
#define MOVE_FUNC_BADSTART 2 ///< bad new start address
#define MOVE_FUNC_NOFUNC 3 ///< no function at 'ea'
#define MOVE_FUNC_REFUSED 4 ///< a plugin refused the action
//@}
/// Move function chunk end address.
/// \param ea any address in the function
/// \param newend new end address of the function
/// \return success
idaman bool ida_export set_func_end(ea_t ea, ea_t newend);
/// Reanalyze a function.
/// This function plans to analyzes all chunks of the given function.
/// Optional parameters (ea1, ea2) may be used to narrow the analyzed range.
/// \param pfn pointer to a function
/// \param ea1 start of the range to analyze
/// \param ea2 end of range to analyze
/// \param analyze_parents meaningful only if pfn points to a function tail.
/// if true, all tail parents will be reanalyzed.
/// if false, only the given tail will be reanalyzed.
idaman void ida_export reanalyze_function(
func_t *pfn,
ea_t ea1=0,
ea_t ea2=BADADDR,
bool analyze_parents=false);
/// Determine the boundaries of a new function.
/// This function tries to find the start and end addresses of a new function.
/// It calls the module with \ph{func_bounds} in order to fine tune
/// the function boundaries.
/// \param nfn structure to fill with information
/// \ nfn->start_ea points to the start address of the new function.
/// \param flags \ref FIND_FUNC_F
/// \return \ref FIND_FUNC_R
idaman int ida_export find_func_bounds(func_t *nfn, int flags);
/// \defgroup FIND_FUNC_F Find function bounds flags
/// Passed as 'flags' parameter to find_func_bounds()
//@{
#define FIND_FUNC_NORMAL 0x0000 ///< stop processing if undefined byte is encountered
#define FIND_FUNC_DEFINE 0x0001 ///< create instruction if undefined byte is encountered
#define FIND_FUNC_IGNOREFN 0x0002 ///< ignore existing function boundaries.
///< by default the function returns function boundaries
///< if ea belongs to a function.
#define FIND_FUNC_KEEPBD 0x0004 ///< do not modify incoming function boundaries,
///< just create instructions inside the boundaries.
//@}
/// \defgroup FIND_FUNC_R Find function bounds result codes
/// Return values for find_func_bounds()
//@{
#define FIND_FUNC_UNDEF 0 ///< function has instructions that pass execution flow to unexplored bytes.
///< nfn->end_ea will have the address of the unexplored byte.
#define FIND_FUNC_OK 1 ///< ok, 'nfn' is ready for add_func()
#define FIND_FUNC_EXIST 2 ///< function exists already.
///< its bounds are returned in 'nfn'.
//@}
/// Get function name.
/// \param out buffer for the answer
/// \param ea any address in the function
/// \return length of the function name
idaman ssize_t ida_export get_func_name(qstring *out, ea_t ea);
/// Calculate function size.
/// This function takes into account all fragments of the function.
/// \param pfn ptr to function structure
idaman asize_t ida_export calc_func_size(func_t *pfn);
/// Get function bitness (which is equal to the function segment bitness).
/// pfn==nullptr => returns 0
/// \retval 0 16
/// \retval 1 32
/// \retval 2 64
idaman int ida_export get_func_bitness(const func_t *pfn);
/// Get number of bits in the function addressing
inline int idaapi get_func_bits(const func_t *pfn) { return 1 << (get_func_bitness(pfn)+4); }
/// Get number of bytes in the function addressing
inline int idaapi get_func_bytes(const func_t *pfn) { return get_func_bits(pfn)/8; }
/// Is the function visible (not hidden)?
inline bool is_visible_func(func_t *pfn) { return (pfn->flags & FUNC_HIDDEN) == 0; }
/// Is the function visible (event after considering #SCF_SHHID_FUNC)?
inline bool is_finally_visible_func(func_t *pfn)
{
return (inf_get_cmtflg() & SCF_SHHID_FUNC) != 0 || is_visible_func(pfn);
}
/// Set visibility of function
idaman void ida_export set_visible_func(func_t *pfn, bool visible);
/// Give a meaningful name to function if it consists of only 'jump' instruction.
/// \param pfn pointer to function (may be nullptr)
/// \param oldname old name of function.
/// if old name was in "j_..." form, then we may discard it
/// and set a new name.
/// if oldname is not known, you may pass nullptr.
/// \return success
idaman int ida_export set_func_name_if_jumpfunc(func_t *pfn, const char *oldname);
/// Calculate target of a thunk function.
/// \param pfn pointer to function (may not be nullptr)
/// \param fptr out: will hold address of a function pointer (if indirect jump)
/// \return the target function or #BADADDR
idaman ea_t ida_export calc_thunk_func_target(func_t *pfn, ea_t *fptr);
/// Does the function return?.
/// To calculate the answer, #FUNC_NORET flag and is_noret() are consulted
/// The latter is required for imported functions in the .idata section.
/// Since in .idata we have only function pointers but not functions, we have
/// to introduce a special flag for them.
idaman bool ida_export func_does_return(ea_t callee);
/// Plan to reanalyze noret flag.
/// This function does not remove FUNC_NORET if it is already present.
/// It just plans to reanalysis.
idaman bool ida_export reanalyze_noret_flag(ea_t ea);
/// Signal a non-returning instruction.
/// This function can be used by the processor module to tell the kernel
/// about non-returning instructions (like call exit). The kernel will
/// perform the global function analysis and find out if the function
/// returns at all. This analysis will be done at the first call to func_does_return()
/// \return true if the instruction 'noret' flag has been changed
idaman bool ida_export set_noret_insn(ea_t insn_ea, bool noret);
//--------------------------------------------------------------------
// F U N C T I O N C H U N K S
//--------------------------------------------------------------------
/// Get pointer to function chunk structure by address.
/// \param ea any address in a function chunk
/// \return ptr to a function chunk or nullptr.
/// This function may return a function entry as well as a function tail.
idaman func_t *ida_export get_fchunk(ea_t ea);
/// Get pointer to function chunk structure by number.
/// \param n number of function chunk, is in range 0..get_fchunk_qty()-1
/// \return ptr to a function chunk or nullptr.
/// This function may return a function entry as well as a function tail.
idaman func_t *ida_export getn_fchunk(int n);
/// Get total number of function chunks in the program
idaman size_t ida_export get_fchunk_qty(void);
/// Get ordinal number of a function chunk in the global list of function chunks.
/// \param ea any address in the function chunk
/// \return number of function chunk (0..get_fchunk_qty()-1).
/// -1 means 'no function chunk at the specified address'.
idaman int ida_export get_fchunk_num(ea_t ea);
/// Get pointer to the previous function chunk in the global list.
/// \param ea any address in the program
/// \return ptr to function chunk or nullptr if previous function chunk doesn't exist
idaman func_t *ida_export get_prev_fchunk(ea_t ea);
/// Get pointer to the next function chunk in the global list.
/// \param ea any address in the program
/// \return ptr to function chunk or nullptr if next function chunk doesn't exist
idaman func_t *ida_export get_next_fchunk(ea_t ea);
//--------------------------------------------------------------------
// Functions to manipulate function chunks
/// Append a new tail chunk to the function definition.
/// If the tail already exists, then it will simply be added to the function tail list
/// Otherwise a new tail will be created and its owner will be set to be our function
/// If a new tail cannot be created, then this function will fail.
/// \param ea1 start of the tail. If a tail already exists at the specified address
/// it must start at 'ea1'
/// \param ea2 end of the tail. If a tail already exists at the specified address
/// it must end at 'ea2'. If specified as BADADDR, IDA will determine
/// the end address itself.
idaman bool ida_export append_func_tail(func_t *pfn, ea_t ea1, ea_t ea2);
/// Remove a function tail.
/// If the tail belongs only to one function, it will be completely removed.
/// Otherwise if the function was the tail owner, the first function using
/// this tail becomes the owner of the tail.
idaman bool ida_export remove_func_tail(func_t *pfn, ea_t tail_ea);
/// Set a function as the possessing function of a function tail.
/// The function should already refer to the tail (after append_func_tail).
idaman bool ida_export set_tail_owner(func_t *fnt, ea_t func_start);
// Auxiliary function(s) to be used in func_..._iterator_t
class func_parent_iterator_t;
class func_tail_iterator_t;
class func_item_iterator_t;
/// Declare helper functions for ::func_item_iterator_t
#define DECLARE_FUNC_ITERATORS(prefix) \
prefix bool ida_export func_tail_iterator_set(func_tail_iterator_t *fti, func_t *pfn, ea_t ea);\
prefix bool ida_export func_tail_iterator_set_ea(func_tail_iterator_t *fti, ea_t ea);\
prefix bool ida_export func_parent_iterator_set(func_parent_iterator_t *fpi, func_t *pfn);\
prefix bool ida_export func_item_iterator_next(func_item_iterator_t *fii, testf_t *testf, void *ud);\
prefix bool ida_export func_item_iterator_prev(func_item_iterator_t *fii, testf_t *testf, void *ud);\
prefix bool ida_export func_item_iterator_decode_prev_insn(func_item_iterator_t *fii, insn_t *out); \
prefix bool ida_export func_item_iterator_decode_preceding_insn(func_item_iterator_t *fii, eavec_t *visited, bool *p_farref, insn_t *out);
DECLARE_FUNC_ITERATORS(idaman)
/// Helper function to accept any address
inline THREAD_SAFE bool idaapi f_any(flags_t, void *) { return true; }
/// Class to enumerate all function tails sorted by addresses.
/// Enumeration is started with main(), first(), or last().
/// If first() is used, the function entry chunk will be excluded from the enumeration.
/// Otherwise it will be included in the enumeration (for main() and last()).
/// The loop may continue until the next() or prev() function returns false.
/// These functions return false when the enumeration is over.
/// The tail chunks are always sorted by their addresses.
///
/// Sample code:
/// \code
/// func_tail_iterator_t fti(pfn);
/// for ( bool ok=fti.first(); ok; ok=fti.next() )
/// const range_t &a = fti.chunk();
/// ....
/// \endcode
///
/// If the 'ea' parameter is used in the constructor, then the iterator is positioned
/// at the chunk containing the specified 'ea'. Otherwise it is positioned at the
/// function entry chunk.
/// If 'pfn' is specified as nullptr then the set() function will fail,
/// but it is still possible to use the class. In this case the iteration will be
/// limited by the segment boundaries.
/// The function main chunk is locked during the iteration.
/// It is also possible to enumerate one single arbitrary range using set_range()
/// This function is mainly designed to be used from ::func_item_iterator_t.
class func_tail_iterator_t
{
func_t *pfn;
int idx;
range_t seglim; // valid and used only if pfn == nullptr
public:
func_tail_iterator_t(void) : pfn(nullptr), idx(-1) {}
func_tail_iterator_t(func_t *_pfn, ea_t ea=BADADDR) : pfn(nullptr) { set(_pfn, ea); }
~func_tail_iterator_t(void)
{
// if was iterating over function chunks, unlock the main chunk
if ( pfn != nullptr )
lock_func_range(pfn, false);
}
bool set(func_t *_pfn, ea_t ea=BADADDR) { return func_tail_iterator_set(this, _pfn, ea); }
bool set_ea(ea_t ea) { return func_tail_iterator_set_ea(this, ea); }
// set an arbitrary range
bool set_range(ea_t ea1, ea_t ea2)
{
this->~func_tail_iterator_t();
pfn = nullptr;
idx = -1;
seglim = range_t(ea1, ea2);
return !seglim.empty();
}
const range_t &chunk(void) const
{
if ( pfn == nullptr )
return seglim;
return idx >= 0 && idx < pfn->tailqty ? pfn->tails[idx] : *(range_t*)pfn;
}
bool first(void) { if ( pfn != nullptr ) { idx = 0; return pfn->tailqty > 0; } return false; } // get only tail chunks
bool last(void) { if ( pfn != nullptr ) { idx = pfn->tailqty - 1; return true; } return false; } // get all chunks (the entry chunk last)
bool next(void) { if ( pfn != nullptr && idx+1 < pfn->tailqty ) { idx++; return true; } return false; }
bool prev(void) { if ( idx >= 0 ) { idx--; return true; } return false; }
bool main(void) { idx = -1; return pfn != nullptr; } // get all chunks (the entry chunk first)
};
/// Function to iterate function chunks (all of them including the entry chunk)
/// \param pfn pointer to the function
/// \param func function to call for each chunk
/// \param ud user data for 'func'
/// \param include_parents meaningful only if pfn points to a function tail.
/// if true, all tail parents will be iterated.
/// if false, only the given tail will be iterated.
idaman void ida_export iterate_func_chunks(
func_t *pfn,
void (idaapi *func)(ea_t ea1, ea_t ea2, void *ud),
void *ud=nullptr,
bool include_parents=false);
/// Class to enumerate all function instructions and data sorted by addresses.
/// The function entry chunk items are enumerated first regardless of their addresses
///
/// Sample code:
/// \code
/// func_item_iterator_t fii;
/// for ( bool ok=fii.set(pfn, ea); ok; ok=fii.next_addr() )
/// ea_t ea = fii.current();
/// ....
/// \endcode
///
/// If 'ea' is not specified in the call to set(), then the enumeration starts at
/// the function entry point.
/// If 'pfn' is specified as nullptr then the set() function will fail,
/// but it is still possible to use the class. In this case the iteration will be
/// limited by the segment boundaries.
/// It is also possible to enumerate addresses in an arbitrary range using set_range().
class func_item_iterator_t
{
func_tail_iterator_t fti;
ea_t ea;
public:
func_item_iterator_t(void) : ea(BADADDR) {}
func_item_iterator_t(func_t *pfn, ea_t _ea=BADADDR) { set(pfn, _ea); }
/// Set a function range. if pfn == nullptr then a segment range will be set.
bool set(func_t *pfn, ea_t _ea=BADADDR)
{
ea = (_ea != BADADDR || pfn == nullptr) ? _ea : pfn->start_ea;
return fti.set(pfn, _ea);
}
/// Set an arbitrary range
bool set_range(ea_t ea1, ea_t ea2) { ea = ea1; return fti.set_range(ea1, ea2); }
bool first(void) { if ( !fti.main() ) return false; ea=fti.chunk().start_ea; return true; }
bool last(void) { if ( !fti.last() ) return false; ea=fti.chunk().end_ea; return true; }
ea_t current(void) const { return ea; }
const range_t &chunk(void) const { return fti.chunk(); }
bool next(testf_t *func, void *ud) { return func_item_iterator_next(this, func, ud); }
bool prev(testf_t *func, void *ud) { return func_item_iterator_prev(this, func, ud); }
bool next_addr(void) { return next(f_any, nullptr); }
bool next_head(void) { return next(f_is_head, nullptr); }
bool next_code(void) { return next(f_is_code, nullptr); }
bool next_data(void) { return next(f_is_data, nullptr); }
bool next_not_tail(void) { return next(f_is_not_tail, nullptr); }
bool prev_addr(void) { return prev(f_any, nullptr); }
bool prev_head(void) { return prev(f_is_head, nullptr); }
bool prev_code(void) { return prev(f_is_code, nullptr); }
bool prev_data(void) { return prev(f_is_data, nullptr); }
bool prev_not_tail(void) { return prev(f_is_not_tail, nullptr); }
bool decode_prev_insn(insn_t *out) { return func_item_iterator_decode_prev_insn(this, out); }
bool decode_preceding_insn(eavec_t *visited, bool *p_farref, insn_t *out)
{ return func_item_iterator_decode_preceding_insn(this, visited, p_farref, out); }
};
/// Class to enumerate all function parents sorted by addresses.
/// Enumeration is started with first() or last().
/// The loop may continue until the next() or prev() function returns false.
/// The parent functions are always sorted by their addresses.
/// The tail chunk is locked during the iteration.
///
/// Sample code:
/// \code
/// func_parent_iterator_t fpi(fnt);
/// for ( bool ok=fpi.first(); ok; ok=fpi.next() )
/// ea_t parent = fpi.parent();
/// ....
/// \endcode
class func_parent_iterator_t
{
func_t *fnt;
int idx;
public:
func_parent_iterator_t(void) : fnt(nullptr), idx(0) {}
func_parent_iterator_t(func_t *_fnt) : fnt(nullptr) { set(_fnt); }
~func_parent_iterator_t(void)
{
if ( fnt != nullptr )
lock_func_range(fnt, false);
}
bool set(func_t *_fnt) { return func_parent_iterator_set(this, _fnt); }
ea_t parent(void) const { return fnt->referers[idx]; }
bool first(void) { idx = 0; return is_func_tail(fnt) && fnt->refqty > 0; }
bool last(void) { idx = fnt->refqty - 1; return idx >= 0; }
bool next(void) { if ( idx+1 < fnt->refqty ) { idx++; return true; } return false; }
bool prev(void) { if ( idx > 0 ) { idx--; return true; } return false; }
void reset_fnt(func_t *_fnt) { fnt = _fnt; } // for internal use only!
};
/// \name Get prev/next address in function
/// Unlike func_item_iterator_t which always enumerates the main function
/// chunk first, these functions respect linear address ordering.
//@{
idaman ea_t ida_export get_prev_func_addr(func_t *pfn, ea_t ea);
idaman ea_t ida_export get_next_func_addr(func_t *pfn, ea_t ea);
//@}
//--------------------------------------------------------------------
/// \name
/// Functions to work with temporary register argument definitions
//@{
idaman void ida_export read_regargs(func_t *pfn);
idaman void ida_export add_regarg(func_t *pfn, int reg, const tinfo_t &tif, const char *name);
//@}
//--------------------------------------------------------------------
// L I B R A R Y M O D U L E S I G N A T U R E S
//--------------------------------------------------------------------
/// \defgroup IDASGN_ Error codes for signature functions:
/// See calc_idasgn_state() and del_idasgn()
//@{
#define IDASGN_OK 0 ///< ok
#define IDASGN_BADARG 1 ///< bad number of signature
#define IDASGN_APPLIED 2 ///< signature is already applied
#define IDASGN_CURRENT 3 ///< signature is currently being applied
#define IDASGN_PLANNED 4 ///< signature is planned to be applied
//@}
/// Add a signature file to the list of planned signature files.
/// \param fname file name. should not contain directory part.
/// \return 0 if failed, otherwise number of planned (and applied) signatures
idaman int ida_export plan_to_apply_idasgn(const char *fname); // plan to use library
/// Apply a signature file to the specified address.
/// \param signame short name of signature file (the file name without path)
/// \param ea address to apply the signature
/// \param is_startup if set, then the signature is treated as a startup one
/// for startup signature ida doesn't rename the first
/// function of the applied module.
/// \return \ref LIBFUNC_
idaman int ida_export apply_idasgn_to(const char *signame, ea_t ea, bool is_startup);
/// Get number of signatures in the list of planned and applied signatures.
/// \return 0..n
idaman int ida_export get_idasgn_qty(void);
/// Get number of the the current signature.
/// \return 0..n-1
idaman int ida_export get_current_idasgn(void);
/// Get state of a signature in the list of planned signatures
/// \param n number of signature in the list (0..get_idasgn_qty()-1)
/// \return state of signature or #IDASGN_BADARG
idaman int ida_export calc_idasgn_state(int n);
/// Remove signature from the list of planned signatures.
/// \param n number of signature in the list (0..get_idasgn_qty()-1)
/// \return #IDASGN_OK, #IDASGN_BADARG, #IDASGN_APPLIED
idaman int ida_export del_idasgn(int n);
/// Get information about a signature in the list.
/// \param signame buffer for the name of the signature.
/// (short form, only base name without the directory part
/// will be stored).
/// if signame == nullptr, then the name won't be returned.
/// \param optlibs buffer for the names of the optional libraries
/// if optlibs == nullptr, then the optional libraries are not returned
/// \param n number of signature in the list (0..get_idasgn_qty()-1)
/// \return number of successfully recognized modules using this signature.
/// -1 means the 'n' is a bad argument, i.e. no signature with this
/// number exists..
idaman int32 ida_export get_idasgn_desc(
qstring *signame,
qstring *optlibs,
int n);
class idasgn_t;
/// Get idasgn header by a short signature name.
/// \param name short name of a signature
/// \return nullptr if can't find the signature
idaman idasgn_t *ida_export get_idasgn_header_by_short_name(const char *name);
/// Get full description of the signature by its short name.
/// \param buf the output buffer
/// \param name short name of a signature
/// \return size of signature description or -1
idaman ssize_t ida_export get_idasgn_title(
qstring *buf,
const char *name);
/// Determine compiler/vendor using the startup signatures.
/// If determined, then appropriate signature files are included into
/// the list of planned signature files.
idaman void ida_export determine_rtl(void);
/// Apply a startup signature file to the specified address.
/// \param ea address to apply the signature to; usually \inf{start_ea}
/// \param startup the name of the signature file without path and extension
/// \return true if successfully applied the signature
idaman bool ida_export apply_startup_sig(ea_t ea, const char *startup);
/// Apply the currently loaded signature file to the specified address.
/// If a library function is found, then create a function and name
/// it accordingly.
/// \param ea any address in the program
/// \returns \ref LIBFUNC_
idaman int ida_export try_to_add_libfunc(ea_t ea);
/// \defgroup LIBFUNC_ Library function codes
/// Return values for try_to_add_libfunc() and apply_idasgn_to()
//@{
#define LIBFUNC_FOUND 0 ///< ok, library function is found
#define LIBFUNC_NONE 1 ///< no, this is not a library function
#define LIBFUNC_DELAY 2 ///< no decision because of lack of information
//@}
// KERNEL mode functions
/// \cond
/// kept in the sdk because inlined
inline void save_signatures(void) {}
bool invalidate_sp_analysis(func_t *pfn);
inline bool invalidate_sp_analysis(ea_t ea)
{ return invalidate_sp_analysis(get_func(ea)); }
/// \endcond
#endif

View File

@@ -1,368 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*
* Graph drawing support
*
*/
#ifndef __GDLDRAW_HPP
#define __GDLDRAW_HPP
#include <map>
#include <set>
#include <funcs.hpp>
/*! \file gdl.hpp
\brief Low level graph drawing operations
*/
//-------------------------------------------------------------------------
// forward declarations:
class node_iterator;
class qflow_chart_t;
class gdl_graph_t;
/// Flow chart block types
enum fc_block_type_t
{
fcb_normal, ///< normal block
fcb_indjump, ///< block ends with indirect jump
fcb_ret, ///< return block
fcb_cndret, ///< conditional return block
fcb_noret, ///< noreturn block
fcb_enoret, ///< external noreturn block (does not belong to the function)
fcb_extern, ///< external normal block
fcb_error, ///< block passes execution past the function end
};
#ifndef SWIG
#define DECLARE_HELPER(decl) \
decl node_iterator *ida_export node_iterator_goup(node_iterator *); \
decl void ida_export create_qflow_chart(qflow_chart_t &); \
decl bool ida_export append_to_flowchart(qflow_chart_t &, ea_t, ea_t); \
decl fc_block_type_t ida_export fc_calc_block_type(const qflow_chart_t &, size_t); \
decl bool ida_export create_multirange_qflow_chart(qflow_chart_t &, const rangevec_t &);
#else
#define DECLARE_HELPER(decl)
#endif // SWIG
DECLARE_HELPER(idaman)
//-------------------------------------------------------------------------
/// Set of integer constants
class intset_t : public std::set<int>
{
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
size_t idaapi print(char *buf, size_t bufsize) const;
const char *idaapi dstr(void) const;
bool has(int value) const
{
const_iterator p = find(value);
const_iterator q = end();
return p != q;
}
};
typedef qvector<intvec_t> array_of_intvec_t;
/// Map of integer constants to integer constants
class intmap_t : public std::map<int, int>
{
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
size_t idaapi print(char *buf, size_t bufsize) const;
const char *idaapi dstr(void) const;
};
typedef qvector<intmap_t> array_of_intmap_t;
//-------------------------------------------------------------------------
/// Set of graph nodes
class node_set_t : public intset_t
{
public:
idaapi node_set_t(void) {}
idaapi node_set_t(int node) { insert(node); }
idaapi node_set_t(const gdl_graph_t *g);
bool idaapi add(int node) { return insert(node).second; }
void idaapi sub(int node) { erase(node); }
void idaapi sub(const node_set_t &r);
void idaapi add(const node_set_t &r);
void idaapi intersect(const node_set_t &r);
void idaapi extract(intvec_t &out) const;
int idaapi first(void) const { return empty() ? -1 : *begin(); }
};
typedef qvector<node_set_t> array_of_node_set_t;
//-------------------------------------------------------------------------
/// Node iterator (used to draw graphs)
class node_iterator
{
DECLARE_HELPER(friend)
friend class gdl_graph_t;
const gdl_graph_t *g;
int i;
node_iterator &_goup(void);
node_iterator &goup(void) { return *node_iterator_goup(this); }
public:
node_iterator(const gdl_graph_t *_g, int n) : g(_g), i(n) {}
node_iterator &operator++(void) { i++; return goup(); }
bool operator==(const node_iterator &n) const { return i == n.i && g == n.g; }
bool operator!=(const node_iterator &n) const { return !(*this == n); }
int operator*(void) const { return i; }
};
//-------------------------------------------------------------------------
/// gdl graph interface - includes only functions required to draw it
class gdl_graph_t
{
// does a path from 'm' to 'n' exist?
bool idaapi path(node_set_t &visited, int m, int n) const;
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
DEFINE_VIRTUAL_DTOR(gdl_graph_t)
virtual char *idaapi get_node_label(char *buf, int /*bufsize*/, int /*n*/) const { buf[0] = '\0'; return buf; }
virtual void idaapi print_graph_attributes(FILE * /*fp*/) const {}
virtual bool idaapi print_node(FILE * /*fp*/, int /*n*/) const { return false; }
virtual bool idaapi print_edge(FILE * /*fp*/, int /*i*/, int /*j*/) const { return false; }
virtual void idaapi print_node_attributes(FILE * /*fp*/, int /*n*/) const {}
virtual int idaapi size(void) const = 0; // number of the max node number
virtual int idaapi node_qty(void) const { return size(); } // number of alive nodes
virtual bool idaapi exists(int /*node*/) const { return true; }
virtual int idaapi entry(void) const { return 0; }
virtual int idaapi exit(void) const { return size()-1; }
virtual int idaapi nsucc(int node) const = 0;
virtual int idaapi npred(int node) const = 0;
virtual int idaapi succ(int node, int i) const = 0;
virtual int idaapi pred(int node, int i) const = 0;
virtual bool idaapi empty(void) const { return node_qty() == 0; }
virtual bgcolor_t idaapi get_node_color(int /*n*/) const { return DEFCOLOR; }
virtual bgcolor_t idaapi get_edge_color(int /*i*/, int /*j*/) const { return DEFCOLOR; }
void idaapi gen_gdl(FILE *fp) const;
void idaapi gen_gdl(const char *file) const;
size_t idaapi nedge(int node, bool ispred) const { return ispred ? npred(node) : nsucc(node); }
int idaapi edge(int node, int i, bool ispred) const { return ispred ? pred(node, i) : succ(node, i); }
int idaapi front(void) { return *begin(); }
node_iterator idaapi begin(void) const { return node_iterator(this, 0).goup(); }
node_iterator idaapi end(void) const { return node_iterator(this, size()); }
// does a path from 'm' to 'n' exist?
bool idaapi path_exists(int m, int n) const { node_set_t v; return path(v, m, n); }
void idaapi gen_dot(FILE *fp) const;
void idaapi gen_dot(const char *file) const;
};
/// Create GDL file for graph
idaman void ida_export gen_gdl(const gdl_graph_t *g, const char *fname);
/// Display GDL file by calling wingraph32.
/// The exact name of the grapher is taken from the configuration file
/// and set up by setup_graph_subsystem().
/// \return error code from os, 0 if ok
idaman int ida_export display_gdl(const char *fname);
//-------------------------------------------------------------------------
// Build and display program graphs
/// Build and display a flow graph.
/// \param filename output file name. the file extension is not used. maybe NULL.
/// \param title graph title
/// \param pfn function to graph
/// \param ea1, ea2 if pfn == NULL, then the address range
/// \param gflags combination of \ref CHART_1.
/// if none of #CHART_GEN_DOT, #CHART_GEN_GDL, #CHART_WINGRAPH
/// is specified, the function will return false
/// \return success. if fails, a warning message is displayed on the screen
idaman bool ida_export gen_flow_graph(
const char *filename,
const char *title,
func_t *pfn,
ea_t ea1,
ea_t ea2,
int gflags);
/// \defgroup CHART_1 Flow graph building flags
/// Passed as flags parameter to:
/// - gen_flow_graph()
/// - gen_simple_call_chart()
/// - gen_complex_call_chart()
//@{
#define CHART_PRINT_NAMES 0x1000 ///< print labels for each block?
#define CHART_GEN_DOT 0x2000 ///< generate .dot file (file extension is forced to .dot)
#define CHART_GEN_GDL 0x4000 ///< generate .gdl file (file extension is forced to .gdl)
#define CHART_WINGRAPH 0x8000 ///< call grapher to display the graph
//@}
/// Build and display a simple function call graph.
/// \param filename output file name. the file extension is not used. maybe NULL.
/// \param wait message to display during graph building
/// \param title graph title
/// \param gflags combination of #CHART_NOLIBFUNCS and \ref CHART_1.
/// if none of #CHART_GEN_DOT, #CHART_GEN_GDL, #CHART_WINGRAPH
/// is specified, the function will return false.
/// \return success. if fails, a warning message is displayed on the screen
idaman bool ida_export gen_simple_call_chart(
const char *filename,
const char *wait,
const char *title,
int gflags);
/// Build and display a complex xref graph.
/// \param filename output file name. the file extension is not used. maybe NULL.
/// \param wait message to display during graph building
/// \param title graph title
/// \param ea1, ea2 address range
/// \param flags combination of \ref CHART_2 and \ref CHART_1.
/// if none of #CHART_GEN_DOT, #CHART_GEN_GDL, #CHART_WINGRAPH
/// is specified, the function will return false.
/// \param recursion_depth optional limit of recursion
/// \return success. if fails, a warning message is displayed on the screen
idaman bool ida_export gen_complex_call_chart(
const char *filename,
const char *wait,
const char *title,
ea_t ea1,
ea_t ea2,
int flags,
int32 recursion_depth=-1);
/// \defgroup CHART_2 Call chart building flags
/// Passed as flags parameter to gen_complex_call_chart()
//@{
#define CHART_NOLIBFUNCS 0x0400 ///< don't include library functions in the graph
#define CHART_REFERENCING 0x0001 ///< references to the addresses in the list
#define CHART_REFERENCED 0x0002 ///< references from the addresses in the list
#define CHART_RECURSIVE 0x0004 ///< analyze added blocks
#define CHART_FOLLOW_DIRECTION 0x0008 ///< analyze references to added blocks only in the direction of the reference who discovered the current block
#define CHART_IGNORE_XTRN 0x0010
#define CHART_IGNORE_DATA_BSS 0x0020
#define CHART_IGNORE_LIB_TO 0x0040 ///< ignore references to library functions
#define CHART_IGNORE_LIB_FROM 0x0080 ///< ignore references from library functions
#define CHART_PRINT_COMMENTS 0x0100
#define CHART_PRINT_DOTS 0x0200 ///< print dots if xrefs exist outside of the range recursion depth
//@}
/// Setup the user-defined graph colors and graph viewer program.
/// This function is called by the GUI at the beginning, so no need to call
/// it again.
idaman void ida_export setup_graph_subsystem(const char *_grapher, bgcolor_t (idaapi *get_graph_color)(int color));
//-V:cancellable_graph_t:730 not all members of a class are initialized inside the constructor
class cancellable_graph_t : public gdl_graph_t
{
public:
mutable bool cancelled;
char padding[3]; // make the class nicely aligned. otherwise we have problems
// with gcc in qflow_chart_t.
cancellable_graph_t(void) : cancelled(false) {}
DEFINE_VIRTUAL_DTOR(cancellable_graph_t)
bool idaapi check_cancel(void) const;
};
//--------------------------------------------------------------------------
/// Information about a basic block of a \ref qflow_chart_t
struct qbasic_block_t : public range_t
{
intvec_t succ; ///< list of node successors
intvec_t pred; ///< list of node predecessors
};
/// Does this block never return?
inline THREAD_SAFE bool is_noret_block(fc_block_type_t btype)
{
return btype == fcb_noret || btype == fcb_enoret;
}
/// Does this block return?
inline THREAD_SAFE bool is_ret_block(fc_block_type_t btype)
{
return btype == fcb_ret || btype == fcb_cndret;
}
/// \defgroup FC_ Flow chart flags
/// Passed as 'flags' parameter to qflow_chart_t
//@{
#define FC_PRINT 0x0001 ///< print names (used only by display_flow_chart())
#define FC_NOEXT 0x0002 ///< do not compute external blocks. Use this to prevent jumps leaving the
///< function from appearing in the flow chart. Unless specified, the
///< targets of those outgoing jumps will be present in the flow
///< chart under the form of one-instruction blocks
#define FC_RESERVED 0x0004 // former FC_PREDS
#define FC_APPND 0x0008 ///< multirange flowchart (set by append_to_flowchart)
#define FC_CHKBREAK 0x0010 ///< build_qflow_chart() may be aborted by user
#define FC_CALL_ENDS 0x0020 ///< call instructions terminate basic blocks
#define FC_NOPREDS 0x0040 ///< do not compute predecessor lists
//@}
/// A flow chart for a function, or a set of address ranges
class qflow_chart_t : public cancellable_graph_t
{
public:
typedef qvector<qbasic_block_t> blocks_t;
DECLARE_HELPER(friend)
qstring title;
range_t bounds; ///< overall bounds of the qflow_chart_t instance
func_t *pfn = nullptr; ///< the function this instance was built upon
int flags = 0; ///< flags. See \ref FC_
blocks_t blocks; ///< basic blocks
int nproper = 0; ///< number of basic blocks belonging to the specified range
idaapi qflow_chart_t(void) {}
idaapi qflow_chart_t(const char *_title, func_t *_pfn, ea_t _ea1, ea_t _ea2, int _flags)
: title(_title), bounds(_ea1, _ea2), pfn(_pfn), flags(_flags)
{
refresh();
}
DEFINE_VIRTUAL_DTOR(qflow_chart_t)
void idaapi create(const char *_title, func_t *_pfn, ea_t _ea1, ea_t _ea2, int _flags)
{
title = _title;
pfn = _pfn;
bounds = range_t(_ea1, _ea2);
flags = _flags;
refresh();
}
void idaapi create(const char *_title, const rangevec_t &ranges, int _flags)
{
title = _title;
flags = _flags;
create_multirange_qflow_chart(*this, ranges);
}
void idaapi append_to_flowchart(ea_t ea1, ea_t ea2) { ::append_to_flowchart(*this, ea1, ea2); }
void idaapi refresh(void) { create_qflow_chart(*this); }
fc_block_type_t calc_block_type(size_t blknum) const
{ return fc_calc_block_type(*this, blknum); }
bool is_ret_block(size_t blknum) const { return ::is_ret_block(calc_block_type(blknum)); }
bool is_noret_block(size_t blknum) const { return ::is_noret_block(calc_block_type(blknum)); }
virtual void idaapi print_node_attributes(FILE * /*fp*/, int /*n*/) const override {}
virtual int idaapi nsucc(int node) const override { return int(blocks[node].succ.size()); }
virtual int idaapi npred(int node) const override { return int(blocks[node].pred.size()); }
virtual int idaapi succ(int node, int i) const override { return blocks[node].succ[i]; }
virtual int idaapi pred(int node, int i) const override { return blocks[node].pred[i]; }
virtual char *idaapi get_node_label(char * /*buf*/, int /*bufsize*/, int /*n*/) const override { return NULL; }
virtual int idaapi size(void) const override { return int(blocks.size()); }
bool idaapi print_names(void) const { return (flags & FC_PRINT) != 0; }
};
#endif // __GDLDRAW_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -1,73 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _HELP_H
#define _HELP_H
typedef int help_t; /* Help messages are referred by ints */
// Get pointer to message text by its message id
// The message texts are read from ida.hlp at the beginning
// Returns: pointer to message text (NULL is never returned by IDA)
idaman THREAD_SAFE const char *ida_export itext(help_t msg_id);
#ifdef __KERNWIN_HPP
GCC_DIAG_OFF(format-nonliteral);
NORETURN inline void Err(help_t format, ...)
{
va_list va;
va_start(va, format);
verror(itext(format), va);
// NOTREACHED
}
inline void Warn(help_t format, ...)
{
va_list va;
va_start(va, format);
vwarning(itext(format), va);
va_end(va);
}
inline void Info(help_t format, ...)
{
va_list va;
va_start(va, format);
vinfo(itext(format), va);
va_end(va);
}
inline int Message(help_t format,...)
{
va_list va;
va_start(va, format);
int nbytes = vmsg(itext(format), va);
va_end(va);
return nbytes;
}
inline int vask_yn(int deflt, help_t format, va_list va)
{
return vask_yn(deflt, itext(format), va);
}
inline int ask_yn(int deflt, help_t format, ...)
{
va_list va;
va_start(va, format);
int code = vask_yn(deflt, itext(format), va);
va_end(va);
return code;
}
GCC_DIAG_ON(format-nonliteral);
#endif
#ifndef NO_OBSOLETE_FUNCS
#endif
#endif /* _HELP_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,146 +0,0 @@
#ifndef IDA_HIGHLIGHTER
#define IDA_HIGHLIGHTER
#include <expr.hpp>
idaman void ida_export code_highlight_block(void *context, highlighter_cbs_t *highlighter_cbs, const qstring &text);
// returns the length of text to colorize
// negative values may have special meaning in the future.
typedef ssize_t idaapi external_colorizer_t(syntax_highlight_style *color, const char *str);
typedef qvector<external_colorizer_t *> external_colorizers_t;
// returns true if identifier is colorized
typedef bool idaapi external_ident_colorizer_t(syntax_highlight_style *color, const qstring &ident);
typedef qvector<external_ident_colorizer_t *> external_ident_colorizers_t;
#define MLTCMTMASK 0xF
#define PREPROC_FLAG 0x10
// Common implementation of syntax_highlighter_t used in different parts of IDA
//-V:ida_syntax_highlighter_t:730 not all members of a class are initialized inside the constructor
struct ida_syntax_highlighter_t : syntax_highlighter_t
{
protected:
// keys of keywords_t point to memory from keyword_strings.
// once allocated, this buffer won't be moved in the memory.
qstrvec_t keyword_memory;
// helper class so that keywords_t gets sorted by string contents, not pointer values.
struct plain_char_ptr_t
{
const char *ptr;
plain_char_ptr_t(const char *p = NULL) : ptr(p) {}
bool operator <(const plain_char_ptr_t &r) const
{
return strcmp(ptr, r.ptr) < 0;
}
bool operator ==(const plain_char_ptr_t &r) const
{
return strcmp(ptr, r.ptr) == 0;
}
};
struct multicmt_t
{
qstring open_multicmt;
qstring close_multicmt;
multicmt_t() {}
multicmt_t(const char *_open_multicmt, const char *_close_multicmt) :
open_multicmt(_open_multicmt),
close_multicmt(_close_multicmt)
{}
};
// typedef std::map<plain_char_ptr_t, syntax_highlight_style> keywords_t;
struct keywords_style_t
{
qvector<plain_char_ptr_t> keywords;
syntax_highlight_style style;
};
typedef qvector<keywords_style_t> keywords_t;
//typedef qvector<plain_char_ptr_t> keywords_t;
typedef qvector<multicmt_t> multicmtvec_t;
keywords_t keywords;
qstring open_cmt; // string that opens a regular line comment
multicmtvec_t multicmts;
char literal_closer; // either close_strconst or close_chrconst for the current literal
// color mappings
syntax_highlight_style text_color = HF_DEFAULT;
syntax_highlight_style comment_color = HF_COMMENT;
syntax_highlight_style string_color = HF_STRING;
syntax_highlight_style preprocessor_color = HF_PREPROC;
external_colorizers_t external_colorizers;
external_ident_colorizers_t external_ident_colorizers;
// work variables
const char *input; // pointer to the start of the input buffer
const char *pending; // pointer in the input buffer
syntax_highlight_style style = HF_DEFAULT; // current highlighting style
bool pending_nonspaces_present(const char *end)
{
for ( const char *p = pending; p != end; ++p )
if ( !qisspace(*p) )
return true;
return false;
}
const char *parse_literal_const(highlighter_cbs_t *highlighter_cbs, const char *ptr, char literal_closer);
void flush_output(highlighter_cbs_t *highlighter_cbs, const char *ptr, syntax_highlight_style style);
void handle_cmt(highlighter_cbs_t *highlighter_cbs, int mcmt_idx, const char **ptr);
void handle_preproc(highlighter_cbs_t *highlighter_cbs, const char **ptr);
public:
// if any of the following features is not needed, just zero them out:
char open_strconst; // character that opens a string constant
char close_strconst; // character that closes a string constant
char open_chrconst; // character that closes a character constant
char close_chrconst; // character that opens a character constant
char escape_char; // backslash
char preprocessor_char; // #
ida_syntax_highlighter_t() : syntax_highlighter_t(&code_highlight_block) {}
void highlight_block_ex(highlighter_cbs_t *highlighter_cbs, const qstring &text);
void add_external_colorizer(external_colorizer_t *th) { external_colorizers.push_back(th); }
void add_external_ident_colorizer(external_ident_colorizer_t *th) { external_ident_colorizers.push_back(th); }
void set_open_cmt(const char *begin) { open_cmt = begin; }
void add_multi_line_comment(const char *begin, const char *end)
{
multicmt_t &mcmt = multicmts.push_back();
mcmt.open_multicmt = begin;
mcmt.close_multicmt = end;
}
void add_keywords(const char *kwstr, syntax_highlight_style _style)
{
char *ctx;
// in order not to allocate every keyword separately, we allocate the whole
// kwstr string at once and will just store pointers to it in the map.
qstring &mem = keyword_memory.push_back();
mem = kwstr;
keywords_style_t *pair_p = NULL;
for ( int i = 0; i < keywords.size(); i++ )
{
if ( keywords[i].style == _style )
{
pair_p = &keywords[i];
break;
}
}
if ( pair_p == NULL )
{
keywords_style_t &pair = keywords.push_back();
pair_p = &pair;
pair_p->style = _style;
}
for ( char *kw = qstrtok(mem.begin(), "|", &ctx); kw != NULL; kw = qstrtok(NULL, "|", &ctx) )
pair_p->keywords.push_back(kw);
}
};
#endif //IDA_HIGHLIGHTER

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,306 +0,0 @@
/*
* Interactive disassembler (IDA)
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
* Floating Point Number Libary.
* Copyright (c) 1995-2006 by Iouri Kharon.
* E-mail: yjh@styx.cabel.net
*
*/
#ifndef _IEEE_H_
#define _IEEE_H_
/*! \file ieee.h
\brief IEEE floating point functions
*/
//-------------------------------------------------------------------
/// Number of 16 bit words in ::eNE
#define IEEE_NE 6
/// Number of 16 bit words in ::eNI
#define IEEE_NI (IEEE_NE+3)
//==========================================================================
/// Array offset to exponent
#define IEEE_E 1
/// Array offset to high guard word
#define IEEE_M 2
/// The exponent of 1.0
#define IEEE_EXONE (0x3fff)
//===================================================================
/// External x type format
typedef uint16 eNE[IEEE_NE];
/// Internal format:
/// - 0 : sign (0/1)
/// - 1 : exponent (based of #IEEE_EXONE). If exp = 0, value = 0.
/// - 2 : high word of mantissa (always zero after normalize)
typedef uint16 eNI[IEEE_NI];
/// Exponent in eNE for NaN and Inf
#define E_SPECIAL_EXP 0x7fff
/// 0.0
extern const eNE ieee_ezero;
#define EZERO { 0, 0000000,0000000,0000000,0000000,0000000 }
/// 1.0
extern const eNE ieee_eone;
#define EONE { 0, 0000000,0000000,0000000,0100000,0x3fff }
/// 2.0
extern const eNE ieee_etwo;
/// 32.0
extern const eNE ieee_e32;
/// 6.93147180559945309417232121458176568075500134360255E-1
extern const eNE ieee_elog2;
/// 1.41421356237309504880168872420969807856967187537695E0
extern const eNE ieee_esqrt2;
/// 2/sqrt(PI) = 1.12837916709551257389615890312154517168810125865800E0
extern const eNE ieee_eoneopi;
/// 3.14159265358979323846264338327950288419716939937511E0
extern const eNE ieee_epi;
/// 5.7721566490153286060651209008240243104215933593992E-1
extern const eNE ieee_eeul;
/// Clear (zero-out) the given value
inline void ecleaz(eNI x) { memset(x, 0, sizeof(eNI)); }
/// Move eNI => eNE
idaman THREAD_SAFE void ida_export emovo(const eNI a, eNE b);
/// Move eNE => eNI
idaman THREAD_SAFE void ida_export emovi(const eNE a, eNI b);
/// Shift NI format up (+) or down
idaman THREAD_SAFE int ida_export eshift(eNI x, int sc);
/// Normalize and round off.
/// \param s the internal format number to be rounded
/// \param lost indicates whether or not the number is exact.
/// this is the so-called sticky bit.
/// \param subflg indicates whether the number was obtained
/// by a subtraction operation. In that case if lost is nonzero
/// then the number is slightly smaller than indicated.
/// \param exp the biased exponent, which may be negative.
/// the exponent field of "s" is ignored but is replaced by
/// "exp" as adjusted by normalization and rounding.
/// \param rndbase if 0 => is the rounding control.
/// else is processor defined base (rndprc)
/// \return success
idaman THREAD_SAFE int ida_export emdnorm(eNI s, int lost, int subflg, int32 exp, int rndbase);
/// \defgroup REAL_ERROR_ Floating point/IEEE Conversion codes
/// Return values for and processor_t::realcvt_t request
//@{
#define REAL_ERROR_FORMAT -1 ///< not supported format for current .idp
#define REAL_ERROR_RANGE -2 ///< number too big (small) for store (mem NOT modified)
#define REAL_ERROR_BADDATA -3 ///< illegal real data for load (IEEE data not filled)
//@}
//
/// \name Prototypes
/// IDP module event prototype -- should be implemented in idp
//@{
/// Floating point conversion function: implemented by \ph{realcvt}.
/// \param m pointer to data
/// \param e internal IEEE format data
/// \param swt operation:
/// - 000: load trunc. float (DEC ^F) 2 bytes (m->e)
/// - 001: load float 4 bytes (m->e)
/// - 003: load double 8 bytes (m->e)
/// - 004: load long double 10 bytes (m->e)
/// - 005: load long double 12 bytes (m->e)
/// - 010: store trunc. float (DEC ^F) 2 bytes (e->m)
/// - 011: store float 4 bytes (e->m)
/// - 013: store double 8 bytes (e->m)
/// - 014: store long double 10 bytes (e->m)
/// - 015: store long double 12 bytes (e->m)
/// \retval 0 ok
/// \retval \ref REAL_ERROR_ on error
int idaapi realcvt(void *m, eNE e, uint16 swt);
/// Little endian
int l_realcvt(void *m, eNE e, uint16 swt);
/// Big endian
int b_realcvt(void *m, eNE e, uint16 swt);
//@}
/// Standard IEEE 754 floating point conversion function.
/// See comment for realcvt().
idaman THREAD_SAFE int ida_export ieee_realcvt(void *m, eNE e, uint16 swt);
/// \name Misc arithmetic/conversion functions
/// \retval 0 ok
/// \retval 1 overfloat / underfloat
/// \retval 2 illegal data (asctoreal())
/// \retval 3 divide by 0 (ediv())
/// \retval 4 too big for integer (eetol())
//@{
/// IEEE to ascii string.
/// \param mode broken down into:
/// - low byte: number of digits after '.'
/// - second byte: FPNUM_LENGTH
/// - third byte: FPNUM_DIGITS
idaman THREAD_SAFE void ida_export realtoasc(char *buf, size_t bufsize, const eNE x, uint mode);
/// ascii string to IEEE
idaman THREAD_SAFE int ida_export asctoreal(const char **sss, eNE y);
/// long to IEEE
idaman THREAD_SAFE void ida_export eltoe(sval_t l, eNE e);
/// int64 to IEEE
idaman THREAD_SAFE void ida_export eltoe64(int64 l, eNE e);
/// uint64 to IEEE
idaman THREAD_SAFE void ida_export eltoe64u(uint64 l, eNE e);
/// IEEE to long (+-0.5 if flg)
idaman THREAD_SAFE int ida_export eetol(sval_t *l, const eNE a, bool roundflg);
/// IEEE to long (+-0.5 if flg)
idaman THREAD_SAFE int ida_export eetol64(int64 *l, const eNE a, bool roundflg);
/// IEEE to ulong (+-0.5 if flg)
idaman THREAD_SAFE int ida_export eetol64u(uint64 *l, const eNE a, bool roundflg);
/// b = a*(2**pwr2)
idaman THREAD_SAFE int ida_export eldexp(const eNE a, int32 pwr2, eNE b);
/// if(!subflg) c = a + b,
/// else c = a - b
idaman THREAD_SAFE int ida_export eadd(const eNE a, const eNE b, eNE c, int subflg);
/// c = a * b
idaman THREAD_SAFE int ida_export emul(const eNE a, const eNE b, eNE c);
/// c = a / b
idaman THREAD_SAFE int ida_export ediv(const eNE a, const eNE b, eNE c);
// predefined functions
/// \cond
void eclear(eNE a);
void emov(eNE a, eNE b);
void eabs(eNE x);
int esign(eNE x);
/// \endcond
/// x = 0
#define eclear(a) memset(a, 0, sizeof(eNE))
/// b = a
#define emov(a, b) memcpy(b, a, sizeof(eNE))
/// x = |x|
#define eabs(x) (x[IEEE_NE-1] &= 0x7fff)
#ifdef __cplusplus
/// x = -x
inline void eneg(eNE x)
{
if ( x[IEEE_NE-1] != 0 )
x[IEEE_NE-1] ^= 0x8000;
}
#endif
/// x < 0 ?
/// \note non standard answer is returned
#define esign(x) (x[IEEE_NE-1] & 0x8000)
//@}
/// Comparison.
/// \retval 0 if a = b
/// \retval 1 if a > b
/// \retval -1 if a < b
idaman THREAD_SAFE int ida_export ecmp(const eNE a, const eNE b);
/// Check for NaN/Inf
enum fpvalue_kind_t
{
FPV_BADARG, ///< wrong value of max_exp
FPV_NORM, ///< regular value
FPV_NAN, ///< NaN
FPV_PINF, ///< positive infinity
FPV_NINF, ///< negative infinity
};
/// \name max_exp values
/// common values for max_exp (for IEEE floating point values)
//@{
const uint32
MAXEXP_FLOAT = 0x80,
MAXEXP_DOUBLE = 0x400,
MAXEXP_LNGDBL = 0x4000;
//@}
/// See ::fpvalue_kind_t
idaman THREAD_SAFE fpvalue_kind_t ida_export get_fpvalue_kind(const eNE a, uint16 reserved = 0);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,824 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __JUMPTABLE_HPP
#define __JUMPTABLE_HPP
#include <pro.h>
#include <ua.hpp> // op_t
#include <nalt.hpp> // switch_info_t, jumptable_info_t
#include <map>
// Class to check for a jump table sequence.
// This class should be used in preference to the hard encoding of jump table sequences
// because it allows for:
// - instruction rescheduling
// - intermingling the jump sequence with other instructions
// - sequence variants
//
// For this class:
// all instructions of the sequence are numbered starting from the last instruction.
// The last instruction has the number 0.
// The instruction before the last instruciton has the number 1, etc.
// There is a virtual function jpiN() for each instruction of the sequence
// These functions return true if 'insn' is filled with the required instruction
//
// The comparison is made in the match() function:
//
// ea points to the last instruction of the sequence (instruction #0)
//
// the 'depends' array contains dependencies between the instructions of the sequence.
// For example:
// ARM thumb LDRH switch
// 7 SUB Ra, #minv (optional)
// 6 CMP Ra, #size
// 5 BCS defea
// 4 ADR Rb, jt
// 3 ADD Rb, Rb, Ra
// 2 LDRH Rb, [Rb,Ra]
// 1 LSL Rb, Rb, #1
// 0 ADD PC, Rb
// In this sequence, instruction #0 depends on the value of Rb which is produced
// by the instruction #1. So, the instruction #0 depends on #1. Therefore, depends[0]
// will contain '1' as its element.
// The instruction #3 depends on 2 registers: Ra and Rb, or in other words,
// it depends on the instructions #4 and #6. Therefore, depends[2] will contain { 4, 6 }
// Maximum 4 dependencies per instruction are allowed.
//
// FIXME
// The 'roots' array contains the first instruction of the dependency chains.
// In our case we can say that there are 2 dependency chains:
// 0 -> 1 -> 2 -> 3 -> 4
// -> 6 -> 7
// 5 -> 6
// Therefore the roots array will consist of {1, 5}.
// 0 denotes the end of the chain and cannot be the root of a dependency chain
// Usually 1 is a root of any jump sequence.
//
// The dependency array allows for checking for optimized sequences of instructions.
// If 2 instructions are not dependent on each other, they may appear in any order.
// (for example, the instruction #4 and the instruction sequence #5-6-7 may appear
// in any order because they do not depend on each other)
// Also any other instructions not modifying the register values may appear between
// the instructions of the sequence (due to the instruction rescheduling performed
// by the compiler).
//
// Provision for optional instructions:
// The presence of an optional instruction in the sequence (like #7) is signalled
// by a negative number of the dependency in the 'depends' array.
//
// Provision for variable instructions:
// In some cases several variants of the same instructions may be supported.
// For example, the instruction #5 might be BCS as well as BGE. It is the job of
// the jpi5() function to check for all variants.
//
// In order to use the 'jump_pattern_t' class you should derive another class from it
// and define the jpiN() virtual functions.
// Then you have to define the 'depends' and 'roots' arrays and call the match()
// function.
// If you processor contains instructions who modify registers in peculiar ways
// you might want to override the check_spoiled() function.
//----------------------------------------------------------------------
// Macro to declare implementation of methods of jump_pattern_t
class jump_pattern_t;
// tracked registers
// We use the 'size' term to denote the number of bits involved in the insn.
// E.g. an operand of type dt_byte has 8-bit size.
// We store the current size (the number of used bits) in the DTYPE field
// of the 'op_t' structure. It may differ from the size of operand in the
// insn. See the comment for set_moved().
// We extend the 'op_dtype_t' type by some negative constants to denote
// sizes from 2 to 7 bits.
typedef qvector<op_t> tracked_regs_t;
#define DECLARE_JUMP_PATTERN_HELPERS(decl)\
decl void ida_export check_spoiled_jpt(const jump_pattern_t *_this, tracked_regs_t *_regs); \
decl bool ida_export match_jpt(jump_pattern_t *_this);\
decl bool ida_export same_value_jpt(jump_pattern_t *_this, const op_t &op, int r_i);\
decl void ida_export combine_regs_jpt(jump_pattern_t *_this, tracked_regs_t *dst, const tracked_regs_t &src, ea_t ea);\
decl void ida_export mark_switch_insns_jpt(const jump_pattern_t *_this, int last, int);\
decl bool ida_export set_moved_jpt(const jump_pattern_t *_this, const op_t &dst, const op_t &src, tracked_regs_t &_regs, op_dtype_t real_dst_dtype, op_dtype_t real_src_dtype);
DECLARE_JUMP_PATTERN_HELPERS(idaman)
class jump_pattern_t
{
protected:
// 32-bit operand generates a 32-bit result, zero- or sign-extended to a
// 64-bit result. This flag may be overwritten in processor modules.
// For example:
// ARM: MOV W8, #0x3C will clear the upper 32 bits of X8,
// PC : mov eax, 3Ch will clear the upper 32 bits of rax
bool modifying_r32_spoils_r64;
public:
typedef bool (jump_pattern_t::*check_insn_t)(void);
inline jump_pattern_t(
switch_info_t *si, // may be NULL
const char (*depends)[4],
int last_reg);
insn_t insn; // current instruction
switch_info_t *si; // answers will be here
enum
{
NINS = 16, // the maximum length of the sequence
INS_MASK = 0x0F,
};
ea_t eas[NINS];
bool skip[NINS]; // do not check the Nth insn if skip[N] is true
int non_spoiled_reg; // if non_spoiled_reg was spoiled then we stop
// matching
check_insn_t check[NINS];
// this is the hidden return value of the jpiN() methods. If it is set and
// jpiN() returned 'true' then we stop processing the dependency chain. If
// it is set and jpiN() returned 'false' then we stop checking the insns
// in the current basic block and we are switching to the next one (and we
// fail if there is no such block).
bool stop_matching;
// this flag can be analyzed by jpiN(). It means that the current insn is
// in the linear flow from the previous insn. It is always 'true' if the
// insn has JPT_NEAR flag.
bool in_linear_flow;
// this address can be analyzed by jpiN(). It means the end of the current
// block. It may help if we want to check in-block jumps.
ea_t block_end;
#define JPT_OPT 0x10 // the dependent insn might be missing
#define JPT_NEAR 0x20 // the dependent insn must be in the linear flow
const char (*depends)[4]; // instruction, on which we depend, and
// additional JPT_... flags
// mark swith instructions to be ignored by the decompiler
// do not mark the indirect jmp (eas[0]) as ignored
// it will be used to recognize switch idioms
// unmark NLOWCASE insns after LAST (in the case of SWI_HXNOLOWCASE flag)
void mark_switch_insns(int last = NINS - 1, int nlowcase = 0) const
{
mark_switch_insns_jpt(this, last, nlowcase);
}
// for fragmented switch idioms, cmp/jbe might be located in a separate
// fragment. we must not mark these instructions as part of the switch
// idiom because doing so would spoil the program logic for the decompiler
// and make the switch operator unreachable. the following vector keeps
// addresses of all instructions which must not be marked. this vector is
// maintained by derived classes.
eavec_t remote_code;
// extra insns used to calculate values (discovered by find_op_value)
eavec_t extra_insn_eas;
// tracked registers
tracked_regs_t regs;
// handle a possible delay slot situation
// while walking backwards in the execution flow
// if <branch> is false and <ea> is in a delay
// slot of a branch likely instruction
// then set <ea> to the branch instruction
// (=annul the delay slot)
// if <branch> is true and the instruction at <ea>
// has a delay slot then set <ea> to the delay slot
// (=execute the delay slot)
virtual void process_delay_slot(ea_t &/*ea*/, bool /*branch*/) const {}
// an artificial register to track the address of the conditional jump
// .value - condition
// .addr - address of the conditional jump
// .specval - address of the default case
// the derived class can use .reg to track the condition register
enum
{
o_condjump = 99,
cc_inc_ncases = 0x01, // increment ncases
cc_check_max_ncases = 0x02, // comparison with the maximum value
};
// compare supported operands
virtual bool equal_ops(const op_t &x, const op_t &y) const
{
if ( x.type != y.type )
return false;
switch ( x.type )
{
case o_void:
// consider spoiled values as not equal
return false;
case o_reg:
// ignore difference in the data size of registers
return x.reg == y.reg;
case o_condjump:
// we do not track the condition flags
return true;
}
return false;
}
// return true if the instruction `insn' is a move one,
// there is no need check spoiled registers in this case
virtual bool handle_mov(tracked_regs_t & /*_regs*/ )
{
return false;
}
// does the instruction `insn' spoil `_regs' ?
virtual void check_spoiled(tracked_regs_t *_regs) const
{
check_spoiled_jpt(this, _regs);
}
// some binaries use the following pattern
// xor eax, eax | mov al, cl
// so we can extend dtype of the operand from dt_byte to dt_dword
virtual op_dtype_t extend_dtype(const op_t &op) const
{
return op.dtype; // do not extend
}
// these methods are not virtual and should be used in processor
// module only
inline void track(int reg, int r_i, op_dtype_t dtype);
inline void trackop(const op_t &op, int r_i);
inline bool is_spoiled(int r_i) { return regs[r_i].type == o_void; }
inline bool is_equal(int reg, int r_i, op_dtype_t dtype);
inline bool is_equal(const op_t &op, int r_i);
inline bool same_value(const op_t &op, int r_i);
virtual bool jpi0(void) = 0;
virtual bool jpi1(void) { return false; }
virtual bool jpi2(void) { return false; }
virtual bool jpi3(void) { return false; }
virtual bool jpi4(void) { return false; }
virtual bool jpi5(void) { return false; }
virtual bool jpi6(void) { return false; }
virtual bool jpi7(void) { return false; }
virtual bool jpi8(void) { return false; }
virtual bool jpi9(void) { return false; }
virtual bool jpia(void) { return false; }
virtual bool jpib(void) { return false; }
virtual bool jpic(void) { return false; }
virtual bool jpid(void) { return false; }
virtual bool jpie(void) { return false; }
virtual bool jpif(void) { return false; }
// jpi<n> will be called if pre_jpi returns true
virtual bool pre_jpi(int /*n*/) { return true; }
bool match(const insn_t &_insn) { insn = _insn; return match_jpt(this); }
// remove compiler warnings -- class with virtual functions MUST have virtual destructor
virtual ~jump_pattern_t() {}
// helpers for mov instruction tracing (see methods handle_mov(),
// check_spoiled() above)
inline static void set_spoiled(tracked_regs_t *_regs);
inline void set_spoiled(tracked_regs_t *_regs, const op_t &op) const;
// track 'mov' insn: dst <- src
// it returns 'true' if insn changes any of the tracked registers
// REAL_DST_DTYPE is the size that will be changed in the DST operand by
// the insn. It can be greater than the operand size because some insns
// clear the upper bits. For example:
// xor eax, eax | mov ax, cx REAL_DST_DTYPE is 32
// xor bh, bh | mov bl, cl REAL_DST_DTYPE is 16
// Extending of the 32-bit register to 64 bits is performed automatically
// based on the modifying_r32_spoils_r64 flag.
// REAL_SRC_DTYPE is the size that will be used in the SRC operand by the
// insn. It can be less than the operand size. For example:
// ARM: AND W8, W8, #0xFF will use 8 bits of X8,
// PC : cwde will use 16 bits of rax.
bool set_moved(
const op_t &dst,
const op_t &src,
tracked_regs_t &_regs,
op_dtype_t real_dst_dtype = dt_void,
op_dtype_t real_src_dtype = dt_void) const
{
return set_moved_jpt(this, dst, src, _regs, real_dst_dtype, real_src_dtype);
}
// calculate state of registers before a conditional jump <ea> as the
// combination of states of each branch
void combine_regs(
tracked_regs_t *dst,
const tracked_regs_t &src,
ea_t ea)
{
combine_regs_jpt(this, dst, src, ea);
}
protected:
bool match_tree();
bool follow_tree(ea_t ea, int n);
bool same_value_impl(const op_t &op, int r_i);
inline bool equal_ops_dtype(const op_t &op, const op_t &reg) const;
static inline bool is_narrower(op_dtype_t dt1, op_dtype_t dt2);
enum
{
dt_7bit = 255,
dt_6bit = 254,
dt_5bit = 253,
dt_4bit = 252,
dt_3bit = 251,
dt_2bit = 250,
};
static inline int get_dtype_nbits(op_dtype_t dtype);
// helper for check_spoiled()
// TODO introduce new virtual methods spoils() and spoils_flags() and
// replace check_spoiled() by non-virtual method
inline void check_spoiled_not_reg(
tracked_regs_t *_regs,
uint maxop = UA_MAXOP) const;
DECLARE_JUMP_PATTERN_HELPERS(friend)
};
//----------------------------------------------------------------------
// kinds of jump tables
enum { JT_NONE = 0, JT_SWITCH, JT_CALL };
// It returns a nonzero JT_... kind if it found a jump pattern. This kind is
// passed to the check_table() function.
typedef int is_pattern_t(switch_info_t *si, const insn_t &insn, procmod_t *procmod);
// It returns a refined kind. For example, JT_NONE if the found jump pattern
// is not a switch, or JT_CALL if it is a call of a func from an array
typedef int table_checker_t(
switch_info_t *si,
ea_t jump_ea,
int is_pattern_res,
procmod_t *pm);
// check a flat 32/16/8 bit jump table -- the most common case
idaman int ida_export check_flat_jump_table(
switch_info_t *si,
ea_t jump_ea,
int is_pattern_res = JT_SWITCH);
// This function finds a switch. It calls functions from the PATTERNS
// array in turn until the first one returns a nonzero value.
// If a suitable pattern is found, it calls check_table() for the final
// check, passing a nonzero result code of the 'is_pattern_t' function.
// If the CHECK_TABLE parameter is NULL then check_flat_jump_table() is
// called.
// NAME is used for a debug output.
// It returns 'false' if INSN is not a switch or it is a call of a func from
// an array. In the latter case it defines this array.
idaman bool ida_export check_for_table_jump(
switch_info_t *si,
const insn_t &insn,
is_pattern_t *const patterns[],
size_t qty,
table_checker_t *check_table = NULL,
const char *name = NULL);
//----------------------------------------------------------------------
// sometimes the size of the jump table is misdetected
// check if any of the would-be targets point into the table
// and if so, truncate it
// if 'ignore_refs' is false, also stop at first data reference
idaman void ida_export trim_jtable(
switch_info_t *si,
ea_t jump_ea,
bool ignore_refs = false);
//----------------------------------------------------------------------
// this function find the size of the jump table for indirect switches
// (indirect switches have the values table which contains indexes into
// the jump table)
// in: si->ncases has the size of the values table
// out: si->jcases is initialized
idaman bool ida_export find_jtable_size(switch_info_t *si);
//----------------------------------------------------------------------
// get default jump address from the jump table.
// This method can be used only for a sparse nonindirect switch with default
// case in the jump table.
idaman ea_t ida_export find_defjump_from_table(
ea_t jump_ea,
const switch_info_t &si);
//----------------------------------------------------------------------
// iterate instructions in the backward execution flow
//lint -esym(1512,backward_flow_iterator_t*) destructor is not virtual
template<class State,class Ctrl>
// State: default constructor, operator=
// Ctrl: combine_regs(State *, const State& ,ea_t)
// process_delay_slot(ea_t &/*ea*/, bool /*branch*/)
struct backward_flow_iterator_t
{
public:
ea_t cur_ea; // current address
State &regs; // current state of the tracked registers
Ctrl &ctrl; // to combine state
bool only_near; // should we follow only the linear flow?
uint max_insn_cnt;
protected:
//lint --e{958} padding is required
func_t *pfn; // to check bounds
const segment_t *seg;
ea_t start_ea;
ea_t cur_end; // end of current basic block
uint insn_cnt;
// visited basic blocks:
// key_type - start of the block, mapped_type - end of the block;
typedef std::map<ea_t, ea_t> visited_t;
visited_t visited;
// waiting basic blocks:
// key_type - end of the block, mapped_type - state at the end;
struct state_t
{
State regs;
uint insn_cnt;
state_t() : regs(), insn_cnt(UINT_MAX) {}
};
typedef std::map<ea_t, state_t> waiting_t;
waiting_t waiting;
public:
backward_flow_iterator_t(
ea_t start_ea_,
State &start_regs,
Ctrl &ctrl_,
bool only_near_,
uint max_insn_cnt_ = 0)
: cur_ea(start_ea_),
regs(start_regs),
ctrl(ctrl_),
only_near(only_near_),
max_insn_cnt(max_insn_cnt_),
pfn(NULL),
seg(NULL),
start_ea(start_ea_),
cur_end(BADADDR),
insn_cnt(0),
visited(),
waiting()
{
// to check bounds
pfn = get_func(start_ea);
if ( pfn == NULL )
{
seg = getseg(start_ea);
QASSERT(10183, seg != NULL);
}
}
// fl_U : no previous instruction (start of a function or a cycle,
// or non linear flow if ONLY_NEAR is true),
// fl_F : got previous instruction by linear flow,
// fl_JF: got previous instruction by jump;
inline cref_t prev_insn();
// stop iterating the current basic block, switch to the lowest waiting
// block
inline cref_t skip_block();
inline ea_t get_cur_end() const
{
return cur_end == BADADDR ? cur_ea : cur_end;
}
protected:
// find visited basic block containing the address
// it returns the pointer to the address of the block end or NULL
inline ea_t *find_visited(ea_t ea);
// get the lowest to start_ea waiting block
inline cref_t get_waiting();
// combine insn counter - count the shortest path
static inline void combine_insn_cnt(uint *dst, uint src)
{
if ( src < *dst )
*dst = src;
}
bool check_bounds() const
{
if ( pfn != NULL )
return func_contains(pfn, cur_ea);
return seg->contains(cur_ea);
}
};
//-------------------------------------------------------------------------
// simple backward flow iterator
struct no_regs_t {};
struct simple_bfi_t
: public backward_flow_iterator_t<no_regs_t, simple_bfi_t>
{
typedef backward_flow_iterator_t<no_regs_t, simple_bfi_t> base_t;
protected:
no_regs_t regs_;
public:
simple_bfi_t(ea_t ea)
: base_t(ea, regs_, *this, false) {}
static void combine_regs(no_regs_t *, const no_regs_t &, ea_t) {}
static void process_delay_slot(ea_t &, bool) {}
};
//======================================================================
// inline implementation
//----------------------------------------------------------------------
//-V:jump_pattern_t:730 not all members of a class are initialized inside the constructor
inline jump_pattern_t::jump_pattern_t(
switch_info_t *_si,
const char (*_depends)[4],
int last_reg)
: modifying_r32_spoils_r64(true),
si(_si),
non_spoiled_reg(-1),
in_linear_flow(false),
depends(_depends),
regs()
{
if ( si != NULL )
si->clear();
regs.resize(last_reg + 1);
}
//----------------------------------------------------------------------
inline bool jump_pattern_t::equal_ops_dtype(
const op_t &op,
const op_t &reg) const
{
if ( !equal_ops(op, reg) )
return false;
// operand should be wider than a tracked register
// e.g. after 'cmp cl, imm' we cannot use cx
if ( !is_narrower(op.dtype, reg.dtype) )
return true;
// we believe that dword is widened to qword
if ( modifying_r32_spoils_r64 && op.dtype == dt_dword )
return true;
// try to extend
if ( !is_narrower(extend_dtype(op), reg.dtype) )
return true;
return false;
}
//----------------------------------------------------------------------
// return true if size1 is narrow than size2
inline bool jump_pattern_t::is_narrower(op_dtype_t dt1, op_dtype_t dt2)
{
if ( dt1 < dt_2bit )
return dt2 < dt_2bit && dt1 < dt2;
else
return dt2 < dt_2bit || dt1 < dt2;
}
//----------------------------------------------------------------------
inline int jump_pattern_t::get_dtype_nbits(op_dtype_t dtype)
{
switch ( dtype )
{
case dt_byte: return 8;
case dt_word: return 16;
case dt_dword: return 32;
case dt_qword: return 64;
case dt_7bit: return 7;
case dt_6bit: return 6;
case dt_5bit: return 5;
case dt_4bit: return 4;
case dt_3bit: return 3;
case dt_2bit: return 2;
default: return -1;
}
}
//----------------------------------------------------------------------
inline void jump_pattern_t::check_spoiled_not_reg(
tracked_regs_t *_regs,
uint maxop) const
{
uint32 feature = insn.get_canon_feature(PH);
if ( feature == 0 )
return;
for ( uint i = 0; i < maxop; ++i )
{
if ( has_cf_chg(feature, i)
&& insn.ops[i].type != o_void
&& insn.ops[i].type != o_reg )
{
set_spoiled(_regs, insn.ops[i]);
}
}
}
//----------------------------------------------------------------------
inline void jump_pattern_t::track(int reg, int r_i, op_dtype_t dtype)
{
regs[r_i].type = o_reg;
regs[r_i].reg = reg;
regs[r_i].dtype = dtype;
}
inline void jump_pattern_t::trackop(const op_t &op, int r_i)
{
regs[r_i] = op;
}
//----------------------------------------------------------------------
inline bool jump_pattern_t::is_equal(int reg, int r_i, op_dtype_t dtype)
{
op_t op;
op.type = o_reg;
op.reg = reg;
op.dtype = dtype;
return is_equal(op, r_i);
}
inline bool jump_pattern_t::is_equal(const op_t &op, int r_i)
{
if ( regs[r_i].type == o_void )
{
// there is no reason to continue match
stop_matching = true;
return false;
}
return equal_ops_dtype(op, regs[r_i]);
}
//----------------------------------------------------------------------
inline bool jump_pattern_t::same_value(const op_t &op, int r_i)
{
return same_value_jpt(this, op, r_i);
}
//----------------------------------------------------------------------
inline void jump_pattern_t::set_spoiled(tracked_regs_t *__regs)
{
tracked_regs_t &_regs = *__regs;
// spoil all registers
for ( size_t i = 0; i < _regs.size(); ++i )
_regs[i].type = o_void;
}
inline void jump_pattern_t::set_spoiled(tracked_regs_t *__regs, const op_t &op) const
{
tracked_regs_t &_regs = *__regs;
for ( size_t i = 0; i < _regs.size(); ++i )
if ( equal_ops(_regs[i], op) )
_regs[i].type = o_void; // spoil register
}
//----------------------------------------------------------------------
// find the previous instruction in code flow
// take into account branches and potential delay slots
template<class State,class Ctrl>
inline cref_t backward_flow_iterator_t<State,Ctrl>::prev_insn()
{
size_t refcnt = 0;
// check visited basic block
ea_t *visited_end = find_visited(cur_ea);
if ( visited_end == NULL )
{
// analyze references to the current address
flags_t F = get_flags(cur_ea);
if ( is_flow(F) )
++refcnt;
if ( has_xref(F) && !is_func(F) ) // do not count jumps to function
{
xrefblk_t xb;
for ( bool ok = xb.first_to(cur_ea, XREF_FAR);
ok && xb.iscode;
ok = xb.next_to() )
{
// count only xrefs from jumps
if ( xb.type == fl_JF || xb.type == fl_JN )
{
if ( only_near )
{
if ( refcnt > 0 )
return fl_U;
// do not consider the flow through another switch as linear
if ( (get_flags(xb.from) & FF_JUMP) != 0 )
return fl_U;
}
++refcnt;
ea_t ea = xb.from;
ctrl.process_delay_slot(ea, true);
// ignore jumps from already visited blocks
if ( find_visited(ea) != NULL )
continue;
// add basic block to the waiting set (combine state of the
// tracked registers at the jump source)
state_t &src_state = waiting[ea];
ctrl.combine_regs(&src_state.regs, regs, ea);
combine_insn_cnt(&src_state.insn_cnt, insn_cnt);
}
}
}
if ( cur_end == BADADDR )
cur_end = cur_ea;
// try ordinary flow
if ( is_flow(F) )
{
ea_t prev_ea = prev_not_tail(cur_ea);
if ( prev_ea != BADADDR )
{
cur_ea = prev_ea;
if ( check_bounds()
&& (max_insn_cnt == 0 || insn_cnt < max_insn_cnt) )
{
++insn_cnt;
// remove reached waiting basic block
typename waiting_t::iterator w = waiting.find(cur_ea);
if ( w != waiting.end() )
{
ctrl.combine_regs(&regs, w->second.regs, cur_ea);
combine_insn_cnt(&insn_cnt, w->second.insn_cnt);
waiting.erase(w);
}
else
{
ctrl.process_delay_slot(cur_ea, false);
}
return fl_F;
}
}
// choose another branch
}
// save block [cur_ea, cur_end] as visited
visited[cur_ea] = cur_end;
}
else if ( cur_end != BADADDR )
{
// reach visited basic block => extend it
*visited_end = cur_end;
}
// get the lowest waiting block
cref_t ret = get_waiting();
// consider one xref as a linear flow
if ( ret == fl_JF && refcnt == 1 && waiting.empty() )
ret = fl_F;
return ret;
}
//----------------------------------------------------------------------
template<class State,class Ctrl>
inline cref_t backward_flow_iterator_t<State,Ctrl>::skip_block()
{
// check visited basic block
ea_t *visited_end = find_visited(cur_ea);
if ( visited_end == NULL )
{
if ( cur_end == BADADDR )
cur_end = cur_ea;
// save block [cur_ea, cur_end] as visited
visited[cur_ea] = cur_end;
}
else if ( cur_end != BADADDR )
{
// reach visited basic block => extend it
*visited_end = cur_end;
}
// get the lowest waiting block
return get_waiting();
}
//----------------------------------------------------------------------
template<class State,class Ctrl>
inline cref_t backward_flow_iterator_t<State,Ctrl>::get_waiting()
{
while ( !waiting.empty() )
{
typename waiting_t::iterator w = waiting.upper_bound(start_ea);
if ( w != waiting.begin() )
--w;
cur_ea = w->first;
if ( check_bounds() )
{
cur_end = BADADDR;
regs = w->second.regs;
insn_cnt = w->second.insn_cnt;
waiting.erase(w);
return fl_JF;
}
waiting.erase(w);
}
return fl_U;
}
//----------------------------------------------------------------------
template<class State,class Ctrl>
inline ea_t *backward_flow_iterator_t<State,Ctrl>::find_visited(ea_t ea)
{
visited_t::iterator v = visited.upper_bound(ea);
// assert: v == visited.end() || v->first > ea
if ( v == visited.begin() )
return NULL;
--v;
// assert: v->first <= ea
if ( ea > v->second )
return NULL;
return &v->second;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,353 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef LEX_HPP
#define LEX_HPP
/*! \file lex.hpp
\brief Tools for parsing C-like input
Functions in this file use objects of opaque type lexer_t.
To create a lexer_t instance, use create_lexer().
*/
typedef ushort lxtype; ///< see \ref lx_
/// \defgroup lx_ Parser token types
/// See token_t::type
/// \note All separators have their ASCII codes as lxtype
//@{
const lxtype
lx_end = 1, ///< no more tokens
lx_ident = 2, ///< ident
lx_number = 3, ///< long constant
lx_string = 4, ///< string constant (token_t.chr != 0 => unicode string)
lx_char = 5, ///< char constant
lx_typename = 6, ///< user-defined type
lx_float = 7, ///< IEEE floating point constant
lx_int64 = 8, ///< int64 constant
lx_key = 128; ///< keywords start. All keys are lx_key + keynum. \n
///< Two-char separators are: (c1 + (c2 << 8)). \n
///< Three-char separators:
///< - "<<=" = ('<' + ('<'<<8)) + '='
///< - ">>=" = ('>' + ('>'<<8)) + '='
//@}
/// Parser token
struct token_t
{
qstring str; ///< idents & strings
lxtype type; ///< see \ref lx_
sval_t num; ///< long & char constants
union
{
bool unicode; ///< (::lx_string: != 0 => unicode string)
bool is_unsigned; ///< (::lx_number, ::lx_int64: != 0 => unsigned value)
};
union
{
ushort fnum[6]; ///< floating point constant
int64 i64; ///< ::lx_int64
};
token_t() : type(0), num(0), unicode(false)
{
// init maximum member of union
memset(&fnum[0], 0x00, sizeof(fnum));
}
};
DECLARE_TYPE_AS_MOVABLE(token_t);
class lexer_t; // lexical analyzer, opaque structure
/// Preprocessor callback for unknown tokens.
/// Will be called when preprocessor calculates the value of #if expression.
typedef error_t lx_resolver_t(lexer_t *lx, void *ud, token_t *curtok, sval_t *res);
#ifdef _MSC_VER
#pragma warning(push)
// Conversion from 'type1 ' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
// We want this sign-extension to happen, since it comes mostly from HANDLEs.
// (see https://msdn.microsoft.com/en-us/library/ms235307.aspx )
#pragma warning(disable:4826)
#endif
/// Preprocessor cast
struct cast_t
{
bool is_unsigned;
int size;
cast_t()
{
reset();
}
void reset(void)
{
is_unsigned = false;
size = 0;
}
};
struct lex_value_t
{
bool is_unsigned;
union
{
int64 val;
uint64 uval;
};
lex_value_t()
{
reset();
}
void set(const lex_value_t &v)
{
set_val(v.val, v.is_unsigned);
}
void reset(void)
{
set_val(0, true);
}
void set_val(int64 v, bool _is_unsigned)
{
is_unsigned = _is_unsigned;
val = v;
}
uint64 get_uval(void) const
{
return val;
}
int64 get_val(void) const
{
return val;
}
bool is_zero(void) const
{
return get_val() == 0;
}
void perform_cast(const cast_t &cast);
void unary_minus(const lex_value_t &v);
void unary_plus(const lex_value_t &v);
void unary_not(const lex_value_t &v);
void bitwise_not(const lex_value_t &v);
void mul(const lex_value_t &v);
void div(const lex_value_t &v);
void mod(const lex_value_t &v);
void add(const lex_value_t &v);
void sub(const lex_value_t &v);
void shift_right(const lex_value_t &v);
void shift_left(const lex_value_t &v);
void bitwise_and(const lex_value_t &v);
void bitwise_xor(const lex_value_t &v);
void bitwise_or(const lex_value_t &v);
void logical_and(const lex_value_t &v);
void logical_or(const lex_value_t &v);
void cmpge(const lex_value_t &v);
void cmple(const lex_value_t &v);
void cmplt(const lex_value_t &v);
void cmpgt(const lex_value_t &v);
void cmpeq(const lex_value_t &v);
void cmpneq(const lex_value_t &v);
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
/// Preprocessor callbacks for casts.
/// Will be called when preprocessor calculates the value of #if expression.
typedef error_t lx_parse_cast_t(lexer_t *lx, cast_t *cast, token_t *ct);
/// Preprocessor callback.
/// It will be called for each input line.
/// \return an error code (0-ok)
typedef int idaapi lx_preprocessor_cb(void *ud, const char *fname, int nl, const char *line);
/// Callback for #pragma directives.
/// \return an error code (0-ok)
typedef int idaapi lx_pragma_cb(void *ud, const char *line);
/// Callback for #warning directives.
/// \return an error code (0-ok)
typedef int idaapi lx_warning_cb(void *ud, const char *line);
/// Callback for #define directives
/// \return an error code (0-ok)
typedef int idaapi lx_macro_cb(
void *ud,
const char *name,
const char *body,
int nargs,
bool isfunc,
bool is_new_macro);
/// Callback for #undef directives
/// \return an error code (0-ok)
typedef int idaapi lx_undef_cb(void *ud, const char *name);
/// Create new lexical analyzer and set its keyword table.
/// If keys==NULL, then set the default C keyword table
idaman lexer_t *ida_export create_lexer(
const char *const *keys,
size_t size,
void *ud=NULL);
/// Destroy a lexical analyzer
idaman void ida_export destroy_lexer(lexer_t *lx);
/// Define a macro
idaman error_t ida_export lex_define_macro(
lexer_t *lx,
const char *macro,
const char *body,
int nargs=0,
bool isfunc=false);
/// Undefine a macro
idaman void ida_export lex_undefine_macro(
lexer_t *lx,
const char *macro);
/// Set lexer options.
/// \param options \ref LXOPT_
/// \return the old options
idaman int ida_export lex_set_options(lexer_t *lx, int options);
/// \defgroup LXOPT_ Lexer options
/// Passed as 'options' parameter to lex_set_options().
/// By default all options are on.
//@{
#define LXOPT_PARSE_FLOATS 0x0001 ///< enable floating point constants
#define LXOPT_REQ_SEPARATOR 0x0002 ///< require a separator between a number and an ident or a character/string constant or dot
#define LXOPT_NOCASE_FILES 0x0004 ///< case-insensitive file search
#define LXOPT_C99_CONSTANTS 0x0008 ///< the size and sign of constants depend on the value itself and the 'U', 'L', and 'LL'
///< modifier suffixes. otherwise the constant is always considered as signed and the size
///< depends only on the number of bytes in the value
//@}
/// Get next token
/// \param p_lnnum line number where the token starts
idaman error_t ida_export lex_get_token(lexer_t *lx, token_t *t);
idaman error_t ida_export lex_get_token2(lexer_t *lx, token_t *t, int32 *p_lnnum);
/// Enumerate all macros.
/// Do so until 'cb' returns non-zero.
idaman int ida_export lex_enum_macros(
const lexer_t *lx,
int idaapi cb(const char *name, const char *body, int nargs, bool isfunc, void *ud),
void *ud=NULL);
/// Debug: get text representation of token
idaman const char *ida_export lex_print_token(qstring *buf, const token_t *t);
//-------------------------------------------------------------------------
/// \name String oriented functions
//@{
/// Set the input line and the macro table.
/// if macros==NULL, the macro table will not be changed.
idaman error_t ida_export lex_init_string(
lexer_t *lx,
const char *line,
void *macros=NULL);
//@}
//-------------------------------------------------------------------------
/// \name File oriented functions
//@{
/// Initialization: file may be NULL.
/// Also see lex_term_file().
idaman error_t ida_export lex_init_file(lexer_t *lx, const char *file);
/// Error handling.
/// if level > 0, then return information about the enclosing file which
/// included the current one.
idaman const char *ida_export lex_get_file_line(
lexer_t *lx,
int32 *linenum,
const char **lineptr,
int level=0);
/// Termination: also see lex_init_file()
idaman void ida_export lex_term_file(lexer_t *lx, bool del_macros);
//@}
//-------------------------------------------------------------------------
/// \name Token stack
//@{
typedef qstack<token_t> tokenstack_t; ///< see get_token(), unget_token()
/// Retrieve token from a stack or lexer.
/// If buf is not empty then get the token on top of the stack.
/// If buf is empty then gen the next token from the lexer.
/// \return success
inline bool get_token(token_t *t, lexer_t *lx, tokenstack_t &buf)
{
if ( !buf.empty() )
*t = buf.pop();
else if ( lex_get_token(lx, t) != eOk )
return false;
return true;
}
/// Push a token back onto the token stack
inline void unget_token(const token_t &t, tokenstack_t &buf)
{
buf.push(t);
}
//@}
#endif // LEX_HPP

View File

@@ -1,595 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _LINES_HPP
#define _LINES_HPP
#include <ida.hpp>
/*! \file lines.hpp
\brief High level functions that deal with the generation
of the disassembled text lines.
This file also contains definitions for the syntax highlighting.
Finally there are functions that deal with anterior/posterior
user-defined lines.
*/
struct range_t;
//---------------------------------------------------------------------------
// C O L O R D E F I N I T I O N S
//---------------------------------------------------------------------------
/// \defgroup color_def Color definitions
///
/// Here we describe the structure of embedded escape sequences used to
/// implement syntax highlighting.
///
/// IDP module should insert appropriate escape characters into the
/// output lines as necessary. This approach allows to create an IDP
/// module without the syntax highlighting too - just don't use
/// escape sequences.
///
/// A typical color sequence looks like this:
///
/// #COLOR_ON COLOR_xxx text #COLOR_OFF COLOR_xxx
///
/// The first 2 items turn color 'xxx' on, then the text follows,
/// and the color is turned off by two last items.
///
/// For the convenience we've defined a set of macro definitions
/// and functions to deal with colors.
//@{
/// \defgroup color_esc Color escape characters
/// Initiate/Terminate a color tag
//@{
#define COLOR_ON '\1' ///< Escape character (ON).
///< Followed by a color code (::color_t).
#define COLOR_OFF '\2' ///< Escape character (OFF).
///< Followed by a color code (::color_t).
#define COLOR_ESC '\3' ///< Escape character (Quote next character).
///< This is needed to output '\1' and '\2'
///< characters.
#define COLOR_INV '\4' ///< Escape character (Inverse foreground and background colors).
///< This escape character has no corresponding #COLOR_OFF.
///< Its action continues until the next #COLOR_INV or end of line.
#define SCOLOR_ON "\1" ///< Escape character (ON)
#define SCOLOR_OFF "\2" ///< Escape character (OFF)
#define SCOLOR_ESC "\3" ///< Escape character (Quote next character)
#define SCOLOR_INV "\4" ///< Escape character (Inverse colors)
/// Is the given char a color escape character?
inline THREAD_SAFE bool requires_color_esc(char c) { return c >= COLOR_ON && c <= COLOR_INV; }
//@}
typedef uchar color_t; ///< color tag - see \ref COLOR_
/// \defgroup COLOR_ Color tags
/// Specify a color for a syntax item
//@{
const color_t
COLOR_DEFAULT = 0x01, ///< Default
COLOR_REGCMT = 0x02, ///< Regular comment
COLOR_RPTCMT = 0x03, ///< Repeatable comment (comment defined somewhere else)
COLOR_AUTOCMT = 0x04, ///< Automatic comment
COLOR_INSN = 0x05, ///< Instruction
COLOR_DATNAME = 0x06, ///< Dummy Data Name
COLOR_DNAME = 0x07, ///< Regular Data Name
COLOR_DEMNAME = 0x08, ///< Demangled Name
COLOR_SYMBOL = 0x09, ///< Punctuation
COLOR_CHAR = 0x0A, ///< Char constant in instruction
COLOR_STRING = 0x0B, ///< String constant in instruction
COLOR_NUMBER = 0x0C, ///< Numeric constant in instruction
COLOR_VOIDOP = 0x0D, ///< Void operand
COLOR_CREF = 0x0E, ///< Code reference
COLOR_DREF = 0x0F, ///< Data reference
COLOR_CREFTAIL = 0x10, ///< Code reference to tail byte
COLOR_DREFTAIL = 0x11, ///< Data reference to tail byte
COLOR_ERROR = 0x12, ///< Error or problem
COLOR_PREFIX = 0x13, ///< Line prefix
COLOR_BINPREF = 0x14, ///< Binary line prefix bytes
COLOR_EXTRA = 0x15, ///< Extra line
COLOR_ALTOP = 0x16, ///< Alternative operand
COLOR_HIDNAME = 0x17, ///< Hidden name
COLOR_LIBNAME = 0x18, ///< Library function name
COLOR_LOCNAME = 0x19, ///< Local variable name
COLOR_CODNAME = 0x1A, ///< Dummy code name
COLOR_ASMDIR = 0x1B, ///< Assembler directive
COLOR_MACRO = 0x1C, ///< Macro
COLOR_DSTR = 0x1D, ///< String constant in data directive
COLOR_DCHAR = 0x1E, ///< Char constant in data directive
COLOR_DNUM = 0x1F, ///< Numeric constant in data directive
COLOR_KEYWORD = 0x20, ///< Keywords
COLOR_REG = 0x21, ///< Register name
COLOR_IMPNAME = 0x22, ///< Imported name
COLOR_SEGNAME = 0x23, ///< Segment name
COLOR_UNKNAME = 0x24, ///< Dummy unknown name
COLOR_CNAME = 0x25, ///< Regular code name
COLOR_UNAME = 0x26, ///< Regular unknown name
COLOR_COLLAPSED= 0x27, ///< Collapsed line
COLOR_FG_MAX = 0x28, ///< Max color number
// Fictive colors
COLOR_ADDR = COLOR_FG_MAX, ///< hidden address marks.
///< the address is represented as 8digit
///< hex number: 01234567.
///< it doesn't have #COLOR_OFF pair.
///< NB: for 64-bit IDA, the address is 16digit.
COLOR_OPND1 = COLOR_ADDR+1, ///< Instruction operand 1
COLOR_OPND2 = COLOR_ADDR+2, ///< Instruction operand 2
COLOR_OPND3 = COLOR_ADDR+3, ///< Instruction operand 3
COLOR_OPND4 = COLOR_ADDR+4, ///< Instruction operand 4
COLOR_OPND5 = COLOR_ADDR+5, ///< Instruction operand 5
COLOR_OPND6 = COLOR_ADDR+6, ///< Instruction operand 6
COLOR_OPND7 = COLOR_ADDR+7, ///< Instruction operand 7
COLOR_OPND8 = COLOR_ADDR+8, ///< Instruction operand 8
COLOR_RESERVED1= COLOR_ADDR+11,///< This tag is reserved for internal IDA use
COLOR_LUMINA = COLOR_ADDR+12;///< Lumina-related, only for the navigation band
//@}
/// Size of a tagged address (see ::COLOR_ADDR)
#define COLOR_ADDR_SIZE (sizeof(ea_t)*2)
/// \defgroup SCOLOR_ Color string constants
/// These definitions are used with the #COLSTR macro
//@{
#define SCOLOR_DEFAULT "\x01" ///< Default
#define SCOLOR_REGCMT "\x02" ///< Regular comment
#define SCOLOR_RPTCMT "\x03" ///< Repeatable comment (defined not here)
#define SCOLOR_AUTOCMT "\x04" ///< Automatic comment
#define SCOLOR_INSN "\x05" ///< Instruction
#define SCOLOR_DATNAME "\x06" ///< Dummy Data Name
#define SCOLOR_DNAME "\x07" ///< Regular Data Name
#define SCOLOR_DEMNAME "\x08" ///< Demangled Name
#define SCOLOR_SYMBOL "\x09" ///< Punctuation
#define SCOLOR_CHAR "\x0A" ///< Char constant in instruction
#define SCOLOR_STRING "\x0B" ///< String constant in instruction
#define SCOLOR_NUMBER "\x0C" ///< Numeric constant in instruction
#define SCOLOR_VOIDOP "\x0D" ///< Void operand
#define SCOLOR_CREF "\x0E" ///< Code reference
#define SCOLOR_DREF "\x0F" ///< Data reference
#define SCOLOR_CREFTAIL "\x10" ///< Code reference to tail byte
#define SCOLOR_DREFTAIL "\x11" ///< Data reference to tail byte
#define SCOLOR_ERROR "\x12" ///< Error or problem
#define SCOLOR_PREFIX "\x13" ///< Line prefix
#define SCOLOR_BINPREF "\x14" ///< Binary line prefix bytes
#define SCOLOR_EXTRA "\x15" ///< Extra line
#define SCOLOR_ALTOP "\x16" ///< Alternative operand
#define SCOLOR_HIDNAME "\x17" ///< Hidden name
#define SCOLOR_LIBNAME "\x18" ///< Library function name
#define SCOLOR_LOCNAME "\x19" ///< Local variable name
#define SCOLOR_CODNAME "\x1A" ///< Dummy code name
#define SCOLOR_ASMDIR "\x1B" ///< Assembler directive
#define SCOLOR_MACRO "\x1C" ///< Macro
#define SCOLOR_DSTR "\x1D" ///< String constant in data directive
#define SCOLOR_DCHAR "\x1E" ///< Char constant in data directive
#define SCOLOR_DNUM "\x1F" ///< Numeric constant in data directive
#define SCOLOR_KEYWORD "\x20" ///< Keywords
#define SCOLOR_REG "\x21" ///< Register name
#define SCOLOR_IMPNAME "\x22" ///< Imported name
#define SCOLOR_SEGNAME "\x23" ///< Segment name
#define SCOLOR_UNKNAME "\x24" ///< Dummy unknown name
#define SCOLOR_CNAME "\x25" ///< Regular code name
#define SCOLOR_UNAME "\x26" ///< Regular unknown name
#define SCOLOR_COLLAPSED "\x27" ///< Collapsed line
#define SCOLOR_ADDR "\x28" ///< Hidden address mark
//@}
//----------------- Line prefix colors --------------------------------------
/// \defgroup COLOR_PFX Line prefix colors
/// Note: line prefix colors are not used in processor modules
//@{
#define COLOR_DEFAULT 0x01 ///< Default
#define COLOR_SELECTED 0x02 ///< Selected
#define COLOR_LIBFUNC 0x03 ///< Library function
#define COLOR_REGFUNC 0x04 ///< Regular function
#define COLOR_CODE 0x05 ///< Single instruction
#define COLOR_DATA 0x06 ///< Data bytes
#define COLOR_UNKNOWN 0x07 ///< Unexplored byte
#define COLOR_EXTERN 0x08 ///< External name definition segment
#define COLOR_CURITEM 0x09 ///< Current item
#define COLOR_CURLINE 0x0A ///< Current line
#define COLOR_HIDLINE 0x0B ///< Hidden line
#define COLOR_LUMFUNC 0x0C ///< Lumina function
#define COLOR_BG_MAX 0x0D ///< Max color number
#define PALETTE_SIZE (COLOR_FG_MAX+COLOR_BG_MAX)
//@}
/// This macro is used to build colored string constants (e.g. for format strings)
/// \param str string literal to surround with color tags
/// \param tag one of SCOLOR_xxx constants
#define COLSTR(str,tag) SCOLOR_ON tag str SCOLOR_OFF tag
//------------------------------------------------------------------------
/// \defgroup color_conv Convenience functions
/// Higher level convenience functions are defined in ua.hpp.
/// Please use the following functions only if functions from ua.hpp
/// are not useful in your case.
//@{
/// Insert an address mark into a string.
/// \param buf pointer to the output buffer; the tag will be appended or inserted into it
/// \param ea address to include
/// \param ins if true, the tag will be inserted at the beginning of the buffer
idaman THREAD_SAFE void ida_export tag_addr(qstring *buf, ea_t ea, bool ins=false);
/// Move pointer to a 'line' to 'cnt' positions right.
/// Take into account escape sequences.
/// \param line pointer to string
/// \param cnt number of positions to move right
/// \return moved pointer
idaman THREAD_SAFE const char *ida_export tag_advance(const char *line, int cnt);
/// Move the pointer past all color codes.
/// \param line can't be NULL
/// \return moved pointer, can't be NULL
idaman THREAD_SAFE const char *ida_export tag_skipcodes(const char *line);
/// Skip one color code.
/// This function should be used if you are interested in color codes
/// and want to analyze all of them.
/// Otherwise tag_skipcodes() function is better since it will skip all colors at once.
/// This function will skip the current color code if there is one.
/// If the current symbol is not a color code, it will return the input.
/// \return moved pointer
idaman THREAD_SAFE const char *ida_export tag_skipcode(const char *line);
/// Calculate length of a colored string
/// This function computes the length in unicode codepoints of a line
/// \return the number of codepoints in the line, or -1 on error
idaman THREAD_SAFE ssize_t ida_export tag_strlen(const char *line);
/// Remove color escape sequences from a string.
/// \param buf output buffer with the string, cannot be NULL.
/// \param str input string, cannot be NULL.
/// \param init_level used to verify that COLOR_ON and COLOR_OFF tags are balanced
/// \return length of resulting string, -1 if error
idaman THREAD_SAFE ssize_t ida_export tag_remove(qstring *buf, const char *str, int init_level=0);
inline THREAD_SAFE ssize_t idaapi tag_remove(qstring *buf, const qstring &str, int init_level=0)
{
return tag_remove(buf, str.c_str(), init_level);
}
inline THREAD_SAFE ssize_t idaapi tag_remove(qstring *buf, int init_level=0)
{
if ( buf->empty() )
return 0;
return tag_remove(buf, buf->begin(), init_level);
}
//@} color_conv
//@} color_def
/// Get prefix color for line at 'ea'
/// \return \ref COLOR_PFX
idaman color_t ida_export calc_prefix_color(ea_t ea);
/// Get background color for line at 'ea'
/// \return RGB color
idaman bgcolor_t ida_export calc_bg_color(ea_t ea);
//------------------------------------------------------------------------
// S O U R C E F I L E S
//------------------------------------------------------------------------
/// \name Source files
/// IDA can keep information about source files used to create the program.
/// Each source file is represented by a range of addresses.
/// A source file may contain several address ranges.
//@{
/// Mark a range of address as belonging to a source file.
/// An address range may belong only to one source file.
/// A source file may be represented by several address ranges.
/// \param ea1 linear address of start of the address range
/// \param ea2 linear address of end of the address range (excluded)
/// \param filename name of source file.
/// \return success
idaman bool ida_export add_sourcefile(ea_t ea1, ea_t ea2, const char *filename);
/// Get name of source file occupying the given address.
/// \param ea linear address
/// \param bounds pointer to the output buffer with the address range
/// for the current file. May be NULL.
/// \return NULL if source file information is not found,
/// otherwise returns pointer to file name
idaman const char *ida_export get_sourcefile(ea_t ea, range_t *bounds=NULL);
/// Delete information about the source file.
/// \param ea linear address
/// \return success
idaman bool ida_export del_sourcefile(ea_t ea);
//@}
//------------------------------------------------------------------------
// G E N E R A T I O N O F D I S A S S E M B L E D T E X T
//------------------------------------------------------------------------
/// \name Generation of disassembled text
//@{
/// User-defined line-prefixes are displayed just after the autogenerated
/// line prefixes in the disassembly listing.
/// There is no need to call this function explicitly.
/// Use the user_defined_prefix_t class.
/// \param prefix_len prefixed length. if 0, then uninstall UDP
/// \param udp object to generate user-defined prefix
/// \param install true:install, false:uninstall
/// \param owner pointer to the plugin_t that owns UDP
/// if non-NULL, then the object will be uninstalled and destroyed
/// when the plugin gets unloaded
idaman bool ida_export install_user_defined_prefix(
size_t prefix_len,
struct user_defined_prefix_t *udp,
const void *owner);
/// Class to generate user-defined prefixes in the disassembly listing.
struct user_defined_prefix_t
{
/// Creating a user-defined prefix object installs it.
user_defined_prefix_t(size_t prefix_len, const void *owner)
{
install_user_defined_prefix(prefix_len, this, owner);
}
/// Destroying a user-defined prefix object uninstalls it.
virtual idaapi ~user_defined_prefix_t()
{
install_user_defined_prefix(0, this, nullptr);
}
// Get a user-defined prefix.
/// This callback must be overridden by the derived class.
/// \param out the output buffer
/// \param ea the current address
/// \param insn the current instruction. if the current item is not
/// an instruction, then insn.itype is zero.
/// \param indent see explanations for \ref gen_printf()
/// \param line the line to be generated.
/// the line usually contains color tags.
/// this argument can be examined to decide
/// whether to generate the prefix.
virtual void idaapi get_user_defined_prefix(
qstring *vout,
ea_t ea,
const class insn_t &insn,
int lnnum,
int indent,
const char *line) = 0;
};
//@}
//------------------------------------------------------------------------
// A N T E R I O R / P O S T E R I O R L I N E S
//------------------------------------------------------------------------
/// \name Anterior/Posterior lines
//@{
/// See higher level functions below
idaman AS_PRINTF(3, 0) bool ida_export vadd_extra_line(
ea_t ea,
int vel_flags, // see VEL_...
const char *format,
va_list va);
#define VEL_POST 0x01 // append posterior line
#define VEL_CMT 0x02 // append comment line
/// Add anterior/posterior non-comment line(s).
/// \param ea linear address
/// \param isprev do we add anterior lines? (0-no, posterior)
/// \param format printf() style format string. may contain \\n to denote new lines.
/// \return true if success
AS_PRINTF(3, 4) inline bool add_extra_line(ea_t ea, bool isprev, const char *format, ...)
{
va_list va;
va_start(va,format);
int vel_flags = (isprev ? 0 : VEL_POST);
bool ok = vadd_extra_line(ea, vel_flags, format, va);
va_end(va);
return ok;
}
/// Add anterior/posterior comment line(s).
/// \param ea linear address
/// \param isprev do we add anterior lines? (0-no, posterior)
/// \param format printf() style format string. may contain \\n to denote
/// new lines. The resulting string should not contain comment
/// characters (;), the kernel will add them automatically.
/// \return true if success
AS_PRINTF(3, 4) inline bool add_extra_cmt(ea_t ea, bool isprev, const char *format, ...)
{
va_list va;
va_start(va,format);
int vel_flags = (isprev ? 0 : VEL_POST) | VEL_CMT;
bool ok = vadd_extra_line(ea, vel_flags, format, va);
va_end(va);
return ok;
}
/// Add anterior comment line(s) at the start of program.
/// \param format printf() style format string. may contain \\n to denote
/// new lines. The resulting string should not contain comment
/// characters (;), the kernel will add them automatically.
/// \return true if success
AS_PRINTF(1, 2) inline bool add_pgm_cmt(const char *format, ...)
{
va_list va;
va_start(va,format);
bool ok = vadd_extra_line(inf_get_min_ea(), VEL_CMT, format, va);
va_end(va);
return ok;
}
//@}
///---------------------------------------------------------------------\cond
/// The following functions are used in kernel only:
// Generate disassembly (many lines) and put them into a buffer
// Returns number of generated lines
idaman int ida_export generate_disassembly(
qstrvec_t *out, // buffer to hold generated lines
int *lnnum, // number of "the most interesting" line
ea_t ea, // address to generate disassembly for
int maxsize, // maximum number of lines
bool as_stack); // Display undefined items as 2/4/8 bytes
// Generate one line of disassembly
// This function discards all "non-interesting" lines
// It is designed to generate one-line descriptions
// of addresses for lists, etc.
idaman bool ida_export generate_disasm_line(
qstring *buf, // output buffer
ea_t ea, // address to generate disassembly for
int flags=0);
#define GENDSM_FORCE_CODE (1 << 0) // generate a disassembly line as if
// there is an instruction at 'ea'
#define GENDSM_MULTI_LINE (1 << 1) // if the instruction consists of several lines,
// produce all of them (useful for parallel instructions)
#define GENDSM_REMOVE_TAGS (1 << 2) // remove tags from output buffer
/// Get length of the line prefix that was used for the last generated line
idaman int ida_export get_last_pfxlen(void);
// Get pointer to the sequence of characters denoting 'close comment'
// empty string means no comment (the current assembler has no open-comment close-comment pairs)
// This function uses ash.cmnt2
idaman const char *ida_export closing_comment(void);
// Every anterior/posterior line has its number.
// Anterior lines have numbers from E_PREV
// Posterior lines have numbers from E_NEXT
const int E_PREV = 1000;
const int E_NEXT = 2000;
idaman int ida_export get_first_free_extra_cmtidx(ea_t ea, int start);
idaman void ida_export update_extra_cmt(ea_t ea, int what, const char *str);
idaman void ida_export del_extra_cmt(ea_t ea, int what);
idaman ssize_t ida_export get_extra_cmt(qstring *buf, ea_t ea, int what);
idaman void ida_export delete_extra_cmts(ea_t ea, int what);
idaman ea_t ida_export align_down_to_stack(ea_t newea);
idaman ea_t ida_export align_up_to_stack(ea_t ea1, ea_t ea2=BADADDR);
// A helper class, to encode from UTF-8, -> into the target encoding.
// This is typically used when generating listings (or any kind of
// output file.)
struct encoder_t
{
// whether or not a message should be printed, letting the
// user know that some text couldn't be recoded properly
enum notify_recerr_t
{
nr_none,
nr_once,
};
virtual ~encoder_t() {}
virtual bool idaapi get_bom(bytevec_t *out) const = 0;
// returns true if conversion was entirely successful, false otherwise.
// codepoints that couldn't be converted, will be output as C
// literal-escaped UTF-8 sequences (e.g., "\xC3\xD9"), and if
// 'nr_once' was passed at creation-time, a one-time notification
// well be output in the messages window.
virtual bool idaapi encode(qstring *s) const = 0;
// encode()s the UTF-8 string composed by format + args, and
// returns true if all the resulting bytes could be written to
// the output file.
AS_PRINTF(3, 4) virtual bool idaapi print(FILE *out, const char *format, ...) const = 0;
// should a file be opened as binary, or should it rather be opened
// in text mode? This will have an importance in how '\n' characters
// are possibly converted into '\x0A\x0D' on windows, which is most
// inappropriate when output'ing e.g., UTF-16, UTF-32..
virtual bool idaapi requires_binary_mode() const = 0;
};
// Create the encoder with the given target encoding. If -1 is passed
// then the effective target encoding will be computed like so:
// if ( encidx < 0 )
// {
// encidx = get_outfile_encoding_idx();
// if ( encidx == STRENC_DEFAULT )
// encidx = get_default_encoding_idx(BPU_1B);
// }
idaman encoder_t *ida_export create_encoding_helper(
int encidx=-1,
encoder_t::notify_recerr_t nr=encoder_t::nr_once);
/// Callback functions to output lines:
//@{
typedef int idaapi html_header_cb_t(FILE *fp);
typedef int idaapi html_footer_cb_t(FILE *fp);
typedef int idaapi html_line_cb_t(
FILE *fp,
const qstring &line,
bgcolor_t prefix_color,
bgcolor_t bg_color);
#define gen_outline_t html_line_cb_t
//@}
///-------------------------------------------------------------------\endcond
#ifndef NO_OBSOLETE_FUNCS
idaman DEPRECATED void ida_export set_user_defined_prefix( // use install_user_defined_prefix()
size_t width,
void (idaapi *get_user_defined_prefix)(
qstring *buf,
ea_t ea,
int lnnum,
int indent,
const char *line));
#endif
#endif

View File

@@ -1,293 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _LLONG_HPP
#define _LLONG_HPP
//---------------------------------------------------------------------------
#if defined(_MSC_VER)
typedef unsigned __int64 ulonglong;
typedef __int64 longlong;
#elif defined(__GNUC__)
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif
//---------------------------------------------------------------------------
#ifdef __cplusplus
inline constexpr longlong make_longlong(uint32 ll,int32 hh) { return ll | (longlong(hh) << 32); }
inline constexpr ulonglong make_ulonglong(uint32 ll,int32 hh) { return ll | (ulonglong(hh) << 32); }
inline uint32 low(const ulonglong &x) { return uint32(x); }
inline uint32 high(const ulonglong &x) { return uint32(x>>32); }
inline uint32 low(const longlong &x) { return uint32(x); }
inline int32 high(const longlong &x) { return uint32(x>>32); }
#else
#define make_longlong(ll,hh) (ll | (longlong(hh) << 32))
#define make_ulonglong(ll,hh) (ll | (ulonglong(hh) << 32))
#endif
idaman THREAD_SAFE longlong ida_export llong_scan(
const char *buf,
int radix,
const char **end);
#ifndef swap64
idaman THREAD_SAFE ulonglong ida_export swap64(ulonglong);
# ifdef __cplusplus
inline longlong swap64(longlong x)
{
return longlong(swap64(ulonglong(x)));
}
# endif
#endif
//---------------------------------------------------------------------------
// 128 BIT NUMBERS
//---------------------------------------------------------------------------
#ifdef __HAS_INT128__
typedef unsigned __int128 uint128;
typedef __int128 int128;
inline int128 make_int128(ulonglong ll,longlong hh) { return ll | (int128(hh) << 64); }
inline uint128 make_uint128(ulonglong ll,ulonglong hh) { return ll | (uint128(hh) << 64); }
inline ulonglong low(const uint128 &x) { return ulonglong(x); }
inline ulonglong high(const uint128 &x) { return ulonglong(x>>64); }
inline ulonglong low(const int128 &x) { return ulonglong(x); }
inline longlong high(const int128 &x) { return ulonglong(x>>64); }
#else
#ifdef __cplusplus
//-V:uint128:730 not all members of a class are initialized inside the constructor
class uint128
{
ulonglong l;
ulonglong h;
friend class int128;
public:
uint128(void) {}
uint128(uint x) { l = x; h = 0; }
uint128(int x) { l = x; h = (x < 0)? -1 : 0; }
uint128(ulonglong x) { l = x; h = 0; }
uint128(longlong x) { l = x; h = (x < 0) ? -1 : 0; }
uint128(ulonglong ll, ulonglong hh) { l = ll; h = hh; }
friend ulonglong low (const uint128 &x) { return x.l; }
friend ulonglong high(const uint128 &x) { return x.h; }
friend uint128 operator+(const uint128 &x, const uint128 &y);
friend uint128 operator-(const uint128 &x, const uint128 &y);
friend uint128 operator/(const uint128 &x, const uint128 &y);
friend uint128 operator%(const uint128 &x, const uint128 &y);
friend uint128 operator*(const uint128 &x, const uint128 &y);
friend uint128 operator|(const uint128 &x, const uint128 &y);
friend uint128 operator&(const uint128 &x, const uint128 &y);
friend uint128 operator^(const uint128 &x, const uint128 &y);
friend uint128 operator>>(const uint128 &x, int cnt);
friend uint128 operator<<(const uint128 &x, int cnt);
uint128 &operator+=(const uint128 &y);
uint128 &operator-=(const uint128 &y);
uint128 &operator/=(const uint128 &y);
uint128 &operator%=(const uint128 &y);
uint128 &operator*=(const uint128 &y);
uint128 &operator|=(const uint128 &y);
uint128 &operator&=(const uint128 &y);
uint128 &operator^=(const uint128 &y);
uint128 &operator>>=(int cnt);
uint128 &operator<<=(int cnt);
uint128 &operator++(void);
uint128 &operator--(void);
friend uint128 operator+(const uint128 &x) { return x; }
friend uint128 operator-(const uint128 &x);
friend uint128 operator~(const uint128 &x) { return uint128(~x.l,~x.h); }
friend int operator==(const uint128 &x, const uint128 &y) { return x.l == y.l && x.h == y.h; }
friend int operator!=(const uint128 &x, const uint128 &y) { return x.l != y.l || x.h != y.h; }
friend int operator> (const uint128 &x, const uint128 &y) { return x.h > y.h || (x.h == y.h && x.l > y.l); }
friend int operator< (const uint128 &x, const uint128 &y) { return x.h < y.h || (x.h == y.h && x.l < y.l); }
friend int operator>=(const uint128 &x, const uint128 &y) { return x.h > y.h || (x.h == y.h && x.l >= y.l); }
friend int operator<=(const uint128 &x, const uint128 &y) { return x.h < y.h || (x.h == y.h && x.l <= y.l); }
};
//-V:int128:730 not all members of a class are initialized inside the constructor
class int128
{
ulonglong l;
longlong h;
friend class uint128;
public:
int128(void) {}
int128(uint x) { l = x; h = 0; }
int128(int x) { l = x; h = (x < 0) ? -1 : 0; }
int128(ulonglong x) { l = x; h = 0; }
int128(longlong x) { l = x; h = (x < 0) ? -1 : 0; }
int128(ulonglong ll, ulonglong hh) { l=ll; h=hh; }
int128(const uint128 &x) { l=x.l; h=x.h; }
friend ulonglong low (const int128 &x) { return x.l; }
friend ulonglong high(const int128 &x) { return x.h; }
friend int128 operator+(const int128 &x, const int128 &y);
friend int128 operator-(const int128 &x, const int128 &y);
friend int128 operator/(const int128 &x, const int128 &y);
friend int128 operator%(const int128 &x, const int128 &y);
friend int128 operator*(const int128 &x, const int128 &y);
friend int128 operator|(const int128 &x, const int128 &y);
friend int128 operator&(const int128 &x, const int128 &y);
friend int128 operator^(const int128 &x, const int128 &y);
friend int128 operator>>(const int128 &x, int cnt);
friend int128 operator<<(const int128 &x, int cnt);
int128 &operator+=(const int128 &y);
int128 &operator-=(const int128 &y);
int128 &operator/=(const int128 &y);
int128 &operator%=(const int128 &y);
int128 &operator*=(const int128 &y);
int128 &operator|=(const int128 &y);
int128 &operator&=(const int128 &y);
int128 &operator^=(const int128 &y);
int128 &operator>>=(int cnt);
int128 &operator<<=(int cnt);
int128 &operator++(void);
int128 &operator--(void);
friend int128 operator+(const int128 &x) { return x; }
friend int128 operator-(const int128 &x);
friend int128 operator~(const int128 &x) { return int128(~x.l,~x.h); }
friend int operator==(const int128 &x, const int128 &y) { return x.l == y.l && x.h == y.h; }
friend int operator!=(const int128 &x, const int128 &y) { return x.l != y.l || x.h != y.h; }
friend int operator> (const int128 &x, const int128 &y) { return x.h > y.h || (x.h == y.h && x.l > y.l); }
friend int operator< (const int128 &x, const int128 &y) { return x.h < y.h || (x.h == y.h && x.l < y.l); }
friend int operator>=(const int128 &x, const int128 &y) { return x.h > y.h || (x.h == y.h && x.l >= y.l); }
friend int operator<=(const int128 &x, const int128 &y) { return x.h < y.h || (x.h == y.h && x.l <= y.l); }
};
inline int128 make_int128(ulonglong ll, longlong hh) { return int128(ll, hh); }
inline uint128 make_uint128(ulonglong ll, longlong hh) { return uint128(ll, hh); }
idaman THREAD_SAFE void ida_export swap128(uint128 *x);
//---------------------------------------------------------------------------
inline uint128 operator+(const uint128 &x, const uint128 &y)
{
ulonglong h = x.h + y.h;
ulonglong l = x.l + y.l;
if ( l < x.l )
h = h + 1;
return uint128(l,h);
}
//---------------------------------------------------------------------------
inline uint128 operator-(const uint128 &x, const uint128 &y)
{
ulonglong h = x.h - y.h;
ulonglong l = x.l - y.l;
if ( l > x.l )
h = h - 1;
return uint128(l,h);
}
//---------------------------------------------------------------------------
inline uint128 operator|(const uint128 &x, const uint128 &y)
{
return uint128(x.l | y.l, x.h | y.h);
}
//---------------------------------------------------------------------------
inline uint128 operator&(const uint128 &x, const uint128 &y)
{
return uint128(x.l & y.l, x.h & y.h);
}
//---------------------------------------------------------------------------
inline uint128 operator^(const uint128 &x, const uint128 &y)
{
return uint128(x.l ^ y.l, x.h ^ y.h);
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator+=(const uint128 &y)
{
return *this = *this + y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator-=(const uint128 &y)
{
return *this = *this - y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator|=(const uint128 &y)
{
return *this = *this | y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator&=(const uint128 &y)
{
return *this = *this & y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator^=(const uint128 &y)
{
return *this = *this ^ y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator/=(const uint128 &y)
{
return *this = *this / y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator%=(const uint128 &y)
{
return *this = *this % y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator*=(const uint128 &y)
{
return *this = *this * y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator<<=(int cnt)
{
return *this = *this << cnt;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator>>=(int cnt)
{
return *this = *this >> cnt;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator++(void)
{
if ( ++l == 0 )
++h;
return *this;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator--(void)
{
if ( l == 0 )
--h;
--l;
return *this;
}
//---------------------------------------------------------------------------
inline uint128 operator-(const uint128 &x)
{
return ~x + 1;
}
#endif // ifdef __cplusplus
#endif // ifdef __HAS_INT128__
#endif // define _LLONG_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -1,384 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __MOVES_HPP
#define __MOVES_HPP
//-------------------------------------------------------------------------
struct graph_location_info_t
{
double zoom; // zoom level, 1.0 == 100%, 0 means auto position
double orgx; // graph origin, x coord
double orgy; // graph origin, y coord
graph_location_info_t(void) : zoom(0), orgx(0), orgy(0) {}
bool operator == (const graph_location_info_t &r) const
{ return zoom == r.zoom && orgx == r.orgx && orgy == r.orgy; } //-V550 An odd precise comparison: zoom == r.zoom
bool operator != (const graph_location_info_t &r) const
{ return !(*this == r); }
void serialize(bytevec_t *out) const;
bool deserialize(memory_deserializer_t &mmdsr);
};
//-------------------------------------------------------------------------
inline void graph_location_info_t::serialize(bytevec_t *out) const
{
CASSERT(sizeof(graph_location_info_t) == 3*8);
out->append(this, sizeof(graph_location_info_t));
}
//-------------------------------------------------------------------------
inline bool graph_location_info_t::deserialize(memory_deserializer_t &mmdsr)
{
return mmdsr.unpack_obj(this, sizeof(graph_location_info_t)) != NULL;
}
//-------------------------------------------------------------------------
struct segm_move_info_t
{
segm_move_info_t(ea_t _from = 0, ea_t _to = 0, size_t _sz = 0)
: from(_from), to(_to), size(_sz) {}
ea_t from, to;
size_t size;
bool operator == (const segm_move_info_t &r) const
{ return from == r.from && to == r.to && size == r.size; }
bool operator != (const segm_move_info_t &r) const
{ return !(*this == r); }
};
DECLARE_TYPE_AS_MOVABLE(segm_move_info_t);
typedef qvector<segm_move_info_t> segm_move_info_vec_t;
struct segm_move_infos_t : public segm_move_info_vec_t
{
const segm_move_info_t *find(ea_t ea) const
{
for ( size_t i = 0; i < size(); ++i )
{
const segm_move_info_t &cur = at(i);
if ( ea >= cur.from && ea < cur.from + cur.size )
return &cur;
}
return NULL;
}
};
//-------------------------------------------------------------------------
class place_t;
//-------------------------------------------------------------------------
struct renderer_info_pos_t // out of renderer_info_t, to enable SWiG parsing
{
int node;
short cx;
short cy;
renderer_info_pos_t() : node(-1), cx(-1), cy(-1) {}
bool operator == (const renderer_info_pos_t &r) const
{ return node == r.node && cx == r.cx && cy == r.cy; }
bool operator != (const renderer_info_pos_t &r) const
{ return !(*this == r); }
void serialize(bytevec_t *out) const;
bool deserialize(memory_deserializer_t &mmdsr);
};
//-------------------------------------------------------------------------
inline void renderer_info_pos_t::serialize(bytevec_t *out) const
{
out->pack_dd(node);
out->pack_dw(cx);
out->pack_dw(cy);
}
//-------------------------------------------------------------------------
inline bool renderer_info_pos_t::deserialize(memory_deserializer_t &mmdsr)
{
node = mmdsr.unpack_dd();
cx = mmdsr.unpack_dw();
if ( mmdsr.empty() )
return false;
cy = mmdsr.unpack_dw();
return true;
}
//-------------------------------------------------------------------------
struct renderer_info_t
{
renderer_info_t() { clear(); }
graph_location_info_t gli;
typedef renderer_info_pos_t pos_t;
pos_t pos;
tcc_renderer_type_t rtype;
bool operator == (const renderer_info_t &r) const
{ return rtype == r.rtype && pos == r.pos && gli == r.gli; }
bool operator != (const renderer_info_t &r) const
{ return !(*this == r); }
void clear()
{
gli = {};
pos = {};
rtype = TCCRT_INVALID;
}
};
//-------------------------------------------------------------------------
class lochist_t;
struct lochist_entry_t;
struct expanded_area_t;
#define LSEF_PLACE (1 << 0)
#define LSEF_RINFO (1 << 1)
#define LSEF_PTYPE (1 << 2)
#define LSEF_ALL (LSEF_PLACE|LSEF_RINFO|LSEF_PTYPE)
#ifndef SWIG
#define DEFINE_LOCHIST_T_HELPERS(decl) \
decl void ida_export lochist_t_register_live(lochist_t &); \
decl void ida_export lochist_t_deregister_live(lochist_t &); \
decl bool ida_export lochist_t_init (lochist_t &, const char *, const place_t &, void *, uint32); \
decl void ida_export lochist_t_jump (lochist_t &, bool try_to_unhide, const lochist_entry_t &e); \
decl bool ida_export lochist_t_fwd (lochist_t &, uint32 cnt, bool try_to_unhide); \
decl bool ida_export lochist_t_back (lochist_t &, uint32 cnt, bool try_to_unhide); \
decl bool ida_export lochist_t_seek (lochist_t &, uint32 index, bool try_to_unhide, bool apply_cur); \
decl const lochist_entry_t *ida_export lochist_t_get_current(const lochist_t &); \
decl uint32 ida_export lochist_t_current_index(const lochist_t &); \
decl void ida_export lochist_t_set (lochist_t &, uint32, const lochist_entry_t &); \
decl bool ida_export lochist_t_get (lochist_entry_t *, const lochist_t &, uint32); \
decl uint32 ida_export lochist_t_size (const lochist_t &);\
decl void ida_export lochist_t_save (const lochist_t &); \
decl void ida_export lochist_t_clear (lochist_t &);
#else
#define DEFINE_LOCHIST_T_HELPERS(decl)
#endif // SWIG
DEFINE_LOCHIST_T_HELPERS(idaman)
#ifndef SWIG
#define DEFINE_LOCHIST_ENTRY_T_HELPERS(decl) \
decl void ida_export lochist_entry_t_serialize(bytevec_t *, const lochist_entry_t &); \
decl bool ida_export lochist_entry_t_deserialize(lochist_entry_t *, const uchar **, const uchar *const, const place_t *);
#else
#define DEFINE_LOCHIST_ENTRY_T_HELPERS(decl)
#endif // SWIG
DEFINE_LOCHIST_ENTRY_T_HELPERS(idaman)
//-------------------------------------------------------------------------
struct lochist_entry_t
{
renderer_info_t rinfo;
place_t *plce;
lochist_entry_t() : plce(NULL) {}
lochist_entry_t(const place_t *p, const renderer_info_t &r)
: rinfo(r), plce((place_t *) p)
{
if ( plce != NULL )
plce = plce->clone();
}
#ifndef SWIG
lochist_entry_t(const lochist_t &s);
#endif // SWIG
lochist_entry_t(const lochist_entry_t &other) : plce(NULL) { *this = other; }
~lochist_entry_t() { clear(); }
const renderer_info_t &renderer_info() const { return rinfo; }
const place_t *place() const { return plce; }
renderer_info_t &renderer_info() { return rinfo; }
place_t *place() { return plce; }
void set_place(const place_t *p) { clear(); plce = p == NULL ? NULL : p->clone(); }
void set_place(const place_t &p) { set_place(&p); }
bool is_valid() const { return plce != NULL; }
lochist_entry_t &operator=(const lochist_entry_t &r)
{
clear();
(*this).rinfo = r.rinfo;
if ( r.plce != NULL )
plce = r.plce->clone();
return *this;
}
void acquire_place(place_t *in_p)
{ clear(); plce = in_p; }
void serialize(bytevec_t *out) const { lochist_entry_t_serialize(out, *this); }
bool deserialize(const uchar **ptr, const uchar *const end, const place_t *tmplate)
{ return lochist_entry_t_deserialize(this, ptr, end, tmplate); }
private:
void clear()
{
if ( plce != NULL )
qfree(plce);
}
friend class lochist_t;
DEFINE_LOCHIST_T_HELPERS(friend)
DEFINE_LOCHIST_ENTRY_T_HELPERS(friend)
};
DECLARE_TYPE_AS_MOVABLE(lochist_entry_t);
#define UNHID_SEGM 0x0001 // unhid a segment at 'target'
#define UNHID_FUNC 0x0002 // unhid a function at 'target'
#define UNHID_RANGE 0x0004 // unhid an range at 'target'
#define DEFAULT_CURSOR_Y 0xFFFF
#define DEFAULT_LNNUM -1
#define CURLOC_LIST "$ curlocs"
#define MAX_MARK_SLOT 1024 // Max number of marked locations
//-------------------------------------------------------------------------
class lochist_t
{
void *ud;
DEFINE_LOCHIST_T_HELPERS(friend)
lochist_entry_t cur;
netnode node;
#define LHF_HISTORY_DISABLED (1 << 0) // enable history?
uint32 flags;
public:
lochist_t() : flags(0) { lochist_t_register_live(*this); }
~lochist_t() { lochist_t_deregister_live(*this); }
bool is_history_enabled() const { return (flags & LHF_HISTORY_DISABLED) == 0; }
int get_place_id() const
{
const place_t *p = cur.place();
return p == NULL ? -1 : p->id();
}
bool init(const char *stream_name, const place_t *_defpos, void *_ud, uint32 _flags)
{ return lochist_t_init(*this, stream_name, *_defpos, _ud, _flags); }
nodeidx_t netcode() const
{ return node; }
void jump(bool try_to_unhide, const lochist_entry_t &e)
{ lochist_t_jump(*this, try_to_unhide, e); }
uint32 current_index() const
{ return lochist_t_current_index(*this); }
bool seek(uint32 index, bool try_to_unhide)
{ return lochist_t_seek(*this, index, try_to_unhide, true); }
bool fwd(uint32 cnt, bool try_to_unhide)
{ return lochist_t_fwd(*this, cnt, try_to_unhide); }
bool back(uint32 cnt, bool try_to_unhide)
{ return lochist_t_back(*this, cnt, try_to_unhide); }
void save() const
{ lochist_t_save(*this); }
void clear()
{ lochist_t_clear(*this); }
const lochist_entry_t &get_current() const
{ return *lochist_t_get_current(*this); }
void set_current(const lochist_entry_t &e)
{ return set(current_index(), e); }
void set(uint32 index, const lochist_entry_t &e)
{ lochist_t_set(*this, index, e); }
bool get(lochist_entry_t *out, uint32 index) const
{ return lochist_t_get(out, *this, index); }
uint32 size(void) const
{ return lochist_t_size(*this); }
const place_t *get_template_place() const
{ return cur.place(); }
};
DECLARE_TYPE_AS_MOVABLE(lochist_t);
//-------------------------------------------------------------------------
#ifndef SWIG
idaman uint32 ida_export bookmarks_t_mark(const lochist_entry_t &, uint32, const char *, const char *, void *);
idaman bool ida_export bookmarks_t_get(lochist_entry_t *, qstring *, uint32 *, void *);
idaman bool ida_export bookmarks_t_get_desc(qstring *, const lochist_entry_t &, uint32, void *);
idaman uint32 ida_export bookmarks_t_find_index(const lochist_entry_t &, void *);
idaman uint32 ida_export bookmarks_t_size(const lochist_entry_t &, void *);
idaman bool ida_export bookmarks_t_erase(const lochist_entry_t &, uint32, void *);
#endif // SWIG
//-------------------------------------------------------------------------
class bookmarks_t
{
bookmarks_t(); // No.
~bookmarks_t() {}
public:
#define BOOKMARKS_CHOOSE_INDEX (uint32(-1))
#define BOOKMARKS_BAD_INDEX (uint32(-1))
// Mark/unmark position
// index - the marked position number (0..MAX_MARK_SLOT)
// if specified as BOOKMARKS_CHOOSE_INDEX: ask the user to select the mark slot.
// title - if index == BOOKMARKS_CHOOSE_INDEX, then the window caption of
// the dialog which will appear on the screen. title==NULL will
// lead to the default caption: "please select a mark slot"
// desc - description of the marked position. If NULL, IDA will show a
// dialog box asking the user to enter the description.
// returns used marker number (BOOKMARKS_BAD_INDEX - none)
static uint32 mark(
const lochist_entry_t &e,
uint32 index,
const char *title,
const char *desc,
void *ud)
{ return bookmarks_t_mark(e, index, title, desc, ud); }
// 'out_entry' MUST:
// - contain a valid place_t*; data will be deserialized into it
// - have a valid, corresponding tcc_place_type_t
static bool get(
lochist_entry_t *out_entry,
qstring *out_desc,
uint32 *index, // index==BOOKMARKS_CHOOSE_INDEX? let the user choose
void *ud)
{ return bookmarks_t_get(out_entry, out_desc, index, ud); }
static bool get_desc(
qstring *out,
const lochist_entry_t &e,
uint32 index,
void *ud)
{ return bookmarks_t_get_desc(out, e, index, ud); }
static uint32 find_index(
const lochist_entry_t &e,
void *ud)
{ return bookmarks_t_find_index(e, ud); }
static uint32 size(
const lochist_entry_t &e,
void *ud)
{ return bookmarks_t_size(e, ud); }
static bool erase(
const lochist_entry_t &e,
uint32 index,
void *ud)
{ return bookmarks_t_erase(e, index, ud); }
};
//-------------------------------------------------------------------------
inline lochist_entry_t::lochist_entry_t(const lochist_t &lh)
: plce(NULL)
{
*this = lh.get_current();
}
#endif // __MOVES_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -1,786 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _NAME_HPP
#define _NAME_HPP
#include <ida.hpp>
/*! \file name.hpp
\brief Functions that deal with names.
A non-tail address of the program may have a name.
Tail addresses (i.e. the addresses in the middle of an instruction or
data item) cannot have names.
*/
class func_t; // funcs.hpp
typedef uchar color_t; // lines.hpp
/// Maximum length of a name in IDA (with the trailing zero)
#define MAXNAMELEN 512
/// Name prefix used by IDA for the imported functions
#define FUNC_IMPORT_PREFIX "__imp_"
/// Set or delete name of an item at the specified address.
/// An item can be anything: instruction, function, data byte, word, string,
/// structure, etc...
/// Include name into the list of names.
/// \param ea linear address.
/// do nothing if ea is not valid (return 0).
/// tail bytes can't have names.
/// \param name new name.
/// - NULL: do nothing (return 0).
/// - "" : delete name.
/// - otherwise this is a new name.
/// \param flags \ref SN_.
/// If a bit is not specified, then the corresponding action is not performed
/// and the name will retain the same bits as before calling this function.
/// For new names, default is: non-public, non-weak, non-auto.
/// \retval 1 ok, name is changed
/// \retval 0 failure, a warning is displayed
idaman bool ida_export set_name(ea_t ea, const char *name, int flags=0);
/// \defgroup SN_ Set name flags
/// Passed as 'flag' parameter to set_name(ea_t, const char *, int)
//@{
#define SN_CHECK 0x00
#define SN_NOCHECK 0x01 ///< Don't fail if the name contains invalid characters.
///< If this bit is clear, all invalid chars
///< (those !is_ident_cp()) will be replaced
///< by SUBSTCHAR
///< List of valid characters is defined in ida.cfg
#define SN_PUBLIC 0x02 ///< if set, make name public
#define SN_NON_PUBLIC 0x04 ///< if set, make name non-public
#define SN_WEAK 0x08 ///< if set, make name weak
#define SN_NON_WEAK 0x10 ///< if set, make name non-weak
#define SN_AUTO 0x20 ///< if set, make name autogenerated
#define SN_NON_AUTO 0x40 ///< if set, make name non-autogenerated
#define SN_NOLIST 0x80 ///< if set, exclude name from the list.
///< if not set, then include the name into
///< the list (however, if other bits are set,
///< the name might be immediately excluded
///< from the list).
#define SN_NOWARN 0x100 ///< don't display a warning if failed
#define SN_LOCAL 0x200 ///< create local name. a function should exist.
///< local names can't be public or weak.
///< also they are not included into the list of names
///< they can't have dummy prefixes.
#define SN_IDBENC 0x400 ///< the name is given in the IDB encoding;
///< non-ASCII bytes will be decoded accordingly.
///< Specifying SN_IDBENC also implies SN_NODUMMY
#define SN_FORCE 0x800 ///< if the specified name is already present
///< in the database, try variations with a
///< numerical suffix like "_123"
#define SN_NODUMMY 0x1000 ///< automatically prepend the name with '_' if it
///< begins with a dummy suffix such as 'sub_'.
///< See also SN_IDBENC
#define SN_DELTAIL 0x2000 ///< if name cannot be set because of a tail byte,
///< delete the hindering item
//@}
inline bool force_name(ea_t ea, const char *name, int flags=0)
{
return set_name(ea, name, flags|SN_FORCE|SN_NODUMMY);
}
/// \name Delete a name of a program item
/// \param ea linear address
/// \retval 1 ok, name is deleted
/// \retval 0 failure, invalid address
//@{
inline bool del_global_name(ea_t ea) { return set_name(ea,"", SN_NOWARN); }
inline bool del_local_name(ea_t ea) { return set_name(ea,"", SN_LOCAL|SN_NOWARN); }
//@}
/// Give an autogenerated (dummy) name.
/// Autogenerated names have special prefixes (loc_...).
/// \param from linear address of the operand which references to the address
/// \param ea linear address
/// \retval 1 ok, dummy name is generated or the byte already had a name
/// \retval 0 failure, invalid address or tail byte
idaman bool ida_export set_dummy_name(ea_t from, ea_t ea); // give dummy name
/// \name Set/Clear bit in flags for 'autogenerated but meaningful name'
/// This bit affects value of has_user_name(), has_auto_name() functions.
/// \param ea linear address
/// \retval 1 ok
/// \retval 0 no meaningful name is present at the specified address
//@{
idaman bool ida_export make_name_auto(ea_t ea);
idaman bool ida_export make_name_user(ea_t ea);
//@}
enum ucdr_kind_t
{
UCDR_STRLIT = 0x01, // string literals
UCDR_NAME = 0x02, // regular (unmangled) names
UCDR_MANGLED = 0x04, // mangled names
UCDR_TYPE = 0x08, // type names
};
enum nametype_t
{
// identifier (e.g., function name)
VNT_IDENT = UCDR_NAME|UCDR_MANGLED,
// type name (can contain '<', '>', ...)
VNT_TYPE = UCDR_TYPE,
// UDT (structure, union, enum) member
VNT_UDTMEM = UCDR_NAME,
// string literal
VNT_STRLIT = UCDR_STRLIT,
VNT_VISIBLE = VNT_UDTMEM,// visible cp (obsolete; will be deleted)
};
/// Validate a name.
/// This function replaces all invalid characters in the name with SUBSTCHAR.
/// However, it will return false if name is valid but not allowed to be an
/// identifier (is a register name).
///
/// \param[in,out] name ptr to name. the name will be modified
/// \param type the type of name we want to validate
/// \param flags see SN_* . Only SN_IDBENC is currently considered
///
/// \return success
idaman bool ida_export validate_name(
qstring *name,
nametype_t type,
int flags = 0);
/// Is the given codepoint acceptable in the given context?
idaman bool ida_export is_valid_cp(wchar32_t cp, nametype_t kind, void *data=NULL);
/// Mark the given codepoint (or range) as acceptable or unacceptable in the given context
/// If 'endcp' is not BADCP, it is considered to be the end of the range:
/// [cp, endcp), and is not included in the range
idaman void ida_export set_cp_validity(ucdr_kind_t kind, wchar32_t cp, wchar32_t endcp=BADCP, bool valid=true);
/// Is the given codepoint (or range) acceptable in the given context?
/// If 'endcp' is not BADCP, it is considered to be the end of the range:
/// [cp, endcp), and is not included in the range
idaman bool ida_export get_cp_validity(ucdr_kind_t kind, wchar32_t cp, wchar32_t endcp=BADCP);
/// Can a character appear in a name? (present in ::NameChars or ::MangleChars)
inline bool is_ident_cp(wchar32_t cp) { return is_valid_cp(cp, VNT_IDENT); }
/// Can a character appear in a string literal (present in ::StrlitChars)
/// If 'specific_ranges' are specified, those will be used instead of
/// the ones corresponding to the current culture (only if ::StrlitChars
/// is configured to use the current culture)
inline bool is_strlit_cp(wchar32_t cp, const rangeset_crefvec_t *specific_ranges=NULL)
{ return is_valid_cp(cp, VNT_STRLIT, (void *) specific_ranges); }
/// Can a character be displayed in a name? (present in ::NameChars)
inline bool is_visible_cp(wchar32_t cp)
{ return is_valid_cp(cp, VNT_VISIBLE); }
/// Is a valid name? (including ::MangleChars)
idaman bool ida_export is_ident(const char *name);
/// Is valid user-specified name? (valid name & !dummy prefix).
/// \param name name to test. may be NULL.
/// \retval 1 yes
/// \retval 0 no
idaman bool ida_export is_uname(const char *name);
/// Is valid type name?
/// \param name name to test. may be NULL.
/// \retval 1 yes
/// \retval 0 no
idaman bool ida_export is_valid_typename(const char *name);
/// Is dummy name?
/// \param name name to test. may be NULL.
/// \return #BADADDR if not, otherwise the address denoted by the name
idaman ea_t ida_export dummy_name_ea(const char *name);
/// Extract a name or address from the specified string.
/// \param[out] out output buffer for the identifier
/// \param line input string
/// \param x x coordinate of cursor
/// \return -1 if cannot extract. otherwise length of the name
idaman ssize_t ida_export extract_name(qstring *out, const char *line, int x);
/// Remove name from the list of names
/// \param ea address of the name
idaman void ida_export hide_name(ea_t ea);
/// Insert name to the list of names
idaman void ida_export show_name(ea_t ea);
/// Get address of the name.
/// Dummy names (like byte_xxxx where xxxx are hex digits) are parsed by this
/// function to obtain the address. The database is not consulted for them.
/// This function works only with regular names.
/// \param from linear address where the name is used.
/// if not applicable, then should be #BADADDR.
/// \param name any name in the program or NULL
/// \return address of the name or #BADADDR
idaman ea_t ida_export get_name_ea(ea_t from, const char *name);
/// Get address of the name used in the expression for the address
/// \param from address of the operand which references to the address
/// \param to the referenced address
/// \return address of the name used to represent the operand
idaman ea_t ida_export get_name_base_ea(ea_t from, ea_t to);
/// Get value of the name.
/// This function knows about: regular names, enums, special segments, etc.
/// \param[out] value pointer to variable with answer
/// \param from linear address where the name is used
/// if not applicable, then should be BADADDR
/// \param name any name in the program or NULL
/// \return \ref NT_
idaman int ida_export get_name_value(uval_t *value, ea_t from, const char *name);
/// \defgroup NT_ Name value result codes
/// Return values for get_name_value()
//@{
#define NT_NONE 0 ///< name doesn't exist or has no value
#define NT_BYTE 1 ///< name is byte name (regular name)
#define NT_LOCAL 2 ///< name is local label
#define NT_STKVAR 3 ///< name is stack variable name
#define NT_ENUM 4 ///< name is symbolic constant
#define NT_ABS 5 ///< name is absolute symbol (#SEG_ABSSYM)
#define NT_SEG 6 ///< name is segment or segment register name
#define NT_STROFF 7 ///< name is structure member
#define NT_BMASK 8 ///< name is a bit group mask name
#define NT_REGVAR 9 ///< name is a renamed register (*value is idx into pfn->regvars)
//@}
/// Additional information for get_ea_name() function
struct getname_info_t
{
size_t cb; ///< size of this struct
int32 inhibitor; ///< codes to inhibit parts of demangled name (see \ref MNG_).
///< Usually this is one of \inf{short_demnames} or \inf{long_demnames}.
int32 demform; ///< demangle only if \inf{demnames} is equal to 'demform'.
int32 demcode; ///< out: return value of demangler
getname_info_t(void) : cb(sizeof(*this)), inhibitor(0), demform(0), demcode(0) {}
};
/// Get name at the specified address.
/// \param[out] out buffer to hold the name
/// \param ea linear address
/// \param gtn_flags how exactly the name should be retrieved.
/// combination of \ref GN_ bits
/// \param gtni additional information for name demangling
/// Please use the convenience functions declared below instead of calling
/// get_ea_name directly.
/// \return success
idaman ssize_t ida_export get_ea_name(
qstring *out,
ea_t ea,
int gtn_flags=0,
getname_info_t *gtni=NULL);
/// \defgroup GN_ bits for get_ea_name() function. There is a convenience
/// function calc_gtn_flags() to calculate the GN_LOCAL flag
//@{
#define GN_VISIBLE 0x0001 ///< replace forbidden characters by SUBSTCHAR
#define GN_COLORED 0x0002 ///< return colored name
#define GN_DEMANGLED 0x0004 ///< return demangled name
#define GN_STRICT 0x0008 ///< fail if cannot demangle
#define GN_SHORT 0x0010 ///< use short form of demangled name
#define GN_LONG 0x0020 ///< use long form of demangled name
#define GN_LOCAL 0x0040 ///< try to get local name first; if failed, get global
#define GN_ISRET 0x0080 ///< for dummy names: use retloc
#define GN_NOT_ISRET 0x0100 ///< for dummy names: do not use retloc
#define GN_NOT_DUMMY 0x0200 ///< do not return a dummy name
//@}
// Convenience functions for get_ea_name returning ssize_t
inline ssize_t get_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, gtn_flags);
}
inline ssize_t idaapi get_visible_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|gtn_flags);
}
inline ssize_t idaapi get_colored_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_COLORED|gtn_flags);
}
inline ssize_t idaapi get_short_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_DEMANGLED|GN_SHORT|gtn_flags);
}
inline ssize_t idaapi get_long_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_DEMANGLED|GN_LONG|gtn_flags);
}
inline ssize_t idaapi get_colored_short_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_COLORED|GN_DEMANGLED|GN_SHORT|gtn_flags);
}
inline ssize_t idaapi get_colored_long_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_COLORED|GN_DEMANGLED|GN_LONG|gtn_flags);
}
inline ssize_t idaapi get_demangled_name(
qstring *out,
ea_t ea,
int32 inhibitor,
int demform,
int gtn_flags=0)
{
getname_info_t gtni;
gtni.inhibitor = inhibitor;
gtni.demform = demform;
gtn_flags |= GN_VISIBLE | GN_DEMANGLED;
return get_ea_name(out, ea, gtn_flags, &gtni);
}
inline ssize_t idaapi get_colored_demangled_name(
qstring *out,
ea_t ea,
int32 inhibitor,
int demform,
int gtn_flags=0)
{
return get_demangled_name(out, ea, inhibitor, demform, gtn_flags|GN_COLORED);
}
// Convenience functions for get_ea_name returning qstring
inline qstring get_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, gtn_flags);
return out;
}
inline qstring get_visible_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|gtn_flags);
return out;
}
inline qstring idaapi get_colored_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_COLORED|gtn_flags);
return out;
}
inline qstring idaapi get_short_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_DEMANGLED|GN_SHORT|gtn_flags);
return out;
}
inline qstring idaapi get_long_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_DEMANGLED|GN_LONG|gtn_flags);
return out;
}
inline qstring idaapi get_colored_short_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_COLORED|GN_DEMANGLED|GN_SHORT|gtn_flags);
return out;
}
inline qstring idaapi get_colored_long_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_COLORED|GN_DEMANGLED|GN_LONG|gtn_flags);
return out;
}
inline qstring idaapi get_demangled_name(
ea_t ea,
int32 inhibitor,
int demform,
int gtn_flags=0)
{
qstring out;
getname_info_t gtni;
gtni.inhibitor = inhibitor;
gtni.demform = demform;
gtn_flags |= GN_VISIBLE | GN_DEMANGLED;
get_ea_name(&out, ea, gtn_flags, &gtni);
return out;
}
inline qstring idaapi get_colored_demangled_name(
ea_t ea,
int32 inhibitor,
int demform,
int gtn_flags=0)
{
qstring out;
get_demangled_name(&out, ea, inhibitor, demform, gtn_flags|GN_COLORED);
return out;
}
/// Calculate flags for get_ea_name() function
#ifdef FUNCS_HPP
inline int calc_gtn_flags(ea_t from, ea_t ea)
{
return func_contains(get_func(from), ea) ? GN_LOCAL : 0;
}
#endif
/// Get name color.
/// \param from linear address where the name is used.
/// if not applicable, then should be #BADADDR.
/// The kernel returns a local name color if the reference is
/// within a function, i.e. 'from' and 'ea' belong to the same function.
/// \param ea linear address
idaman color_t ida_export get_name_color(ea_t from, ea_t ea);
/// \defgroup GETN_ Name expression flags
/// Passed as 'flags' parameter to get_name_expr()
//@{
#define GETN_APPZERO 0x0001 ///< meaningful only if the name refers to a structure.
///< append a struct field name if the field offset is zero?
#define GETN_NOFIXUP 0x0002 ///< ignore the fixup information when producing the name
#define GETN_NODUMMY 0x0004 ///< do not create a new dummy name but pretend it exists
//@}
/// Convert address to name expression (name with a displacement).
/// This function takes into account fixup information and returns
/// a colored name expression (in the form <name> +/- <offset>).
/// It also knows about structure members and arrays.
/// If the specified address doesn't have a name, a dummy name is generated.
/// \param[out] out output buffer for the name
/// \param from linear address of instruction operand or data referring to
/// the name. This address will be used to get fixup information,
/// so it should point to exact position of the operand in the
/// instruction.
/// \param n number of referencing operand. for data items specify 0
/// \param ea address to convert to name expression
/// \param off the value of name expression. this parameter is used only to
/// check that the name expression will have the wanted value.
/// 'off' may be equal to BADADDR but this is discouraged
/// because it prohibits checks.
/// \param flags \ref GETN_
/// \return < 0 if address is not valid, no segment or other failure.
/// otherwise the length of the name expression in characters.
idaman ssize_t ida_export get_name_expr(
qstring *out,
ea_t from,
int n,
ea_t ea,
uval_t off,
int flags=GETN_APPZERO);
/// Get a nice colored name at the specified address.
/// Ex:
/// - segment:sub+offset
/// - segment:sub:local_label
/// - segment:label
/// - segment:address
/// - segment:address+offset
/// \param[out] buf buffer to hold the name
/// \param ea linear address
/// \param flags \ref GNCN_
/// \return the length of the generated name in bytes.
idaman ssize_t ida_export get_nice_colored_name(
qstring *buf,
ea_t ea,
int flags=0);
/// \defgroup GNCN_ Nice colored name flags
/// Passed as 'flags' parameter to get_nice_colored_name()
//@{
#define GNCN_NOSEG 0x0001 ///< ignore the segment prefix when producing the name
#define GNCN_NOCOLOR 0x0002 ///< generate an uncolored name
#define GNCN_NOLABEL 0x0004 ///< don't generate labels
#define GNCN_NOFUNC 0x0008 ///< don't generate funcname+... expressions
#define GNCN_SEG_FUNC 0x0010 ///< generate both segment and function names (default is to omit segment name if a function name is present)
#define GNCN_SEGNUM 0x0020 ///< segment part is displayed as a hex number
#define GNCN_REQFUNC 0x0040 ///< return 0 if the address does not belong to a function
#define GNCN_REQNAME 0x0080 ///< return 0 if the address can only be represented as a hex number
#define GNCN_NODBGNM 0x0100 ///< don't use debug names
#define GNCN_PREFDBG 0x0200 ///< if using debug names, prefer debug names over function names
//@}
/// Append names of struct fields to a name if the name is a struct name.
/// \param out pointer to the output buffer
/// \param disp displacement from the name
/// \param n number of operand n which the name appears
/// \param path path in the struct. path is an array of id's.
/// maximal length of array is #MAXSTRUCPATH.
/// the first element of the array is the structure id.
/// consecutive elements are id's of used union members (if any).
/// \param plen size of path array
/// \param flags the input flags. they will be returned if the struct
/// cannot be found.
/// \param delta delta to add to displacement
/// \param appzero should append a struct field name if the displacement is zero?
/// \return flags of the innermost struct member or the input flags
idaman flags_t ida_export append_struct_fields(
qstring *out,
adiff_t *disp,
int n,
const tid_t *path,
int plen,
flags_t flags,
adiff_t delta,
bool appzero);
/// Get offset within a structure if the operand refers to structure.
/// Ex:
/// \v{mov ax, somedata.field5-2 (before it was max ax, 3)}
/// for this instruction, op #1 the function will return
/// - disp: the value of 'field5', i.e. 5
/// - delta: -2
/// - path: the existing path if any
/// \param disp pointer to displacement (answer will be here)
/// \param delta pointer to displacement delta (answer will be here)
/// \param path existing strpath (if any)
/// \param ea linear address of instruction/data
/// \param n number of operand
/// \return if success, then length of path + 1.
/// if failed, then 0.
idaman int ida_export get_struct_operand(
adiff_t *disp,
adiff_t *delta,
tid_t *path,
ea_t ea,
int n);
/// \name Work with publicness of a name
//@{
idaman bool ida_export is_public_name(ea_t ea);
idaman void ida_export make_name_public(ea_t ea);
idaman void ida_export make_name_non_public(ea_t ea);
//@}
/// \name Work with weak names.
//@{
idaman bool ida_export is_weak_name(ea_t ea);
idaman void ida_export make_name_weak(ea_t ea);
idaman void ida_export make_name_non_weak(ea_t ea);
//@}
/// \name Work with the list of names
//@{
/// Get number of names in the list
idaman size_t ida_export get_nlist_size(void);
/// Get index of the name in the list
/// \warning returns the closest match.
/// may return idx >= size.
idaman size_t ida_export get_nlist_idx(ea_t ea);
/// Is name included into names list?
idaman bool ida_export is_in_nlist(ea_t ea);
/// Get address from the list at 'idx'
idaman ea_t ida_export get_nlist_ea(size_t idx);
/// Get name using idx
idaman const char *ida_export get_nlist_name(size_t idx);
/// Rebuild names list
idaman void ida_export rebuild_nlist(void);
//@}
/// Renumber dummy names
idaman void ida_export reorder_dummy_names(void);
/// Specify strategy for retrieving debug names
enum debug_name_how_t
{
DEBNAME_EXACT, ///< find a name at exactly the specified address
DEBNAME_LOWER, ///< find a name with the address >= the specified address
DEBNAME_UPPER, ///< find a name with the address > the specified address
DEBNAME_NICE, ///< find a name with the address <= the specified address
};
/// ea, name pair
struct ea_name_t
{
ea_t ea;
qstring name;
ea_name_t(void) : ea(BADADDR) {}
ea_name_t(ea_t _ea, const qstring &_name) : ea(_ea), name(_name) {}
};
DECLARE_TYPE_AS_MOVABLE(ea_name_t);
typedef qvector<ea_name_t> ea_name_vec_t; ///< vector of ea,name pairs
/// \name Debug names
/// Debug names exist during the debugging session.
/// The kernel does not verify them for anything and happily accepts
/// any string as a name.
//@{
idaman int ida_export set_debug_names(const ea_t *addrs, const char *const *names, int qty);
idaman bool ida_export set_debug_name(ea_t ea, const char *name);
idaman ssize_t ida_export get_debug_name(
qstring *out,
ea_t *ea_ptr,
debug_name_how_t how);
idaman void ida_export del_debug_names(ea_t ea1, ea_t ea2);
idaman ea_t ida_export get_debug_name_ea(const char *name);
idaman void ida_export get_debug_names(ea_name_vec_t *names, ea_t ea1, ea_t ea2);
//@}
enum demreq_type_t
{
DQT_NPURGED_8 = -8, // only calculate number of purged bytes (sizeof(arg)==8)
DQT_NPURGED_4 = -4, // only calculate number of purged bytes (sizeof(arg)==4)
DQT_NPURGED_2 = -2, // only calculate number of purged bytes (sizeof(arg)==2)
DQT_COMPILER = 0, // only detect compiler that generated the name
DQT_NAME_TYPE = 1, // only detect the name type (data/code)
DQT_FULL = 2, // really demangle
};
/// Demangle a name.
/// \param out output buffer
/// \param name name to demangle
/// \param disable_mask bits to inhibit parts of demangled name (see \ref MNG_).
/// by the M_COMPILER bits a specific compiler can be
/// selected (see \ref MT_).
/// \return ME_... or MT__ bitmasks from demangle.hpp
idaman int32 ida_export demangle_name(
qstring *out,
const char *name,
uint32 disable_mask,
demreq_type_t demreq=DQT_FULL);
/// Demangle a name.
inline qstring idaapi demangle_name(
const char *name,
uint32 disable_mask,
demreq_type_t demreq=DQT_FULL)
{
qstring out;
demangle_name(&out, name, disable_mask, demreq);
return out;
}
inline int32 detect_compiler_using_demangler(const char *name)
{
return demangle_name(NULL, name, 0, DQT_COMPILER);
}
/// What name types to ignore
typedef int ignore_name_def_t;
const ignore_name_def_t
ignore_none = 0,
ignore_regvar = 1,
ignore_llabel = 2,
ignore_stkvar = 3,
ignore_glabel = 4;
/// Is the name defined locally in the specified function?
/// \param pfn pointer to function
/// \param name name to check
/// \param ignore_name_def which names to ignore when checking
/// \param ea1 the starting address of the range inside the function (optional)
/// \param ea2 the ending address of the range inside the function (optional)
/// \return true if the name has been defined
idaman bool ida_export is_name_defined_locally(
func_t *pfn,
const char *name,
ignore_name_def_t ignore_name_def,
ea_t ea1=BADADDR,
ea_t ea2=BADADDR);
// Clean a name.
// This function removes punctuation marks (underscores and dots) from both
// ends of the name, and other typical prefixes/suffixes. Name is assumed to
// have the following format: [j_][@][.][_*][imp_]name[@digits][_NN]
// \param out output buffer
// \param ea address of the name (used to remove the module name)
// if != BADADDR, the optional prefix (module name) will be
// removed
// \param name name to clean
// \param flags combination of CN_... bits
// \return true if returned a non-empty name
idaman bool ida_export cleanup_name(
qstring *out,
ea_t ea,
const char *name,
uint32 flags=0);
#define CN_KEEP_TRAILING__DIGITS 0x01 // do not remove "_\d+" at the end of name
#endif // _NAME_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -1,454 +0,0 @@
#ifndef NETWORK_HPP
#define NETWORK_HPP
#include <map>
#include <pro.h>
#ifdef __NT__
# if !defined(AF_MAX)
# include <ws2tcpip.h>
# endif
# define SYSTEM "Windows"
# define socklen_t int
# define SHUT_RD SD_RECEIVE
# define SHUT_WR SD_SEND
# define SHUT_RDWR SD_BOTH
#else // not NT, i.e. UNIX
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <netdb.h>
# define closesocket(s) close(s)
# define SOCKET size_t
# define INVALID_SOCKET size_t(-1)
# define SOCKET_ERROR (-1)
# if defined(__LINUX__)
# if defined(__ARM__)
# if defined(__ANDROID__)
# define SYSTEM "Android"
# else
# define SYSTEM "ARM Linux"
# endif
# else
# if defined(__ANDROID__)
# define SYSTEM "Android x86"
# else
# define SYSTEM "Linux"
# endif
# endif
// linux debugger cannot be multithreaded because it uses thread_db.
// i doubt that this library is meant to be used with multiple
// applications simultaneously.
# define __SINGLE_THREADED_SERVER__
# elif defined(__MAC__)
# define SYSTEM "Mac OS X"
# else
# error "Unknown platform"
# endif
# include <sys/socket.h>
# include <netinet/in.h>
#endif
#ifndef __X86__
# define _SYSBITS " 64-bit"
#else
# define _SYSBITS " 32-bit"
#endif
#ifdef TESTABLE_BUILD
# ifdef __EA64__
# define SYSBITS _SYSBITS " (sizeof ea=64)"
# else
# define SYSBITS _SYSBITS " (sizeof ea=32)"
# endif
#else
# define SYSBITS _SYSBITS
#endif
#ifdef __SINGLE_THREADED_SERVER__
# define __SERVER_TYPE__ "ST"
#else
# define __SERVER_TYPE__ "MT"
#endif
#define TIMEOUT (1000/25) // timeout for polling (ms)
#define TIMEOUT_INFINITY -1
#define RECV_HELLO_TIMEOUT 1000 // timeout for the first packet (ms)
#define RECV_TIMEOUT_PERIOD 10000 // timeout for recv (ms)
// bidirectional codes (client <-> server)
enum base_packet_id_t
{
RPC_OK = 0, // response: function call succeeded
RPC_UNK, // response: unknown function code
RPC_MEM, // response: no memory
base_packet_id_last
};
#define RPC_OPEN 3 // server->client: i'm ready, the very first packet
#define RPC_EVENT 4 // server->client: debug event ready, followed by debug_event
#define RPC_EVOK 5 // client->server: event processed (in response to RPC_EVENT)
#define RPC_CANCELLED 6 // client->server: operation was cancelled by the user
// we need EVOK to handle the situation when the debug
// event was detected by the server during polling and
// was sent to the client using RPC_EVENT but client has not received it yet
// and requested GET_DEBUG_EVENT. In this case we should not
// call remote_get_debug_event() but instead force the client
// to use the event sent by RPC_EVENT.
// In other words, if the server has sent RPC_EVENT but has not
// received RPC_EVOK, it should fail all GET_DEBUG_EVENTS.
// client->server codes
#define RPC_INIT 10
#define RPC_TERM 11
#define RPC_GET_PROCESSES 12
#define RPC_START_PROCESS 13
#define RPC_EXIT_PROCESS 14
#define RPC_ATTACH_PROCESS 15
#define RPC_DETACH_PROCESS 16
#define RPC_GET_DEBUG_EVENT 17
#define RPC_PREPARE_TO_PAUSE_PROCESS 18
#define RPC_STOPPED_AT_DEBUG_EVENT 19
#define RPC_CONTINUE_AFTER_EVENT 20
#define RPC_TH_SUSPEND 21
#define RPC_TH_CONTINUE 22
#define RPC_SET_RESUME_MODE 23
#define RPC_GET_MEMORY_INFO 24
#define RPC_READ_MEMORY 25
#define RPC_WRITE_MEMORY 26
#define RPC_UPDATE_BPTS 27
#define RPC_UPDATE_LOWCNDS 28
#define RPC_EVAL_LOWCND 29
#define RPC_ISOK_BPT 30
#define RPC_READ_REGS 31
#define RPC_WRITE_REG 32
#define RPC_GET_SREG_BASE 33
#define RPC_SET_EXCEPTION_INFO 34
#define RPC_OPEN_FILE 35
#define RPC_CLOSE_FILE 36
#define RPC_READ_FILE 37
#define RPC_WRITE_FILE 38
#define RPC_IOCTL 39 // both client and the server may send this packet
#define RPC_UPDATE_CALL_STACK 40
#define RPC_APPCALL 41
#define RPC_CLEANUP_APPCALL 42
#define RPC_REXEC 43
#define RPC_GET_SCATTERED_IMAGE 44
#define RPC_GET_IMAGE_UUID 45
#define RPC_GET_SEGM_START 46
#define RPC_BIN_SEARCH 47
// server->client codes
#define RPC_SET_DEBUG_NAMES 50
#define RPC_SYNC_STUB 51
#define RPC_ERROR 52
#define RPC_MSG 53
#define RPC_WARNING 54
#define RPC_HANDLE_DEBUG_EVENT 55
#define RPC_REPORT_IDC_ERROR 56
#define RPC_IMPORT_DLL 57
#pragma pack(push, 1)
struct PACKED rpc_packet_t
{ // fields are always sent in the network order
uint32 length; // length of the packet (do not count length & code)
uchar code; // function code
};
CASSERT(sizeof(rpc_packet_t) == 5);
#pragma pack(pop)
enum rpc_notification_type_t
{
rnt_unknown = 0,
rnt_msg,
rnt_warning,
rnt_error,
};
#define DEFINE_ONE_NOTIFICATION_FUNCTION(FuncName, NotifCode, RpcEngineInst) \
AS_PRINTF(2, 3) void FuncName(const char *format, ...) \
{ \
va_list va; \
va_start(va, format); \
dvnotif(NotifCode, RpcEngineInst, format, va); \
va_end(va); \
}
#define DEFINE_ALL_NOTIFICATION_FUNCTIONS(RpcEngineInst) \
DEFINE_ONE_NOTIFICATION_FUNCTION(dmsg, 0, RpcEngineInst) \
DEFINE_ONE_NOTIFICATION_FUNCTION(dwarning, 1, RpcEngineInst) \
DEFINE_ONE_NOTIFICATION_FUNCTION(derror, -1, RpcEngineInst)
class rpc_engine_t;
//-------------------------------------------------------------------------
AS_PRINTF(2, 0) ssize_t dvnotif_client(
int code,
const char *format,
va_list va);
#ifdef __NT__
# define IRSERR_TIMEOUT WAIT_TIMEOUT
#else
# define IRSERR_TIMEOUT ETIME
#endif
#define IRSERR_CANCELLED -0xE5CA7E // escape
#define IRSERR_SKIP_ITER -0x5217 // skip recv() in rpc_engine_t's recv_data loop
//-------------------------------------------------------------------------
// idarpc_stream_t
//-------------------------------------------------------------------------
// the idarpc_stream_t structure is not defined.
// it is used as an opaque type provided by the transport level.
// the transport level defines its own local type for it.
struct idarpc_stream_t;
idarpc_stream_t *irs_new(bool use_tls=false);
bool irs_init_client(idarpc_stream_t *irs, const char *hostname, int port_number);
bool irs_init_server(
idarpc_stream_t *irs,
const char *hostname,
int port_number,
const char *certchain=nullptr,
const char *privkey=nullptr);
bool irs_accept(idarpc_stream_t *irs, idarpc_stream_t *listener);
bool irs_handshake(idarpc_stream_t *irs, int timeout_ms = -1);
int irs_ready(idarpc_stream_t *irs, int timeout_ms = -1);
ssize_t irs_recv(idarpc_stream_t *irs, void *buf, size_t n);
ssize_t irs_send(idarpc_stream_t *irs, const void *buf, size_t n);
void irs_term(idarpc_stream_t **pirs, int shutdown_flags = -1);
int irs_get_error(idarpc_stream_t *irs);
const char *irs_strerror(idarpc_stream_t *irs);
bool irs_peername(idarpc_stream_t *irs, qstring *out, bool lookupname = true);
bool irs_sockname(idarpc_stream_t *irs, qstring *out, bool lookupname = true);
enum progress_loop_ctrl_t
{
plc_proceed,
plc_skip_iter,
plc_cancel,
};
typedef progress_loop_ctrl_t irs_progress_cb_t(bool receiving, size_t processed, size_t total, void *);
void irs_set_progress_cb(idarpc_stream_t *irs, int ms, irs_progress_cb_t cb, void *ud=NULL);
struct irs_cancellable_op_t
{
idarpc_stream_t *irs;
irs_cancellable_op_t(idarpc_stream_t *_irs, bool receiving, size_t goal=0);
~irs_cancellable_op_t();
void inc_progress(size_t progress);
};
//-------------------------------------------------------------------------
typedef qtime64_t utc_timestamp_t;
//-------------------------------------------------------------------------
// base_dispatcher_t + client_handler_t
//-------------------------------------------------------------------------
struct client_handler_t
{
FILE *channels[16];
idarpc_stream_t *irs;
qstring peer_name;
uint32 session_id;
utc_timestamp_t session_start;
bool verbose;
void close_all_channels();
void clear_channels();
int find_free_channel() const;
client_handler_t(idarpc_stream_t *_irs, bool _verbose);
virtual ~client_handler_t();
virtual bool handle() = 0; // true - delete this
virtual void shutdown_gracefully(int signum) = 0;
//lint -sem(client_handler_t::term_irs,cleanup)
void term_irs();
AS_PRINTF(2, 3) int lprintf(const char *format, ...) const;
private:
DECLARE_UNCOPYABLE(client_handler_t);
};
//-------------------------------------------------------------------------
struct client_handlers_list_t
{
typedef std::map<client_handler_t *, qthread_t> storage_t;
storage_t storage;
virtual ~client_handlers_list_t() {}
virtual void lock() {}
virtual void unlock() {}
virtual bool is_multi_threaded() const { return false; }
};
//-------------------------------------------------------------------------
struct mt_client_handlers_list_t : public client_handlers_list_t
{
qmutex_t mutex;
mt_client_handlers_list_t() { mutex = qmutex_create(); QASSERT(1540, mutex != NULL); }
virtual ~mt_client_handlers_list_t() { qmutex_free(mutex); }
virtual void lock() override { qmutex_lock(mutex); }
virtual void unlock() override { qmutex_unlock(mutex); }
virtual bool is_multi_threaded() const override { return true; }
};
//-------------------------------------------------------------------------
struct base_dispatcher_t
{
ushort port_number;
qstring ipv4_address;
qstring certchain;
qstring privkey;
idarpc_stream_t *irs;
client_handlers_list_t *clients_list;
bool use_tls;
bool verbose;
base_dispatcher_t(bool multi_threaded);// : port_number(-1), irs(NULL), verbose(false) {}
virtual ~base_dispatcher_t();
void dispatch();
virtual void collect_cliopts(cliopts_t *out);
//
void install_signal_handlers();
//
virtual client_handler_t *new_client_handler(idarpc_stream_t *_irs) = 0;
void delete_client_handler(client_handler_t *inst);
virtual void shutdown_gracefully(int signum);
private:
void handle_session(client_handler_t *handler);
void add_to_clients_list(client_handler_t *handler, qthread_t t);
DECLARE_UNCOPYABLE(base_dispatcher_t);
};
//-------------------------------------------------------------------------
// packing/unpacking utils
//-------------------------------------------------------------------------
bytevec_t prepare_rpc_packet(uchar code);
void finalize_packet(bytevec_t &pkt);
//const char *get_rpc_name(int code);
//-------------------------------------------------------------------------
// rpc_engine_t
//-------------------------------------------------------------------------
#define VERBOSE_ENABLED
#ifdef VERBOSE_ENABLED
#define verb(x) do { if ( verbose ) msg x; } while(0)
#define verb_eng(engine, x) do { if ( (engine)->verbose ) msg x; } while(0)
#else
#define verb(x) //msg x
#define verb_eng(engine, x)
#endif
#define verbev(x) //msg x
//-------------------------------------------------------------------------
struct rpc_packet_data_t
{
uchar code;
rpc_packet_data_t(uchar _code) : code(_code) {}
virtual ~rpc_packet_data_t() {}
virtual void serialize(bytevec_t *out, int version) const = 0;
virtual bool deserialize(const uchar **ptr, size_t len, int version) = 0;
};
//-------------------------------------------------------------------------
typedef int ioctl_handler_t(
class rpc_engine_t *rpc,
int fn,
const void *buf,
size_t size,
void **poutbuf,
ssize_t *poutsize);
//-------------------------------------------------------------------------
typedef rpc_packet_data_t *rpc_packet_instantiator_t(const uchar *ptr, size_t len, int version);
//-------------------------------------------------------------------------
struct rpc_packet_type_desc_t
{
uchar code;
const char *name;
rpc_packet_instantiator_t *instantiate;
};
DECLARE_TYPE_AS_MOVABLE(rpc_packet_type_desc_t);
typedef qvector<rpc_packet_type_desc_t> rpc_packet_type_desc_vec_t;
//---------------------------------------------------------------------------
class rpc_engine_t
{
public:
bool network_error;
// pointer to the ioctl request handler, in case you
// need to handle ioctl requests from the server.
ioctl_handler_t *ioctl_handler;
int recv_timeout;
bool is_client;
bool logged_in;
protected:
void register_packet_type_descs(const rpc_packet_type_desc_t *ptypes, size_t cnt);
const rpc_packet_type_desc_t *find_packet_type_desc(int code) const;
const rpc_packet_type_desc_t *find_packet_type_desc(const char *name) const;
public:
rpc_engine_t(bool is_client);
virtual ~rpc_engine_t() {}
int handle_ioctl_packet(bytevec_t &pkt, const uchar *ptr, const uchar *end);
// low-level: deal with bytes, and don't handle "conversations".
int send_data(bytevec_t &data);
rpc_packet_t *recv_packet();
virtual rpc_packet_t *send_request_and_receive_reply(bytevec_t &pkt) = 0;
virtual idarpc_stream_t *get_irs() const = 0;
AS_PRINTF(3, 0) virtual ssize_t send_notif(int code, const char *format, va_list va);
virtual bool get_broken_connection(void) { return false; }
virtual void set_broken_connection(void) {};
int send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize);
void set_ioctl_handler(ioctl_handler_t *h) { ioctl_handler = h; }
DEFINE_ALL_NOTIFICATION_FUNCTIONS(this);
private:
rpc_packet_type_desc_vec_t ptypes;
int recv_data(void *out, size_t len);
AS_PRINTF(3,0) static ssize_t dvnotif(int code, rpc_engine_t *rpc, const char *format, va_list va);
};
//-------------------------------------------------------------------------
AS_PRINTF(3, 0) ssize_t dvnotif_rpc(
int code,
rpc_engine_t *rpc,
const char *format,
va_list va);
//---------------------------------------------------------------------------
AS_PRINTF(1, 0) int vlprintf(const char *format, va_list va);
AS_PRINTF(1, 2) int lprintf(const char *format, ...);
void set_lprintf_output(FILE *out);
//---------------------------------------------------------------------------
size_t format_timestamp(char *buf, size_t bufsize, qtime64_t ts);
#endif // NETWORK_HPP

View File

@@ -1,254 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _OFFSET_HPP
#define _OFFSET_HPP
#include <nalt.hpp>
#include <segment.hpp>
/*! \file offset.hpp
\brief Functions that deal with offsets.
"Being an offset" is a characteristic of an operand.
This means that operand or its part represent offset from
some address in the program. This linear address is called
"offset base". Some operands may have 2 offsets simultaneously.
Generally, IDA doesn't handle this except for Motorola outer offsets.
Thus there may be two offset values in an operand: simple offset and
outer offset.
Outer offsets are handled by specifying special operand number:
it should be ORed with #OPND_OUTER value.
See bytes.hpp for further explanation of operand numbers.
*/
/// Get default reference type depending on the segment.
/// \return one of ::REF_OFF8,::REF_OFF16,::REF_OFF32
idaman reftype_t ida_export get_default_reftype(ea_t ea);
/// Convert operand to a reference.
/// To delete an offset, use clr_op_type() function.
/// \param ea linear address.
/// if 'ea' has unexplored bytes, try to convert them to
/// - no segment: fail
/// - 16bit segment: to 16bit word data
/// - 32bit segment: to dword
/// \param n number of operand (may be ORed with #OPND_OUTER)
/// - 0: first
/// - 1: second
/// - 2: third
/// - #OPND_MASK: all operands
/// \param ri reference information
/// \return success
idaman bool ida_export op_offset_ex(ea_t ea, int n, const refinfo_t *ri);
/// See op_offset_ex()
idaman bool ida_export op_offset(
ea_t ea,
int n,
reftype_t type,
ea_t target=BADADDR,
ea_t base=0,
adiff_t tdelta=0);
/// Convert operand to a reference with the default reference type
inline bool op_plain_offset(ea_t ea, int n, ea_t base)
{
reftype_t reftype = get_default_reftype(ea);
return op_offset(ea, n, reftype, BADADDR, base) != 0;
}
/// Get offset base value
/// \param ea linear address
/// \param n number of operand
/// \return offset base or #BADADDR
inline ea_t get_offbase(ea_t ea, int n)
{
refinfo_t ri;
if ( !get_refinfo(&ri, ea, n) )
return BADADDR;
return ri.base;
}
/// Get offset expression (in the form "offset name+displ").
/// This function uses offset translation function (\ph{translate}) if your IDP
/// module has such a function. Translation function is used to map linear
/// addresses in the program (only for offsets).
///
/// Example: suppose we have instruction at linear address 0x00011000:
/// \v{mov ax, [bx+7422h]}
/// and at ds:7422h:
/// \v{array dw ...}
/// We want to represent the second operand with an offset expression, so
/// then we call:
/// \v{
/// get_offset_expresion(0x001100, 1, 0x001102, 0x7422, buf);
/// | | | | |
/// | | | | +output buffer
/// | | | +value of offset expression
/// | | +address offset value in the instruction
/// | +the second operand
/// +address of instruction
/// }
/// and the function will return a colored string:
/// \v{offset array}
/// \param buf output buffer to hold offset expression
/// \param ea start of instruction or data with the offset expression
/// \param n number of operand (may be ORed with #OPND_OUTER)
/// - 0: first operand
/// - 1: second operand
/// \param from linear address of instruction operand or data referring to
/// the name. This address will be used to get fixup information,
/// so it should point to exact position of operand in the
/// instruction.
/// \param offset value of operand or its part. The function will return
/// text representation of this value as offset expression.
/// \param getn_flags combination of:
/// - #GETN_APPZERO: meaningful only if the name refers to
/// a structure. appends the struct field name
/// if the field offset is zero
/// - #GETN_NODUMMY: do not generate dummy names for the expression
/// but pretend they already exist
/// (useful to verify that the offset expression
/// can be represented)
/// \retval 0 can't convert to offset expression
/// \retval 1 ok, a simple offset expression
/// \retval 2 ok, a complex offset expression
idaman int ida_export get_offset_expression(
qstring *buf,
ea_t ea,
int n,
ea_t from,
adiff_t offset,
int getn_flags=0);
/// See get_offset_expression()
idaman int ida_export get_offset_expr(
qstring *buf,
ea_t ea,
int n,
const refinfo_t &ri,
ea_t from,
adiff_t offset,
int getn_flags=0);
/// Does the specified address contain a valid OFF32 value?.
/// For symbols in special segments the displacement is not taken into account.
/// If yes, then the target address of OFF32 will be returned.
/// If not, then #BADADDR is returned.
idaman ea_t ida_export can_be_off32(ea_t ea);
/// Try to calculate the offset base
/// This function takes into account the fixup information,
/// current ds and cs values.
/// \param ea the referencing instruction/data address
/// \param n operand number
/// - 0: first operand
/// - 1: other operand
/// \return output base address or #BADADDR
idaman ea_t ida_export calc_offset_base(ea_t ea, int n);
/// Try to calculate the offset base.
/// 2 bases are checked: current ds and cs.
/// If fails, return #BADADDR
idaman ea_t ida_export calc_probable_base_by_value(ea_t ea, uval_t off);
/// Calculate the target and base addresses of an offset expression.
/// The calculated target and base addresses are returned in the locations
/// pointed by 'base' and 'target'. In case 'ri.base' is #BADADDR, the
/// function calculates the offset base address from the referencing
/// instruction/data address.
/// The target address is copied from ri.target. If ri.target is #BADADDR
/// then the target is calculated using the base address and 'opval'.
/// This function also checks if 'opval' matches the full value of the
/// reference and takes in account the memory-mapping.
/// \param target output target address
/// \param base output base address
/// \param from the referencing instruction/data address
/// \param ri reference info block from the database
/// \param opval operand value (usually op_t::value or op_t::addr)
/// \return success
idaman bool ida_export calc_reference_data(
ea_t *target,
ea_t *base,
ea_t from,
const refinfo_t &ri,
adiff_t opval);
/// Add xrefs for a reference from the given instruction (\insn_t{ea}).
/// This function creates a cross references to the target and the base.
/// insn_t::add_off_drefs() calls this function to create xrefs for
/// 'offset' operand.
/// \param insn the referencing instruction
/// \param from the referencing instruction/data address
/// \param ri reference info block from the database
/// \param opval operand value (usually op_t::value or op_t::addr)
/// \param type type of xref
/// \param opoff offset of the operand from the start of instruction
/// \return the target address of the reference
idaman ea_t ida_export add_refinfo_dref(
const insn_t &insn,
ea_t from,
const refinfo_t &ri,
adiff_t opval,
dref_t type,
int opoff);
/// Calculates the target, using the provided refinfo_t
inline ea_t calc_target(ea_t from, adiff_t opval, const refinfo_t &ri)
{
ea_t target;
if ( !calc_reference_data(&target, NULL, from, ri, opval) )
return BADADDR;
return target;
}
/// Retrieves refinfo_t structure and calculates the target
inline ea_t calc_target(ea_t from, ea_t ea, int n, adiff_t opval)
{
refinfo_t ri;
return get_refinfo(&ri, ea, n) ? calc_target(from, opval, ri) : BADADDR;
}
/// Calculate the value of the reference base.
inline ea_t calc_basevalue(ea_t target, ea_t base)
{
return base - get_segm_base(getseg(target));
}
#endif // _OFFSET_HPP

View File

@@ -1,233 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef PARSEJSON_HPP
#define PARSEJSON_HPP
/*! \file parsejson.hpp
\brief Tools for parsing JSON-formatted input
See also lex.hpp/parse.hpp for finer-grained functions & documentation.
*/
#include <lex.hpp>
//---------------------------------------------------------------------------
enum jtype_t
{
JT_UNKNOWN = 0,
JT_NUM,
JT_STR,
JT_OBJ,
JT_ARR,
JT_BOOL,
};
//---------------------------------------------------------------------------
struct jobj_t;
struct jarr_t;
#define DECLARE_JVALUE_HELPERS(decl) \
decl void ida_export jvalue_t_clear(jvalue_t *); \
decl void ida_export jvalue_t_copy(jvalue_t *, const jvalue_t &);
struct jvalue_t;
DECLARE_JVALUE_HELPERS(idaman)
//-------------------------------------------------------------------------
struct jvalue_t
{
jvalue_t() : _type(JT_UNKNOWN), _num(0) {}
jvalue_t(const jvalue_t &o) : _type(JT_UNKNOWN) { jvalue_t_copy(this, o); }
~jvalue_t() { clear(); }
void clear() { jvalue_t_clear(this); }
jvalue_t &operator=(const jvalue_t &o) { jvalue_t_copy(this, o); return *this; }
jtype_t type() const { return _type; }
int64 num() const { QASSERT(1277, _type == JT_NUM); return _num; }
const char *str() const { QASSERT(1278, _type == JT_STR); return _str->c_str(); }
const qstring &qstr() const { QASSERT(1623, _type == JT_STR); return *_str; }
const jobj_t &obj() const { QASSERT(1279, _type == JT_OBJ); return *_obj; }
const jarr_t &arr() const { QASSERT(1280, _type == JT_ARR); return *_arr; }
bool vbool() const { QASSERT(1281, _type == JT_BOOL); return _bool; }
jobj_t &obj() { QASSERT(1282, _type == JT_OBJ); return *_obj; }
jarr_t &arr() { QASSERT(1283, _type == JT_ARR); return *_arr; }
//lint -sem(jvalue_t::set_str, custodial(1)) function takes ownership of its argument
//lint -sem(jvalue_t::set_obj, custodial(1)) function takes ownership of its argument
//lint -sem(jvalue_t::set_arr, custodial(1)) function takes ownership of its argument
void set_num(int64 i) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_NUM; _num = i; }
void set_str(qstring *s) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_STR; _str = s; }
void set_obj(jobj_t *o) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_OBJ; _obj = o; }
void set_arr(jarr_t *a) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_ARR; _arr = a; }
void set_bool(bool b) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_BOOL; _bool = b; }
jobj_t *extract_obj() { QASSERT(1624, _type == JT_OBJ); jobj_t *o = _obj; _obj = NULL; _type = JT_UNKNOWN; return o; }
jarr_t *extract_arr() { QASSERT(1625, _type == JT_ARR); jarr_t *a = _arr; _arr = NULL; _type = JT_UNKNOWN; return a; }
private:
DECLARE_JVALUE_HELPERS(friend)
jtype_t _type;
union
{
int64 _num;
qstring *_str;
jobj_t *_obj;
jarr_t *_arr;
bool _bool;
};
};
DECLARE_TYPE_AS_MOVABLE(jvalue_t);
typedef qvector<jvalue_t> jvalues_t;
//---------------------------------------------------------------------------
struct kvp_t
{
qstring key;
jvalue_t value;
};
DECLARE_TYPE_AS_MOVABLE(kvp_t);
//-------------------------------------------------------------------------
struct jobj_t : public qvector<kvp_t>
{
bool has_value(const char *k) const { return get_value(k) != NULL; }
jvalue_t *get_value(const char *k, jtype_t t=JT_UNKNOWN)
{
jvalue_t *v = NULL;
for ( size_t i = 0, _n = size(); i < _n; ++i )
{
if ( at(i).key == k )
{
if ( t == JT_UNKNOWN || at(i).value.type() == t )
v = &at(i).value;
break;
}
}
return v;
}
const jvalue_t *get_value(const char *k, jtype_t t=JT_UNKNOWN) const
{
return ((jobj_t *) this)->get_value(k, t);
}
const jvalue_t *get_value_or_fail(const char *k, jtype_t t=JT_UNKNOWN) const
{
const jvalue_t *v = get_value(k, t);
QASSERT(1289, v != NULL);
return v;
}
jvalue_t *get_value_or_new(const char *key)
{
jvalue_t *v = get_value(key);
if ( v == NULL )
{
kvp_t &kvp = push_back();
kvp.key = key;
v = &kvp.value;
}
return v;
}
int64 get_num(const char *k) const { return get_value_or_fail(k)->num(); }
bool get_bool(const char *k) const { return get_value_or_fail(k)->vbool(); }
const char *get_str(const char *k) const { return get_value_or_fail(k)->str(); }
const jobj_t &get_obj(const char *k) const { return get_value_or_fail(k)->obj(); }
const jarr_t &get_arr(const char *k) const { return get_value_or_fail(k)->arr(); }
#define DEFINE_FLAG_GETTER(Type, JType, GetExpr) \
bool get(Type *out, const char *k) const \
{ \
const jvalue_t *v = get_value(k, JType); \
bool ok = v != NULL; \
if ( ok ) \
*out = GetExpr; \
return ok; \
}
#define DEFINE_DFLT_GETTER(Type, JType, GetExpr) \
Type get(const char *k, Type dflt) const \
{ \
const jvalue_t *v = get_value(k, JType); \
return v != NULL ? GetExpr : dflt; \
}
#define DEFINE_SETTER(Type, SetExpr) \
void put(const char *key, Type value) \
{ \
jvalue_t *v = get_value_or_new(key); \
SetExpr; \
}
#define DEFINE_ACCESSORS(Type, ConstType, JType, GetExpr, SetExpr) \
DEFINE_FLAG_GETTER(ConstType, JType, GetExpr) \
DEFINE_DFLT_GETTER(ConstType, JType, GetExpr) \
DEFINE_SETTER(Type, SetExpr)
DEFINE_ACCESSORS(int, int, JT_NUM, v->num(), v->set_num(value));
DEFINE_ACCESSORS(int64, int64, JT_NUM, v->num(), v->set_num(value));
DEFINE_ACCESSORS(bool, bool, JT_BOOL, v->vbool(), v->set_bool(value));
DEFINE_ACCESSORS(jarr_t *, const jarr_t *, JT_ARR, &v->arr(), v->set_arr(value)); // setter takes ownership
DEFINE_ACCESSORS(jobj_t *, const jobj_t *, JT_OBJ, &v->obj(), v->set_obj(value)); // setter takes ownership
DEFINE_ACCESSORS(const char *, const char *, JT_STR, v->str(), v->set_str(new qstring(value)));
#undef DEFINE_ACCESSORS
#undef DEFINE_SETTER
#undef DEFINE_DFLT_GETTER
#undef DEFINE_FLAG_GETTER
};
DECLARE_TYPE_AS_MOVABLE(jobj_t);
//---------------------------------------------------------------------------
struct jarr_t
{
jvalues_t values;
size_t count_items_with_type(jtype_t t) const
{
size_t cnt = 0;
for ( size_t i = 0, n = values.size(); i < n; ++i )
if ( values[i].type() == t )
++cnt;
return cnt;
}
bool is_homogeneous(jtype_t t) const
{
return count_items_with_type(t) == values.size();
}
};
DECLARE_TYPE_AS_MOVABLE(jarr_t);
//---------------------------------------------------------------------------
// Note: If 'ungot_tokens' is not NULL, its contents will be used before fetching tokens from the lexer
idaman THREAD_SAFE error_t ida_export parse_json(jvalue_t *out, lexer_t *lx, tokenstack_t *ungot_tokens = NULL);
idaman THREAD_SAFE error_t ida_export parse_json_string(jvalue_t *out, const char *s);
//-------------------------------------------------------------------------
#define SJF_PRETTY 0x1
idaman THREAD_SAFE bool ida_export serialize_json(
qstring *out,
const jvalue_t &v,
uint32 flags=0);
inline THREAD_SAFE bool serialize_json(
qstring *out,
const jobj_t *o,
uint32 flags=0)
{
jvalue_t v;
v.set_obj((jobj_t *) o);
bool rc = serialize_json(out, v, flags);
v.extract_obj();
return rc;
}
#endif // PARSEJSON_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -1,104 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _PROBLEMS_HPP
#define _PROBLEMS_HPP
/*! \file problems.hpp
\brief Functions that deal with the list of problems.
There are several problem lists. An address may be inserted to any list.
The kernel simply maintains these lists, no additional processing
is done.
The problem lists are accessible for the user
from the View->Subviews->Problems menu item.
Addresses in the lists are kept sorted. In general IDA just maintains
these lists without using them during analysis (except PR_ROLLED).
*/
typedef uchar problist_id_t; ///< see \ref PR_
/// \defgroup PR_ Problem types
//@{
const problist_id_t
PR_NOBASE = 1, ///< Can't find offset base
PR_NONAME = 2, ///< Can't find name
PR_NOFOP = 3, ///< Can't find forced op (not used anymore)
PR_NOCMT = 4, ///< Can't find comment (not used anymore)
PR_NOXREFS = 5, ///< Can't find references
PR_JUMP = 6, ///< Jump by table !!!! ignored
PR_DISASM = 7, ///< Can't disasm
PR_HEAD = 8, ///< Already head
PR_ILLADDR = 9, ///< Exec flows beyond limits
PR_MANYLINES = 10, ///< Too many lines
PR_BADSTACK = 11, ///< Failed to trace the value of the stack pointer
PR_ATTN = 12, ///< Attention! Probably erroneous situation.
PR_FINAL = 13, ///< Decision to convert to instruction/data is made by IDA
PR_ROLLED = 14, ///< The decision made by IDA was wrong and rolled back
PR_COLLISION = 15, ///< FLAIR collision: the function with the given name already exists
PR_DECIMP = 16, ///< FLAIR match indecision: the patterns matched, but not the function(s) being referenced
PR_END = 17; ///< Number of problem types
//@}
/// Get the human-friendly description of the problem,
/// if one was provided to remember_problem.
/// \param buf a buffer to store the message into.
/// \param t problem list type.
/// \param ea linear address.
/// \return the message length or -1 if none
idaman ssize_t ida_export get_problem_desc(qstring *buf, problist_id_t t, ea_t ea);
/// Insert an address to a list of problems.
/// Display a message saying about the problem (except of ::PR_ATTN,::PR_FINAL)
/// ::PR_JUMP is temporarily ignored.
/// \param type problem list type
/// \param ea linear address
/// \param msg a user-friendly message to be displayed instead of
/// the default more generic one associated with
/// the type of problem. Defaults to NULL.
idaman void ida_export remember_problem(problist_id_t type, ea_t ea, const char *msg = NULL);
/// Get an address from the specified problem list.
/// The address is not removed from the list.
/// \param type problem list type
/// \param lowea the returned address will be higher or equal
/// than the specified address
/// \return linear address or #BADADDR
idaman ea_t ida_export get_problem(problist_id_t type, ea_t lowea);
/// Remove an address from a problem list
/// \param type problem list type
/// \param ea linear address
/// \return success
idaman bool ida_export forget_problem(problist_id_t type, ea_t ea);
/// Get problem list description
idaman const char *ida_export get_problem_name(problist_id_t type, bool longname=true);
/// Check if the specified address is present in the problem list
idaman bool ida_export is_problem_present(problist_id_t t, ea_t ea);
inline bool was_ida_decision(ea_t ea) { return is_problem_present(PR_FINAL, ea); }
#endif // _PROBLEMS_HPP

View File

@@ -1,172 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _PRODIR_H
#define _PRODIR_H
//-V:qffblk_t:730 not all members of a class are initialized inside the constructor
//-V:qffblk64_t:730
/*! \file prodir.h
\brief Unified interface to qfindfirst(),qfindnext(),qfindclose() functions.
These are low level functions, it is better to use enumerate_files2().
*/
/// \def{DIRCHAR, Path separator}
/// \def{SDIRCHAR, Path separator as a string}
/// \def{DRVCHAR, Windows drive separator}
#ifdef __NT__
#define __FAT__
#define SDIRCHAR "\\"
#define DIRCHAR '\\'
#define DRVCHAR ':'
#else
#define SDIRCHAR "/"
#define DIRCHAR '/'
#endif
/// Extension character is '.' for all systems
#define EXTCHAR '.'
//----------------------------------------------------------------------------
/// \struct{qffblk_t, Various file statistics returned by qfind()-like functions}
/// \var{qffblk_t::ff_name, file path}
/// \var{qffblk_t::ff_fsize, file size}
/// \var{qffblk_t::ff_attrib, file attribute}
/// \var{qffblk_t::ff_ftime, file time stamp (ms dos fat format)}
/// \var{qffblk_t::ff_fdate, file date stamp (ms dos fat format)}
/// \def{FA_RDONLY, File cannot be opened for writing}
/// \def{FA_DIREC, Directory}
/// \def{FA_ARCH, File has not been backed up}
/// \def{MAXPATH, Size limit of qffblk_t::ff_name}
#if defined(__UNIX__)
#define MAXPATH QMAXPATH
struct qffblk_t // Unix
{
// user fields:
int ff_attrib;
#define FA_DIREC S_IFDIR
#define FA_ARCH 0
#define FA_RDONLY 0
char ff_name[QMAXPATH];
uint32 ff_fsize;
uint16 ff_fdate;
uint16 ff_ftime;
// private fields:
void *filelist;
int fileidx, fileqty;
char dirpath[QMAXPATH];
char pattern[QMAXPATH];
int attr;
qffblk_t(void) : filelist(NULL), fileqty(0) {}
};
#elif !defined(__X86__)
// Win64 - use Visual Studio's ffblk
#define MAXPATH _MAX_PATH
struct qffblk_t
{
// inlined __finddata64_t from Visual Studio (for compatibility with IDA 7.0 API)
unsigned attrib;
// Time values are stored in UTC format.
__time64_t time_create; // -1 for FAT file systems
__time64_t time_access; // -1 for FAT file systems
__time64_t time_write;
__int64 size;
char name[260]; // NB: file name is assumed to be UTF-8
intptr_t handle; // handle returned by _wfindfirst64
int attr; // attr value passed to qfindfirst. only FA_DIREC is checked
#define FA_RDONLY 0x01
#define FA_DIREC 0x10
#define FA_ARCH 0x20
#define ff_name name
#define ff_attrib attrib
#define ff_fsize size
unsigned short ff_ftime; // FAT/DOS format modification time
unsigned short ff_fdate; // FAT/DOS format modification date
qffblk_t(void) : handle(-1) {}
};
CASSERT(sizeof(qffblk_t) == 0x140);
#else
#define MAXPATH 260
struct qffblk_t // Win32 - use Borland's ffblk (IDA 6.95 API compatibility)
{
long ff_reserved;
long ff_fsize;
unsigned long ff_attrib;
#define FA_RDONLY 0x01
#define FA_DIREC 0x10
#define FA_ARCH 0x20
unsigned short ff_ftime;
unsigned short ff_fdate;
char ff_name[MAXPATH];
qffblk_t(void) : ff_reserved(0) {}
};
#endif
/// \def{MAXDRIVE, Max drive name size}
/// \def{MAXDIR, Max directory name size}
/// \def{MAXFILE, Max file name size}
/// \def{MAXEXT, Max file extension size}
#if defined(__UNIX__)
#define MAXDRIVE QMAXPATH
#define MAXDIR QMAXPATH
#define MAXFILE QMAXPATH
#define MAXEXT QMAXPATH
#else
#define MAXDRIVE _MAX_DRIVE
#define MAXDIR _MAX_DIR
#define MAXFILE _MAX_FNAME
#define MAXEXT _MAX_EXT
#endif
/// Find first file that matches the pattern.
/// \param pattern file name pattern, usually with * and ? wildcards
/// \param blk structure that will hold the answer.
/// blk->ff_name will hold the file name, for example.
/// \param attr the desired file types (#FA_DIREC for directories only or 0 for both directories and files)
/// \return 0 if found a file, other values mean error (check qerrno)
idaman THREAD_SAFE int ida_export qfindfirst(
const char *pattern,
struct qffblk64_t *blk,
int attr);
/// Find next file that matches the pattern.
/// \param blk structure that holds the current state.
/// blk->ff_name will hold the next file name upon return.
/// \return 0 if found the next file, other values mean error (check qerrno)
idaman THREAD_SAFE int ida_export qfindnext(struct qffblk64_t *blk);
/// Stop the file enumeration and free internal structures.
/// \note usually there is no need to call this function manually, it is called
/// from the ::qffblk64_t destructor.
/// \param blk file enumeration structure
idaman THREAD_SAFE void ida_export qfindclose(struct qffblk64_t *blk);
/// Common structure with 64-bit ff_fsize - see ::qffblk_t.
struct qffblk64_t
{
int ff_attrib;
char ff_name[QMAXPATH];
uint64 ff_fsize;
uint16 ff_fdate;
uint16 ff_ftime;
// private field
struct qffblk_t base;
qffblk64_t(void) {}
~qffblk64_t(void) { qfindclose(this); }
};
#endif // _PRODIR_H

View File

@@ -1,295 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _RANGE_HPP
#define _RANGE_HPP
/*! \file range.hpp
\brief Contains the definition of ::rangecb_t.
This is a base class used by many parts of IDA.
It is a collection of address ranges in the program.
It conceptually consists of separate ::range_t instances.
A range is a non-empty continuous range of addresses (specified by
its start and end addresses, the end address is excluded from the
range) with some characteristics. For example, the ensemble of program
segments is represented by an "rangecb_t" called "segs".
Ranges are stored in the Btree part of the IDA database.
To learn more about Btrees (Balanced Trees):
http://www.bluerwhite.org/btree/
*/
#ifndef SWIG
struct range_t;
/// Helper function. Should not be called directly!
idaman size_t ida_export range_t_print(const range_t *, char *buf, size_t bufsize);
#endif
//--------------------------------------------------------------------------
/// Base class for an range. This class is used as a base class for
/// a class with real information - see segment.hpp for example.
/// The end address points beyond the range.
struct range_t
{
friend size_t ida_export range_t_print(const range_t *cb, char *buf, size_t bufsize);
ea_t start_ea; ///< start_ea included
ea_t end_ea; ///< end_ea excluded
/// Constructor
range_t(void) : start_ea(0), end_ea(0) {}
/// Constructor
range_t(ea_t ea1, ea_t ea2) : start_ea(ea1), end_ea(ea2) {}
/// Compare two range_t instances, based on the start_ea
int compare(const range_t &r) const { return start_ea > r.start_ea ? 1 : start_ea < r.start_ea ? -1 : 0; }
bool operator ==(const range_t &r) const { return compare(r) == 0; } ///< Compare two range_t's with '=='
bool operator !=(const range_t &r) const { return compare(r) != 0; } ///< Compare two range_t's with '!='
bool operator > (const range_t &r) const { return compare(r) > 0; } ///< Compare two range_t's with '<'
bool operator < (const range_t &r) const { return compare(r) < 0; } ///< Compare two range_t's with '>'
/// Is 'ea' in the address range?
bool contains(ea_t ea) const { return start_ea <= ea && end_ea > ea; }
/// Is every ea in 'r' also in this range_t?
bool contains(const range_t &r) const { return r.start_ea >= start_ea && r.end_ea <= end_ea; }
/// Is there an ea in 'r' that is also in this range_t?
bool overlaps(const range_t &r) const { return r.start_ea < end_ea && start_ea < r.end_ea; }
/// Set #start_ea, #end_ea to 0
void clear(void) { start_ea = end_ea = 0; }
/// Is the size of the range_t <= 0?
bool empty(void) const { return start_ea >= end_ea; }
/// Get #end_ea - #start_ea
asize_t size(void) const { return end_ea - start_ea; }
/// Assign the range_t to the intersection between the range_t and 'r'
void intersect(const range_t &r)
{
if ( start_ea < r.start_ea )
start_ea = r.start_ea;
if ( end_ea > r.end_ea )
end_ea = r.end_ea;
if ( end_ea < start_ea )
end_ea = start_ea;
}
/// Ensure that the range_t includes 'ea'
void extend(ea_t ea)
{
if ( start_ea > ea )
start_ea = ea;
if ( end_ea < ea )
end_ea = ea;
}
/// Print the range_t.
/// \param buf the output buffer
/// \param bufsize the size of the buffer
size_t print(char *buf, size_t bufsize) const { return range_t_print(this, buf, bufsize); }
};
DECLARE_TYPE_AS_MOVABLE(range_t);
typedef qvector<range_t> rangevec_base_t;
struct rangevec_t : public rangevec_base_t /// Vector of range_t instances
{
};
//--------------------------------------------------------------------------
// Various kinds of ranges, see
// \ref idb_event::changing_range_cmt
// \ref idb_event::range_cmt_changed
enum range_kind_t
{
RANGE_KIND_UNKNOWN,
RANGE_KIND_FUNC, ///< \ref func_t
RANGE_KIND_SEGMENT, ///< \ref segment_t
RANGE_KIND_HIDDEN_RANGE, ///< \ref hidden_range_t
};
//--------------------------------------------------------------------------
/// Helper functions. Should not be called directly!
#ifndef SWIG
#define RANGESET_HELPER_DEFINITIONS(decl) \
decl bool ida_export rangeset_t_add(rangeset_t *, const range_t &range);\
decl bool ida_export rangeset_t_sub(rangeset_t *, const range_t &range);\
decl bool ida_export rangeset_t_add2(rangeset_t *, const rangeset_t &aset);\
decl bool ida_export rangeset_t_sub2(rangeset_t *, const rangeset_t &aset);\
decl bool ida_export rangeset_t_has_common(const rangeset_t *, const range_t &range, bool strict);\
decl bool ida_export rangeset_t_has_common2(const rangeset_t *, const rangeset_t &aset);\
decl bool ida_export rangeset_t_contains(const rangeset_t *, const rangeset_t &aset);\
decl size_t ida_export rangeset_t_print(const rangeset_t *, char *buf, size_t bufsize);\
decl bool ida_export rangeset_t_intersect(rangeset_t *, const rangeset_t &aset);\
decl const range_t *ida_export rangeset_t_find_range(const rangeset_t *, ea_t ea);\
decl ea_t ida_export rangeset_t_next_addr(const rangeset_t *, ea_t ea);\
decl ea_t ida_export rangeset_t_prev_addr(const rangeset_t *, ea_t ea);\
decl ea_t ida_export rangeset_t_next_range(const rangeset_t *, ea_t ea);\
decl ea_t ida_export rangeset_t_prev_range(const rangeset_t *, ea_t ea);\
decl rangevec_t::const_iterator ida_export rangeset_t_lower_bound(const rangeset_t *, ea_t ea);\
decl rangevec_t::const_iterator ida_export rangeset_t_upper_bound(const rangeset_t *, ea_t ea);\
decl void ida_export rangeset_t_swap(rangeset_t *, rangeset_t &r);
#else
#define RANGESET_HELPER_DEFINITIONS(decl)
#endif // SWIG
class rangeset_t;
RANGESET_HELPER_DEFINITIONS(idaman)
/// An ordered set of non-overlapping address ranges
class rangeset_t
{
rangevec_t bag;
mutable const range_t *cache;
int undo_code = -1;
RANGESET_HELPER_DEFINITIONS(friend)
bool verify(void) const;
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
/// Constructor
rangeset_t(void) : cache(NULL) {}
/// Constructor - Initialize set with 'range'
rangeset_t(const range_t &range): cache(NULL) { if ( !range.empty() ) bag.push_back(range); }
/// Constructor - Initialize set with 'ivs'
rangeset_t(const rangeset_t &ivs) : bag(ivs.bag), cache(NULL) {}
rangeset_t &operator=(const rangeset_t &ivs) { bag = ivs.bag; cache = NULL; return *this; }
/// Set this = 'r' and 'r' = this. See qvector::swap()
void swap(rangeset_t &r) { rangeset_t_swap(this, r); }
/// Add an address range to the set.
/// If 'range' intersects an existing element e, then e is extended
/// to include 'range', and any superfluous elements (subsets of e) are removed.
/// \param range address range to add. cannot be empty
/// \return false if 'range' was not added (the set was unchanged)
bool add(const range_t &range) { return rangeset_t_add(this, range); }
/// Create a new range_t from 'start' and 'end' and add it to the set
bool add(ea_t start, ea_t _end) { return add(range_t(start, _end)); }
/// Add each element of 'aset' to the set.
/// \return false if no elements were added (the set was unchanged)
bool add(const rangeset_t &aset) { return rangeset_t_add2(this, aset); }
/// Subtract an address range from the set.
/// All subsets of 'range' will be removed, and all elements that intersect
/// 'range' will be truncated/split so they do not include 'range'.
/// \param range address range to subtract. cannot be empty.
/// \return false if 'range' was not subtracted (the set was unchanged)
bool sub(const range_t &range) { return rangeset_t_sub(this, range); }
/// Subtract an ea (an range of size 1) from the set. See sub(const range_t &)
bool sub(ea_t ea) { return sub(range_t(ea, ea+1)); }
/// Subtract each range in 'aset' from the set
/// \return false if nothing was subtracted (the set was unchanged)
bool sub(const rangeset_t &aset) { return rangeset_t_sub2(this, aset); }
/// Is there an ea in 'range' that is also in the rangeset?
bool has_common(const range_t &range) const
{ return rangeset_t_has_common(this, range, false); }
/// Is every ea in 'range' contained in the rangeset?
bool includes(const range_t &range) const
{ return rangeset_t_has_common(this, range, true); }
/// Print each range_t in the rangeset
size_t print(char *buf, size_t bufsize) const
{ return rangeset_t_print(this, buf, bufsize); }
/// Size in bytes
asize_t count(void) const;
/// Get the range_t at index 'idx'
const range_t &getrange(int idx) const { return bag[idx]; }
/// Get the last range_t in the set
const range_t &lastrange(void) const { return bag.back(); }
/// Get the number of range_t elements in the set
size_t nranges(void) const { return bag.size(); }
/// Does the set have zero elements
bool empty(void) const { return bag.empty(); }
/// Delete all elements from the set. See qvector::clear()
void clear(void) { bag.clear(); cache = NULL; }
/// Does any element of 'aset' overlap with an element in this rangeset?. See range_t::overlaps()
bool has_common(const rangeset_t &aset) const
{ return rangeset_t_has_common2(this, aset); }
/// Does an element of the rangeset contain 'ea'? See range_t::contains(ea_t)
bool contains(ea_t ea) const { return !empty() && find_range(ea) != NULL; }
/// Is every element in 'aset' contained in an element of this rangeset?. See range_t::contains(range_t)
bool contains(const rangeset_t &aset) const
{ return rangeset_t_contains(this, aset); }
/// Set the rangeset to its intersection with 'aset'.
/// \return false if the set was unchanged
bool intersect(const rangeset_t &aset)
{ return rangeset_t_intersect(this, aset); }
/// Is every element in the rangeset contained in an element of 'aset'?
bool is_subset_of(const rangeset_t &aset) const { return aset.contains(*this); }
/// Do this rangeset and 'aset' have identical elements?
bool is_equal(const rangeset_t &aset) const { return bag == aset.bag; }
bool operator==(const rangeset_t &aset) const { return is_equal(aset); } ///< Compare two rangesets with '=='
bool operator!=(const rangeset_t &aset) const { return !is_equal(aset); } ///< Compare two rangesets with '!='
typedef rangevec_t::iterator iterator; ///< Iterator for rangesets
typedef rangevec_t::const_iterator const_iterator; ///< Const iterator for rangesets
const_iterator begin(void) const { return bag.begin(); } ///< Get an iterator that points to the first element in the set
const_iterator end(void) const { return bag.end(); } ///< Get an iterator that points to the end of the set. (This is NOT the last element)
iterator begin(void) { return bag.begin(); } ///< \copydoc begin
iterator end(void) { return bag.end(); } ///< \copydoc end
/// Get the first range that contains at least one ea_t value greater than 'ea'
const_iterator lower_bound(ea_t ea) const { return rangeset_t_lower_bound(this, ea); }
/// Get the first range such that every ea_t value in this range is strictly greater than 'ea'
const_iterator upper_bound(ea_t ea) const { return rangeset_t_upper_bound(this, ea); }
/// Get the element from the set that contains 'ea'.
/// \return NULL if there is no such element
const range_t *find_range(ea_t ea) const
{ return rangeset_t_find_range(this, ea); }
/// When searching the rangeset, we keep a cached element to help speed up searches.
/// \return a pointer to the cached element
const range_t *cached_range(void) const { return cache; }
/// Get the smallest ea_t value greater than 'ea' contained in the rangeset
ea_t next_addr(ea_t ea) const { return rangeset_t_next_addr(this, ea); }
/// Get the largest ea_t value less than 'ea' contained in the rangeset
ea_t prev_addr(ea_t ea) const { return rangeset_t_prev_addr(this, ea); }
/// Get the smallest ea_t value greater than 'ea' that is not in the same range as 'ea'
ea_t next_range(ea_t ea) const { return rangeset_t_next_range(this, ea); }
/// Get the largest ea_t value less than 'ea' that is not in the same range as 'ea'
ea_t prev_range(ea_t ea) const { return rangeset_t_prev_range(this, ea); }
/// Subtract the address range (from, from+size) and add the range (to, to+size)
int move_chunk(ea_t from, ea_t to, asize_t size);
/// TODO: return code borrowed from va.hpp, same with move_chunk()
int check_move_args(ea_t from, ea_t to, asize_t size);
};
DECLARE_TYPE_AS_MOVABLE(rangeset_t);
typedef qvector<rangeset_t> array_of_rangesets; ///< Array of rangeset_t objects
typedef qvector<const rangeset_t*> rangeset_crefvec_t;
#endif // _RANGE_HPP

View File

@@ -1,240 +0,0 @@
/*************************************************
* Perl-Compatible Regular Expressions *
*************************************************/
/* PCRE2 is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
#ifndef _REGEX_H_
#define _REGEX_H_
#ifdef __cplusplus
#include <map>
#include <kernwin.hpp>
#endif
#include <pro.h>
#ifdef __GNUC__
#undef __P
#endif
typedef off_t regoff_t;
/* The structure representing a compiled regular expression. */
struct regex_t
{
int re_magic;
size_t re_nsub; /* number of parenthesized subexpressions */
const char *re_endp; /* end pointer for REG_PEND */
void *re_g; /* none of your business :-) */
};
/* The structure in which a captured offset is returned. */
struct regmatch_t
{
regoff_t rm_so; /* start of match */
regoff_t rm_eo; /* end of match */
};
#ifndef REG_ICASE
/* Options, mostly defined by POSIX, but with some extras. */
#define REG_ICASE 0x0001 /* Maps to PCRE2_CASELESS */
#define REG_NEWLINE 0x0002 /* Maps to PCRE2_MULTILINE */
#define REG_NOTBOL 0x0004 /* Maps to PCRE2_NOTBOL */
#define REG_NOTEOL 0x0008 /* Maps to PCRE2_NOTEOL */
#define REG_DOTALL 0x0010 /* NOT defined by POSIX; maps to PCRE2_DOTALL */
#define REG_NOSUB 0x0020 /* Maps to PCRE2_NO_AUTO_CAPTURE */
#define REG_UTF 0x0040 /* NOT defined by POSIX; maps to PCRE2_UTF */
#define REG_STARTEND 0x0080 /* BSD feature: pass subject string by so,eo */
#define REG_NOTEMPTY 0x0100 /* NOT defined by POSIX; maps to PCRE2_NOTEMPTY */
#define REG_UNGREEDY 0x0200 /* NOT defined by POSIX; maps to PCRE2_UNGREEDY */
#define REG_UCP 0x0400 /* NOT defined by POSIX; maps to PCRE2_UCP */
/* This is not used by PCRE2, but by defining it we make it easier
to slot PCRE2 into existing programs that make POSIX calls. */
#define REG_EXTENDED 0
#define REG_TRACE 0 // unsupported by PCRE2
/* Error values. Not all these are relevant or used by the wrapper. */
enum
{
REG_ASSERT = 1, /* internal error ? */
REG_BADBR, /* invalid repeat counts in {} */
REG_BADPAT, /* pattern error */
REG_BADRPT, /* ? * + invalid */
REG_EBRACE, /* unbalanced {} */
REG_EBRACK, /* unbalanced [] */
REG_ECOLLATE, /* collation error - not relevant */
REG_ECTYPE, /* bad class */
REG_EESCAPE, /* bad escape sequence */
REG_EMPTY, /* empty expression */
REG_EPAREN, /* unbalanced () */
REG_ERANGE, /* bad range inside [] */
REG_ESIZE, /* expression too big */
REG_ESPACE, /* failed to get memory */
REG_ESUBREG, /* bad back reference */
REG_INVARG, /* bad argument */
REG_NOMATCH /* match failed */
};
#endif //REG_ICASE
/* The functions */
// compile the regular expression
idaman THREAD_SAFE int ida_export qregcomp(
struct regex_t *preg,
const char *pattern,
int cflags);
// mapping from error codes returned by qregcomp() and qregexec() to a string
idaman THREAD_SAFE size_t ida_export qregerror(
int errcode,
const struct regex_t *preg,
char *errbuf,
size_t errbuf_size);
// match regex against a string
idaman THREAD_SAFE int ida_export qregexec(
const struct regex_t *preg,
const char *str,
size_t nmatch,
struct regmatch_t pmatch[],
int eflags);
// free any memory allocated by qregcomp
idaman THREAD_SAFE void ida_export qregfree(struct regex_t *preg);
#ifdef __cplusplus
//-------------------------------------------------------------------------
class refcnted_regex_t : public qrefcnt_obj_t
{
regex_t regex;
refcnted_regex_t()
{
regex = {};
}
virtual ~refcnted_regex_t()
{
qregfree(&regex);
}
public:
virtual void idaapi release(void) override
{
delete this;
}
int exec(const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
{
return qregexec(&regex, string, nmatch, pmatch, eflags);
}
int process_errors(int code, qstring *errmsg)
{
if ( code != 0 && errmsg != NULL )
{
char errbuf[MAXSTR];
qregerror(code, &regex, errbuf, sizeof(errbuf));
*errmsg = errbuf;
}
return code;
}
static refcnted_regex_t *create(const qstring &text, bool case_insensitive, qstring *errmsg)
{
if ( text.empty() )
return NULL;
refcnted_regex_t *p = new refcnted_regex_t();
int rflags = REG_EXTENDED;
if ( case_insensitive )
rflags |= REG_ICASE;
int code = qregcomp(&p->regex, text.begin(), rflags);
if ( p->process_errors(code, errmsg) != 0 )
{
// It is unnecessary to qregfree() here: the deletion of 'p' will
// call qregfree (but anyway, even that is unnecessary, because
// if we end up here, it means qregcomp() failed, and when that
// happens, qregcomp() frees the regex itself.)
delete p;
p = NULL;
}
return p;
}
size_t nsub(void)
{
/* number of parenthesized subexpressions */
return regex.re_nsub;
}
DECLARE_UNCOPYABLE(refcnted_regex_t);
};
typedef qrefcnt_t<refcnted_regex_t> regex_ptr_t;
//---------------------------------------------------------------------------
struct regex_cache_t
{
regex_ptr_t &find_or_create(const qstring &str)
{
regex_cache_map_t::iterator it = cache.find(str);
if ( it == cache.end() )
{
qstring errmsg;
regex_ptr_t rx = regex_ptr_t(refcnted_regex_t::create(str, false, &errmsg));
if ( rx == NULL )
error("%s", errmsg.c_str());
it = cache.insert(regex_cache_map_t::value_type(str, rx)).first;
}
return it->second;
}
private:
typedef std::map<qstring,regex_ptr_t> regex_cache_map_t;
regex_cache_map_t cache;
};
#endif //__cplusplus
#ifndef NO_OBSOLETE_FUNCS
idaman DEPRECATED THREAD_SAFE int ida_export regcomp(struct regex_t *preg, const char *pattern, int cflags);
idaman DEPRECATED THREAD_SAFE size_t ida_export regerror(int errcode, const struct regex_t *preg, char *errbuf, size_t errbuf_size);
idaman DEPRECATED THREAD_SAFE int ida_export regexec(const struct regex_t *preg, const char *str, size_t nmatch, struct regmatch_t pmatch[], int eflags);
idaman DEPRECATED THREAD_SAFE void ida_export regfree(struct regex_t *preg);
#endif
#endif /* !_REGEX_H_ */

View File

@@ -1,375 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __REGISTRY_HPP
#define __REGISTRY_HPP
/*! \file registry.hpp
\brief Registry related functions
IDA uses the registry to store global configuration options that must
persist after IDA has been closed.
On Windows, IDA uses the Windows registry directly. On Unix systems, the registry
is stored in a file (typically ~/.idapro/ida.reg).
The root key for accessing IDA settings in the registry is defined by #ROOT_KEY_NAME.
*/
/// Key used to store IDA settings in registry (Windows version).
/// \note this name is automatically prepended to all
/// key names passed to functions in this file.
#define ROOT_KEY_NAME "Software\\Hex-Rays\\IDA"
/// \cond
// Low level functions. DO NOT USE THEM. See the wrappers below.
// 'mode' is:
// - 0: data is a raw buffer, and its datalen must be able to hold the entire binary contents
// - 1: data is a raw buffer, and its datalen doesn't need to be able to hold the entire binary contents
// - 2: data is a ::bytevec_t*, datalen is ignored.
idaman bool ida_export reg_bin_op(
const char *name,
bool save,
void *data,
size_t datalen,
const char *subkey,
int mode = 0);
idaman bool ida_export reg_str_get(qstring *buf, const char *name, const char *subkey);
idaman void ida_export reg_str_set(const char *name, const char *subkey, const char *buf);
idaman int ida_export reg_int_op(
const char *name,
bool save,
int value,
const char *subkey = NULL);
/// \endcond
/// Types of values stored in the registry
enum regval_type_t
{
reg_unknown = 0, ///< unknown
reg_sz = 1, ///< utf8 string
reg_binary = 3, ///< binary data
reg_dword = 4 ///< 32-bit number
};
/// Delete a key from the registry
idaman bool ida_export reg_delete_subkey(const char *name);
/// Delete a subtree from the registry
idaman bool ida_export reg_delete_tree(const char *name);
/// Delete a value from the registry.
/// \param name value name
/// \param subkey parent key
/// \return success
idaman bool ida_export reg_delete(const char *name, const char *subkey = NULL);
/// Is there already a key with the given name?
idaman bool ida_export reg_subkey_exists(const char *name);
/// Is there already a value with the given name?
/// \param name value name
/// \param subkey parent key
idaman bool ida_export reg_exists(const char *name, const char *subkey = NULL);
/// Retrieve the child names of the given key.
/// \param out result
/// \param name key name
/// \param subkeys if true, collect subkey names. if false, collect value names.
/// \return false if the given key does not exist
idaman bool ida_export reg_subkey_children(qstrvec_t *out, const char *name, bool subkeys);
/// Get data type of a given value.
/// \param out result
/// \param name value name
/// \param subkey key name
/// \return false if the [key+]value doesn't exist
idaman bool ida_export reg_data_type(regval_type_t *out, const char *name, const char *subkey = NULL);
/// Retrieve all string values associated with the given key.
/// Also see reg_update_strlist().
idaman void ida_export reg_read_strlist(qstrvec_t *list, const char *subkey);
/// Update list of strings associated with given key.
/// \param subkey key name
/// \param add string to be added to list, can be NULL
/// \param maxrecs limit list to this size
/// \param rem string to be removed from list, can be NULL
/// \param ignorecase ignore case for 'add' and 'rem'
idaman void ida_export reg_update_strlist(
const char *subkey,
const char *add,
size_t maxrecs,
const char *rem = NULL,
bool ignorecase = false);
/// Write binary data to the registry.
/// \param name value name
/// \param data input, must not be NULL
/// \param datalen length of input in bytes
/// \param subkey key name
inline void reg_write_binary(
const char *name,
const void *data,
size_t datalen,
const char *subkey = NULL)
{
reg_bin_op(name, true, CONST_CAST(void *)(data), datalen, subkey);
}
/// Read binary data from the registry.
/// \param name value name
/// \param[out] data result, must not be NULL
/// \param datalen length of out buffer in bytes
/// \param subkey key name
/// \return false if 'data' is not large enough to hold all data present.
/// in this case 'data' is left untouched.
inline bool reg_read_binary(
const char *name,
void *data,
size_t datalen,
const char *subkey = NULL)
{
return reg_bin_op(name, false, data, datalen, subkey);
}
/// Read a chunk of binary data from the registry.
/// This function succeeds even in the case of a partial read.
/// \param name value name
/// \param[out] data result, must not be NULL
/// \param datalen length of output buffer in bytes
/// \param subkey key name
/// \return success
inline bool reg_read_binary_part(
const char *name,
void *data,
size_t datalen,
const char *subkey = NULL)
{
return reg_bin_op(name, false, data, datalen, subkey, 1);
}
/// Read binary data from the registry.
/// \param name value name
/// \param[out] data output buffer, must not be NULL
/// \param subkey key name
/// \return success
inline bool reg_read_binary(
const char *name,
bytevec_t *data,
const char *subkey = NULL)
{
return reg_bin_op(name, false, data, 0, subkey, 2);
}
/// Write a string to the registry.
/// \param name value name
/// \param utf8 utf8-encoded string
/// \param subkey key name
inline void reg_write_string(
const char *name,
const char *utf8,
const char *subkey = NULL)
{
reg_str_set(name, subkey, utf8);
}
/// Read a string from the registry.
/// \param[out] utf8 output buffer
/// \param name value name
/// \param subkey key name
/// \return success
inline bool reg_read_string(
qstring *utf8,
const char *name,
const char *subkey = NULL)
{
return reg_str_get(utf8, name, subkey);
}
/// Read integer value from the registry.
/// \param name value name
/// \param defval default value
/// \param subkey key name
/// \return the value read from the registry, or 'defval' if the read failed
inline int reg_read_int(const char *name, int defval, const char *subkey = NULL)
{
return reg_int_op(name, false, defval, subkey);
}
/// Write integer value to the registry.
/// \param name value name
/// \param value value to write
/// \param subkey key name
inline void reg_write_int(const char *name, int value, const char *subkey = NULL)
{
reg_int_op(name, true, value, subkey);
}
/// Read boolean value from the registry.
/// \param name value name
/// \param defval default value
/// \param subkey key name
/// \return boolean read from registry, or 'defval' if the read failed
inline bool reg_read_bool(const char *name, bool defval, const char *subkey = NULL)
{
return reg_int_op(name, false, int(defval), subkey) != 0;
}
/// Write boolean value to the registry.
/// \param name value name
/// \param value boolean to write (nonzero = true)
/// \param subkey key name
inline void reg_write_bool(const char *name, int value, const char *subkey = NULL)
{
reg_int_op(name, true, value != 0, subkey);
}
/// Get all subkey names of given key
inline bool reg_subkey_subkeys(qstrvec_t *out, const char *name)
{
return reg_subkey_children(out, name, true);
}
/// Get all value names under given key
inline bool reg_subkey_values(qstrvec_t *out, const char *name)
{
return reg_subkey_children(out, name, false);
}
/// Update registry with a file list.
/// Case sensitivity will vary depending on the target OS.
/// \note 'add' and 'rem' must be UTF-8, just like for regular string operations.
inline void reg_update_filestrlist(
const char *subkey,
const char *add,
size_t maxrecs,
const char *rem = NULL)
{
reg_update_strlist(
subkey, add, maxrecs, rem,
#ifdef __NT__ // Ignore case in Windows
true
#else
false
#endif
);
}
//-----------------------------------------------------------------------------
// INTERNALS
/// \cond
#define _RVN_(f) regname_ ## f
#ifndef __DEFINE_REG_NAMES__
#define REG_VAL_NAME(n,s) \
extern const char _RVN_(n)[]
#else
#define REG_VAL_NAME(n,s) \
extern const char _RVN_(n)[]; \
const char _RVN_(n)[] = s
#endif
#define REG_BOOL_FUNC(func, valname) \
REG_VAL_NAME(func, valname); \
inline void regset_ ## func(bool value) \
{ reg_write_bool(_RVN_(func), value); } \
inline bool regget_ ## func(bool def) \
{ return reg_read_bool(_RVN_(func), def); }
#define REG_INT_FUNC(func, valname) \
REG_VAL_NAME(func,valname); \
inline void regset_ ## func(int value) \
{ \
reg_int_op(_RVN_(func), true, value); \
} \
inline int regget_ ## func(int def=0) \
{ \
return reg_int_op(_RVN_(func), false, def); \
}
idaman void ida_export reg_load(void);
idaman void ida_export reg_flush(void);
// if using history functions below, you have to define the following two variables
extern const char regkey_history[];
extern int max_history_files; // max number of files in the file menu
// and in the welcome box
#define MAX_HISTORY_FILES_DEF 10 // default value
inline void regget_history(qstrvec_t *list)
{
#ifdef DEMO
qnotused(list);
#else
reg_read_strlist(list, regkey_history);
#endif
}
inline void reg_update_history(const char *addfile, const char *removefile = NULL)
{
#ifdef DEMO
qnotused(addfile);
qnotused(removefile);
#else
// On Windows avoid duplicate upper/lower-case entries
// by using reg_update_filestrlist() which takes care of case sensitivity
reg_update_filestrlist(regkey_history, addfile, max_history_files, removefile);
#endif
}
inline void reg_history_size_truncate(void)
{
#ifndef DEMO
reg_update_strlist(regkey_history, NULL, max_history_files, NULL);
#endif
}
/// \endcond
#endif // __REGISTRY_HPP

View File

@@ -1,167 +0,0 @@
/*
* Interactive disassembler (IDA).
* ALL RIGHTS RESERVED.
* Copyright (c) 1990-2020 Hex-Rays
*
*/
#ifndef __SEARCH_HPP
#define __SEARCH_HPP
/*! \file search.hpp
\brief Middle-level search functions
They all are controlled by \ref SEARCH_
*/
/// \defgroup SEARCH_ Search flags
//@{
#define SEARCH_UP 0x000 ///< search towards lower addresses
#define SEARCH_DOWN 0x001 ///< search towards higher addresses
#define SEARCH_NEXT 0x002 ///< skip the starting address when searching.
///< this bit is useful only for search(), bin_search2(), find_reg_access().
///< find_.. functions skip the starting address automatically.
#define SEARCH_CASE 0x004 ///< case-sensitive search (case-insensitive otherwise)
#define SEARCH_REGEX 0x008 ///< regular expressions in search string (supported only for the text search)
#define SEARCH_NOBRK 0x010 ///< do not test if the user clicked cancel to interrupt the search
#define SEARCH_NOSHOW 0x020 ///< do not display the search progress/refresh screen
#define SEARCH_IDENT 0x080 ///< search for an identifier (text search).
///< it means that the characters before
///< and after the match cannot be is_visible_char().
#define SEARCH_BRK 0x100 ///< return #BADADDR if the search was cancelled.
#define SEARCH_USE 0x200 ///< find_reg_access: search for a use (read access)
#define SEARCH_DEF 0x400 ///< find_reg_access: search for a definition (write access)
//@}
/// Is the #SEARCH_DOWN bit set?
inline THREAD_SAFE bool search_down(int sflag) { return (sflag & SEARCH_DOWN) != 0; }
/// \name find_... functions
/// \param ea start ea
/// \param sflag combination of \ref SEARCH_
/// \param[out] opnum filled with operand number whenever relevant
/// \return first ea at which the search criteria is met
//@{
/// Find next error or problem
idaman ea_t ida_export find_error(ea_t ea, int sflag, int *opnum=NULL);
/// Find next operand without any type info
idaman ea_t ida_export find_notype(ea_t ea, int sflag, int *opnum=NULL);
/// Find next unexplored address
idaman ea_t ida_export find_unknown(ea_t ea, int sflag);
/// Find next ea that is the start of an instruction or data
idaman ea_t ida_export find_defined(ea_t ea, int sflag);
/// Find next suspicious operand
idaman ea_t ida_export find_suspop(ea_t ea, int sflag, int *opnum=NULL);
/// Find next data address
idaman ea_t ida_export find_data(ea_t ea,int sflag);
/// Find next code address
idaman ea_t ida_export find_code(ea_t ea,int sflag);
/// Find next code address that does not belong to a function
idaman ea_t ida_export find_not_func(ea_t ea,int sflag);
/// Find next immediate operand with the given value
idaman ea_t ida_export find_imm(ea_t ea, int sflag, uval_t search_value, int *opnum=NULL);
/// See search()
idaman ea_t ida_export find_text(ea_t start_ea, int y, int x, const char *ustr, int sflag);
/// Find access to a register.
/// \param out pointer to the output buffer. must be non-null.
/// upon success contains info about the found register.
/// upon failed search for a read access out->range contains
/// the info about the non-redefined parts of the register.
/// \param start_ea starting address
/// \param end_ea ending address. BADADDR means that the end limit is missing.
/// otherwise, if the search direction is SEARCH_UP,
/// END_EA must be lower than START_EA.
/// \param regname the register to search for.
/// \param sflag combination of \ref SEARCH_ bits.
/// \note This function does not care about the control flow and
/// probes all instructions in the specified range, starting from START_EA.
/// Only direct references to registers are detected. Function calls and
/// system traps are ignored.
/// \return the found address. BADADDR if not found or error.
idaman ea_t ida_export find_reg_access(
struct reg_access_t *out,
ea_t start_ea,
ea_t end_ea,
const char *regname,
int sflag);
//@}
class place_t;
/// Search for a text substring (low level function).
/// \param ud line array parameter
/// \param[in,out] start pointer to starting place:
/// - start->ea: starting address
/// - start->lnnum: starting Y coordinate
/// \param end pointer to ending place:
/// - end->ea: ending address
/// - end->lnnum: ending Y coordinate
/// \param[in,out] startx pointer to starting X coordinate
/// \param str substring to search for.
/// \param sflag \ref SEARCH_
/// \retval 0 substring not found
/// \retval 1 substring found. The matching position is returned in:
/// - start->ea: address
/// - start->lnnum: Y coordinate
/// - *startx: X coordinate
/// \retval 2 search was cancelled by ctrl-break.
/// The farthest searched address is
/// returned in the same manner as in the successful return (1).
/// \retval 3 the input regular expression is bad.
/// The error message was displayed.
idaman int ida_export search(
void *ud,
place_t *start,
const place_t *end,
int *startx,
const char *str,
int sflag);
#if !defined(NO_OBSOLETE_FUNCS)
idaman DEPRECATED int ida_export user2bin(uchar *, uchar *, ea_t, const char *, int, bool); // use parse_binpat_str()
idaman DEPRECATED ea_t ida_export find_binary(ea_t, ea_t, const char *, int, int); // use bin_search2()
#endif
#endif // __SEARCH_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -1,179 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _SRAREA_HPP
#define _SRAREA_HPP
#include <range.hpp>
/*! \file segregs.hpp
\brief Functions that deal with the segment registers.
If your processor doesn't use segment registers, then these functions
are of no use for you. However, you should define
two virtual segment registers - CS and DS (for code segment and
data segment) and specify their internal numbers in the LPH structure
(processor_t::reg_code_sreg and processor_t::reg_data_sreg).
*/
//-------------------------------------------------------------------------
/// The values of the segment registers are kept as address ranges. The segment
/// register does not change its value within one address range.
/// The processor module finds segment register change points and splits
/// ::sreg_range_t ranges so that a new sreg_range_t range is started at
/// each segment register change point. The kernel deletes sreg_range_t
/// if an instruction is converted back to unexplored bytes.
///
/// So, we have information about a segment register by keeping information
/// about the range of addresses where segment register does not change the value.
///
/// Note that each segment has information about the default values of
/// the segment registers. This information is used if the value of a segment
/// register could not be determined.
struct sreg_range_t : public range_t
{
sel_t val; ///< segment register value
uchar tag; ///< \ref SR_
/// \defgroup SR_ Segment register range tags
/// Used by sreg_range_t::tag
//@{
#define SR_inherit 1 ///< the value is inherited from the previous range
#define SR_user 2 ///< the value is specified by the user
#define SR_auto 3 ///< the value is determined by IDA
#define SR_autostart 4 ///< used as #SR_auto for segment starting address
//@}
};
DECLARE_TYPE_AS_MOVABLE(sreg_range_t);
/// Get value of a segment register.
/// This function uses segment register range and default segment register
/// values stored in the segment structure.
/// \param ea linear address in the program
/// \param rg number of the segment register
/// \return value of the segment register, #BADSEL if value is unknown.
idaman sel_t ida_export get_sreg(ea_t ea, int rg);
/// Create a new segment register range.
/// This function is used when the IDP emulator detects that a segment
/// register changes its value.
/// \param ea linear address where the segment register will
/// have a new value. if ea==#BADADDR, nothing to do.
/// \param rg the number of the segment register
/// \param v the new value of the segment register. If the value is
/// unknown, you should specify #BADSEL.
/// \param tag the register info tag. see \ref SR_
/// \param silent if false, display a warning() in the case of failure
/// \return success
idaman bool ida_export split_sreg_range(
ea_t ea,
int rg,
sel_t v,
uchar tag,
bool silent=false);
/// Set default value of a segment register for a segment.
/// \param sg pointer to segment structure
/// if NULL, then set the register for all segments
/// \param rg number of segment register
/// \param value its default value. this value will be used by get_sreg()
/// if value of the register is unknown at the specified address.
/// \return success
idaman bool ida_export set_default_sreg_value(segment_t *sg, int rg, sel_t value);
/// Set the segment register value at the next instruction.
/// This function is designed to be called from idb_event::sgr_changed handler
/// in order to contain the effect of changing a segment
/// register value only until the next instruction.
///
/// It is useful, for example, in the ARM module: the modification
/// of the T register does not affect existing instructions later in the code.
/// \param ea1 address to start to search for an instruction
/// \param ea2 the maximal address
/// \param rg the segment register number
/// \param value the segment register value
idaman void ida_export set_sreg_at_next_code(ea_t ea1, ea_t ea2, int rg, sel_t value);
/// Get segment register range by linear address.
/// \param out segment register range
/// \param ea any linear address in the program
/// \param rg the segment register number
/// \return success
idaman bool ida_export get_sreg_range(sreg_range_t *out, ea_t ea, int rg);
/// Get segment register range previous to one with address.
/// \note more efficient then get_sreg_range(reg, ea-1)
/// \param out segment register range
/// \param ea any linear address in the program
/// \param rg the segment register number
/// \return success
idaman bool ida_export get_prev_sreg_range(sreg_range_t *out, ea_t ea, int rg);
/// Set default value of DS register for all segments
idaman void ida_export set_default_dataseg(sel_t ds_sel);
/// Get number of segment register ranges.
/// \param rg the segment register number
idaman size_t ida_export get_sreg_ranges_qty(int rg);
/// Get segment register range by its number.
/// \param out segment register range
/// \param rg the segment register number
/// \param n number of range (0..qty()-1)
/// \return success
idaman bool ida_export getn_sreg_range(sreg_range_t *out, int rg, int n);
/// Get number of segment register range by address.
/// \param ea any address in the range
/// \param rg the segment register number
/// \return -1 if no range occupies the specified address.
/// otherwise returns number of
/// the specified range (0..get_srranges_qty()-1)
idaman int ida_export get_sreg_range_num(ea_t ea, int rg);
/// Delete segment register range started at ea.
/// When a segment register range is deleted,
/// the previous range is extended to cover the empty space.
/// The segment register range at the beginning of a segment cannot be deleted.
/// \param ea start_ea of the deleted range
/// \param rg the segment register number
/// \return success
idaman bool ida_export del_sreg_range(ea_t ea, int rg);
/// Duplicate segment register ranges.
/// \param dst_rg number of destination segment register
/// \param src_rg copy ranges from
/// \param map_selector map selectors to linear addresses using sel2ea()
idaman void ida_export copy_sreg_ranges(int dst_rg, int src_rg, bool map_selector=false);
#endif // _SRAREA_HPP

View File

@@ -1,78 +0,0 @@
/*
* The Interactive Disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _STRLIST_HPP
#define _STRLIST_HPP
/*! \file strlist.hpp
\brief Functions that deal with the string list
While the kernel keeps the strings list, it does not update it.
The string list is not used by the kernel because
keeping it up-to-date would slow down IDA without any benefit.
The users of this list should build_strlist() before accessing it.
*/
/// Structure to keep string list parameters
struct strwinsetup_t
{
strwinsetup_t()
: minlen(-1), display_only_existing_strings(0),
only_7bit(1), ignore_heads(0) {}
bytevec_t strtypes; // set of allowed string types
sval_t minlen;
uchar display_only_existing_strings;
uchar only_7bit;
uchar ignore_heads;
inline bool is_initialized() const { return minlen > -1; }
};
/// Information about one string from the string list
struct string_info_t
{
ea_t ea;
int length; // in octets
int type;
string_info_t() : ea(BADADDR), length(0), type(0) {}
string_info_t(ea_t _ea) : ea(_ea), length(0), type(0) {}
bool operator<(const string_info_t &r) const { return ea < r.ea; }
};
DECLARE_TYPE_AS_MOVABLE(string_info_t);
/// Get access to the static string list options
idaman strwinsetup_t *ida_export get_strlist_options();
/// Build the string list.
/// You should initialize options before this call using the
/// restore_config() or setup_strings_window() methods.
idaman void ida_export build_strlist();
/// Clear the string list.
idaman void ida_export clear_strlist();
/// Get number of elements in the string list
idaman size_t ida_export get_strlist_qty(void);
/// Get nth element of the string list (n=0..get_strlist_qty()-1)
idaman bool ida_export get_strlist_item(string_info_t *si, size_t n);
#endif // _STRLIST_HPP

View File

@@ -1,651 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
/*! \file struct.hpp
\brief Structure type management (assembly level types)
*/
#ifndef _STRUCT_HPP
#define _STRUCT_HPP
#include <bytes.hpp>
#define STRUC_SEPARATOR '.' ///< structname.fieldname
/// Describes a member of an assembly level structure
class member_t
{
public:
tid_t id; ///< name(), cmt, rptcmt
ea_t soff; ///< start offset (for unions - number of the member 0..n)
ea_t eoff; ///< end offset
flags_t flag; ///< type+representation bits
//private:
uint32 props; ///< \ref MF_
/// \defgroup MF_ Struct member properties
/// Used by member_t::props
//@{
#define MF_OK 0x00000001 ///< is the member ok? (always yes)
#define MF_UNIMEM 0x00000002 ///< is a member of a union?
#define MF_HASUNI 0x00000004 ///< has members of type "union"?
#define MF_BYTIL 0x00000008 ///< the member was created due to the type system
#define MF_HASTI 0x00000010 ///< has type information?
#define MF_BASECLASS 0x00000020 ///< a special member representing base class
#define MF_DTOR 0x00000040 ///< a special member representing destructor
#define MF_DUPNAME 0x00000080 ///< duplicate name resolved with _N suffix (N==soff)
//@}
/// Is a member of a union?
bool unimem(void) const { return (props & MF_UNIMEM) != 0; }
/// Has members of type "union"?
bool has_union(void) const { return (props & MF_HASUNI) != 0; }
/// Was the member created due to the type system?
bool by_til(void) const { return (props & MF_BYTIL) != 0; }
/// Has type information?
bool has_ti(void) const { return (props & MF_HASTI) != 0; }
/// Is a base class member?
bool is_baseclass(void) const { return (props & MF_BASECLASS) != 0; }
/// Duplicate name was resolved during import?
bool is_dupname(void) const { return (props & MF_DUPNAME) != 0; }
/// Is a virtual destructor?
bool is_destructor(void) const { return (props & MF_DTOR) != 0; }
/// Get start offset (for unions - returns 0)
ea_t get_soff(void) const { return unimem() ? 0 : soff; }
};
/// Information about a structure type (assembly level)
//-V:struc_t:730 not all members of a class are initialized inside the constructor
class struc_t
{
protected:
struc_t(void) {} ///< plugins may not create struc_t instances. they should
///< use add_struc() and get_struc()
public:
tid_t id; ///< struct id
uint32 memqty; ///< number of members
member_t *members; ///< only defined members are stored here.
///< there may be gaps between members.
ushort age; ///< not used
uint32 props; ///< \ref SF_
/// \defgroup SF_ Structure properties
/// Used by struc_t::props
//@{
#define SF_VAR 0x00000001 ///< is variable size structure (varstruct)?
///< a variable size structure is one with
///< the zero size last member.
///< if the last member is a varstruct, then the current
///< structure is a varstruct too.
#define SF_UNION 0x00000002 ///< is a union?
///< varunions are prohibited!
#define SF_HASUNI 0x00000004 ///< has members of type "union"?
#define SF_NOLIST 0x00000008 ///< don't include in the chooser list
#define SF_TYPLIB 0x00000010 ///< the structure comes from type library
#define SF_HIDDEN 0x00000020 ///< the structure is collapsed
#define SF_FRAME 0x00000040 ///< the structure is a function frame
#define SF_ALIGN 0x00000F80 ///< alignment (shift amount: 0..31)
#define SF_GHOST 0x00001000 ///< ghost copy of a local type
//@}
/// Is variable size structure?
bool is_varstr(void) const { return (props & SF_VAR) != 0; }
/// Is a union?
bool is_union(void) const { return (props & SF_UNION) != 0; }
/// Has members of type "union"?
bool has_union(void) const { return (props & SF_HASUNI) != 0; }
/// Is included in chooser list?
/// Use \ref set_struc_listed to change the listed status
bool is_choosable(void) const { return (props & SF_NOLIST) == 0; }
/// Does structure come from a type library?
bool from_til(void) const { return (props & SF_TYPLIB) != 0; }
/// Is the structure collapsed?
/// Use \ref set_struc_hidden to change the hidden status
bool is_hidden(void) const { return (props & SF_HIDDEN) != 0; }
/// Is this structure a function frame?
bool is_frame(void) const { return (props & SF_FRAME) != 0; }
/// See #SF_ALIGN
int get_alignment(void) const { return (props & SF_ALIGN) >> 7; }
/// Is a ghost copy of a local type?
bool is_ghost(void) const { return (props & SF_GHOST) != 0; }
/// Do not use; use set_struc_align()
void set_alignment(int shift)
{
props &= ~SF_ALIGN;
props |= (shift << 7) & SF_ALIGN;
}
void set_ghost(bool _is_ghost) { setflag(props, SF_GHOST, _is_ghost); }
mutable int32 ordinal; ///< corresponding local type ordinal number
};
/// \name Internal structures list
/// IDA maintains an internal vector of known structures.
/// Use these functions to work with this vector.
//@{
/// Get number of known structures
idaman size_t ida_export get_struc_qty(void);
/// Get index of first structure.
/// \return #BADADDR if no known structures, 0 otherwise
idaman uval_t ida_export get_first_struc_idx(void);
/// Get index of last structure.
/// \return #BADADDR if no known structures, get_struc_qty()-1 otherwise
idaman uval_t ida_export get_last_struc_idx(void);
/// Get previous struct index.
/// \return #BADADDR if resulting index is negative, otherwise idx - 1
inline THREAD_SAFE uval_t get_prev_struc_idx(uval_t idx) { return idx == BADNODE ? idx : idx - 1; }
/// Get next struct index.
/// \return #BADADDR if resulting index is out of bounds, otherwise idx++
idaman uval_t ida_export get_next_struc_idx(uval_t idx);
/// Get internal number of the structure
idaman uval_t ida_export get_struc_idx(tid_t id);
/// Get struct id by struct number
idaman tid_t ida_export get_struc_by_idx(uval_t idx);
/// Get pointer to struct type info
idaman struc_t *ida_export get_struc(tid_t id);
//@}
/// Get struct id by name
inline tid_t get_struc_id(const char *name)
{
tid_t id = node2ea(netnode(name));
return get_struc(id) == NULL ? BADADDR : id;
}
/// Get struct name by id
/// \param[out] out buffer to hold the name
/// \param id struct id
/// \param flags \ref STRNFL_
idaman ssize_t ida_export get_struc_name(qstring *out, tid_t id, int flags=0);
/// \defgroup STRNFL_ Struct name flags
/// Passed as 'flags' parameter to get_struc_name()
//@{
#define STRNFL_REGEX 0x0001 ///< apply regular expressions to beautify the name
//@}
inline qstring get_struc_name(tid_t id, int flags=0)
{
qstring name;
get_struc_name(&name, id, flags);
return name;
}
/// Get struct comment
inline ssize_t get_struc_cmt(qstring *buf, tid_t id, bool repeatable) { return getnode(id).supstr(buf, repeatable != 0); }
/// Get struct size (also see get_struc_size(tid_t))
idaman asize_t ida_export get_struc_size(const struc_t *sptr);
/// Get struct size (also see get_struc_size(const struc_t *))
inline asize_t get_struc_size(tid_t id) { return get_struc_size(get_struc(id)); }
/// \name Struct offsets
/// \note for unions, soff == number of the current member
//@{
/// Get offset of member with largest offset less than 'offset'.
/// \return #BADADDR if no prev offset
idaman ea_t ida_export get_struc_prev_offset(const struc_t *sptr, ea_t offset);
/// Get offset of member with smallest offset larger than 'offset'.
/// \return #BADADDR if no next offset
idaman ea_t ida_export get_struc_next_offset(const struc_t *sptr, ea_t offset);
/// Get offset of last member.
/// \return #BADADDR if memqty == 0
idaman ea_t ida_export get_struc_last_offset(const struc_t *sptr);
/// Get offset of first member.
/// \return #BADADDR if memqty == 0
idaman ea_t ida_export get_struc_first_offset(const struc_t *sptr);
/// For unions: returns number of members, for structs: returns size of structure
inline ea_t get_max_offset(struc_t *sptr)
{
if ( sptr == NULL )
return 0; // just to avoid GPF
return sptr->is_union()
? sptr->memqty
: get_struc_size(sptr);
}
//@}
/// Is variable size structure?
inline bool is_varstr(tid_t id)
{
struc_t *sptr = get_struc(id);
return sptr != NULL && sptr->is_varstr();
}
/// Is a union?
inline bool is_union(tid_t id)
{
struc_t *sptr = get_struc(id);
return sptr != NULL && sptr->is_union();
}
/// Get containing structure of member by its full name "struct.field"
idaman struc_t *ida_export get_member_struc(const char *fullname);
/// Get child struct if member is a struct
idaman struc_t *ida_export get_sptr(const member_t *mptr);
/// Get member at given offset
idaman member_t *ida_export get_member(const struc_t *sptr, asize_t offset);
/// Get member id at given offset
inline tid_t get_member_id(const struc_t *sptr, asize_t offset)
{
member_t *mptr = get_member(sptr, offset);
return mptr != NULL ? mptr->id : BADADDR;
}
/// Get a member by its name, like "field44"
idaman member_t *ida_export get_member_by_name(const struc_t *sptr, const char *membername);
/// Get a member by its fully qualified name, "struct.field"
idaman member_t *ida_export get_member_by_fullname(struc_t **sptr_place, const char *fullname);
/// Get a member's fully qualified name, "struct.field"
inline ssize_t idaapi get_member_fullname(qstring *out, tid_t mid) { return getnode(mid).get_name(out); }
/// Get name of structure member
idaman ssize_t ida_export get_member_name(qstring *out, tid_t mid);
inline qstring get_member_name(tid_t mid)
{
qstring name;
get_member_name(&name, mid);
return name;
}
/// Get comment of structure member
inline ssize_t idaapi get_member_cmt(qstring *buf, tid_t mid, bool repeatable) { return getnode(mid).supstr(buf, repeatable != 0); }
/// Get size of structure member.
/// May return 0 for the last member of varstruct.
/// For union members, returns member_t::eoff.
inline asize_t get_member_size(const member_t *NONNULL mptr) { return mptr->unimem() ? mptr->eoff : (mptr->eoff - mptr->soff); }
/// Is variable size member?
idaman bool ida_export is_varmember(const member_t *mptr);
/// Get member that is most likely referenced by the specified offset.
/// Useful for offsets > sizeof(struct).
idaman member_t *ida_export get_best_fit_member(const struc_t *sptr, asize_t offset);
/// Get the next member idx, if it does not exist, return -1
idaman ssize_t ida_export get_next_member_idx(const struc_t *sptr, asize_t off);
/// Get the prev member idx, if it does not exist, return -1
idaman ssize_t ida_export get_prev_member_idx(const struc_t *sptr, asize_t off);
//--------------------------------------------------------------------------
// manipulation
/// Create a structure type.
/// if idx==#BADADDR then add as the last idx.
/// if name==NULL then a name will be generated "struct_%d".
idaman tid_t ida_export add_struc(uval_t idx, const char *name, bool is_union=false);
/// Delete a structure type
idaman bool ida_export del_struc(struc_t *sptr);
/// Set internal number of struct.
/// Also see get_struc_idx(), get_struc_by_idx().
idaman bool ida_export set_struc_idx(const struc_t *sptr, uval_t idx);
/// Set structure alignment (#SF_ALIGN)
idaman bool ida_export set_struc_align(struc_t *sptr, int shift);
/// Set structure name
idaman bool ida_export set_struc_name(tid_t id, const char *name);
/// Set structure comment
idaman bool ida_export set_struc_cmt(tid_t id, const char *cmt, bool repeatable);
/// Return values for add_struc_member()
enum struc_error_t
{
STRUC_ERROR_MEMBER_OK = 0, ///< success
STRUC_ERROR_MEMBER_NAME = -1, ///< already has member with this name (bad name)
STRUC_ERROR_MEMBER_OFFSET = -2, ///< already has member at this offset
STRUC_ERROR_MEMBER_SIZE = -3, ///< bad number of bytes or bad sizeof(type)
STRUC_ERROR_MEMBER_TINFO = -4, ///< bad typeid parameter
STRUC_ERROR_MEMBER_STRUCT = -5, ///< bad struct id (the 1st argument)
STRUC_ERROR_MEMBER_UNIVAR = -6, ///< unions can't have variable sized members
STRUC_ERROR_MEMBER_VARLAST = -7, ///< variable sized member should be the last member in the structure
STRUC_ERROR_MEMBER_NESTED = -8, ///< recursive structure nesting is forbidden
};
/// Add member to existing structure.
/// \param sptr structure to modify
/// \param fieldname if NULL, then "anonymous_#" name will be generated
/// \param offset #BADADDR means add to the end of structure
/// \param flag type + representation bits
/// \param mt additional info about member type.
/// must be present for
/// structs, offsets, enums, strings,
/// struct offsets.
/// \param nbytes if == 0 then the structure
/// will be a varstruct.
/// in this case the member should be
/// the last member in the structure
idaman struc_error_t ida_export add_struc_member(
struc_t *sptr,
const char *fieldname,
ea_t offset,
flags_t flag,
const opinfo_t *mt,
asize_t nbytes);
/// Delete member at given offset
idaman bool ida_export del_struc_member(struc_t *sptr, ea_t offset);
/// Delete members which occupy range of offsets (off1..off2).
/// \return number of deleted members or -1 on error
idaman int ida_export del_struc_members(struc_t *sptr, ea_t off1, ea_t off2);
/// Set name of member at given offset
idaman bool ida_export set_member_name(struc_t *sptr, ea_t offset,const char *name);
/// Set type of member at given offset (also see add_struc_member())
idaman bool ida_export set_member_type(struc_t *sptr, ea_t offset, flags_t flag,const opinfo_t *mt, asize_t nbytes);
/// Set member comment
idaman bool ida_export set_member_cmt(member_t *mptr,const char *cmt, bool repeatable);
/// Expand/Shrink structure type
idaman bool ida_export expand_struc(struc_t *sptr, ea_t offset, adiff_t delta, bool recalc=true);
/// Update struct information in the database (internal function)
idaman void ida_export save_struc(struc_t *sptr, bool may_update_ltypes=true);
/// Hide/unhide a struct type
inline void idaapi set_struc_hidden(struc_t *sptr, bool is_hidden)
{
setflag(sptr->props, SF_HIDDEN, is_hidden);
save_struc(sptr, false);
}
/// Add/remove a struct type from the struct list
inline void idaapi set_struc_listed(struc_t *sptr, bool is_listed)
{
setflag(sptr->props, SF_NOLIST, !is_listed);
save_struc(sptr, false);
}
/// Member type information (return values for set_member_tinfo())
enum smt_code_t
{
SMT_BADARG = -6, ///< bad parameters
SMT_NOCOMPAT = -5, ///< the new type is not compatible with the old type
SMT_WORSE = -4, ///< the new type is worse than the old type
SMT_SIZE = -3, ///< the new type is incompatible with the member size
SMT_ARRAY = -2, ///< arrays are forbidden as function arguments
SMT_OVERLAP = -1, ///< member would overlap with members that cannot be deleted
SMT_FAILED = 0, ///< failed to set new member type
SMT_OK = 1, ///< success: changed the member type
SMT_KEEP = 2, ///< no need to change the member type, the old type is better
};
/// Get tinfo for given member
idaman bool ida_export get_member_tinfo(tinfo_t *tif, const member_t *mptr);
/// Delete tinfo for given member
idaman bool ida_export del_member_tinfo(struc_t *sptr, member_t *mptr);
/// Set tinfo for given member.
/// \param sptr containing struct
/// \param mptr target member
/// \param memoff offset within member
/// \param tif type info
/// \param flags \ref SET_MEMTI_
idaman smt_code_t ida_export set_member_tinfo(
struc_t *sptr,
member_t *mptr,
uval_t memoff,
const tinfo_t &tif,
int flags);
/// \defgroup SET_MEMTI_ Set member tinfo flags
/// Passed as 'flags' parameter to set_member_tinfo()
//@{
#define SET_MEMTI_MAY_DESTROY 0x0001 ///< may destroy other members
#define SET_MEMTI_COMPATIBLE 0x0002 ///< new type must be compatible with the old
#define SET_MEMTI_FUNCARG 0x0004 ///< mptr is function argument (cannot create arrays)
#define SET_MEMTI_BYTIL 0x0008 ///< new type was created by the type subsystem
#define SET_MEMTI_USERTI 0x0010 ///< user-specified type
//@}
/// Try to get tinfo for given member - if failed, generate a tinfo using information about the
/// member id from the disassembly
idaman bool ida_export get_or_guess_member_tinfo(tinfo_t *tif, const member_t *mptr);
/// Get operand type info for member
inline opinfo_t *retrieve_member_info(opinfo_t *buf, const member_t *mptr)
{
if ( mptr == NULL )
return NULL;
return get_opinfo(buf, mptr->id, 0, mptr->flag);
}
/// Is member name prefixed with "anonymous"?
inline THREAD_SAFE bool is_anonymous_member_name(const char *name)
{
return name == NULL
|| strncmp(name, "anonymous", 9) == 0;
}
/// Is member name an auto-generated name?
inline THREAD_SAFE bool is_dummy_member_name(const char *name)
{
return name == NULL
|| strncmp(name, "arg_", 4) == 0
|| strncmp(name, "var_", 4) == 0
|| is_anonymous_member_name(name);
}
/// Check if the specified member id points to a struct member
inline member_t *idaapi get_member_by_id(
qstring *out_mname, // note: id 'out_mname' is important for SWiG
tid_t mid,
struc_t **sptr_place)
{
if ( get_member_fullname(out_mname, mid) > 0 )
return get_member_by_fullname(sptr_place, out_mname->begin());
return NULL;
}
/// Check if the specified member id points to a struct member. convenience function
inline member_t *idaapi get_member_by_id(tid_t mid, struc_t **sptr_place=NULL)
{
qstring buf;
return get_member_by_id(&buf, mid, sptr_place);
}
/// Is a member id?
inline bool is_member_id(tid_t mid)
{
return get_member_by_id(mid) != NULL;
}
/// Is a special member with the name beginning with ' '?
idaman bool ida_export is_special_member(tid_t id);
/// Implements action to take when a field is visited with visit_stroff_fields()
struct ida_local struct_field_visitor_t
{
virtual int idaapi visit_field(struc_t *sptr, member_t *mptr) = 0;
};
//--------------------------------------------------------------------------
/// Visit structure fields in a stroff expression or in a reference to a struct data variable.
/// This function can be used to enumerate all components of an expression like 'a.b.c'.
/// \param sfv visitor object
/// \param path struct path (path[0] contains the initial struct id)
/// \param plen len
/// \param[in,out] disp offset into structure
/// \param appzero should visit field at offset zero?
idaman flags_t ida_export visit_stroff_fields(
struct_field_visitor_t &sfv,
const tid_t *path,
int plen,
adiff_t *disp,
bool appzero);
//--------------------------------------------------------------------------
/// Should display a structure offset expression as the structure size?
inline bool stroff_as_size(int plen, const struc_t *sptr, asize_t value)
{
return plen == 1
&& value > 0
&& sptr != NULL
&& !sptr->is_varstr()
&& value == get_struc_size(sptr);
}
//-------------------------------------------------------------------------
// F U N C T I O N S F O R T H E K E R N E L
//-------------------------------------------------------------------------
///-------------------------------------------------------------------\cond
inline void save_structs(void) {}
///----------------------------------------------------------------\endcond
#endif // _STRUCT_HPP

View File

@@ -1,217 +0,0 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 2016-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
* Module independent exception description
*/
#ifndef TRYBLKS_HPP
#define TRYBLKS_HPP
/*! \file tryblks.hpp
*
* \brief Architecture independent exception handling info.
*
* Try blocks have the following general properties:
* - An try block specifies a possibly fragmented guarded code region.
* - Each try block has always at least one catch/except block description
* - Each catch block contains its boundaries and a filter.
* - Additionally a catch block can hold sp adjustment and the offset to the
* exception object offset (C++).
* - Try blocks can be nested. Nesting is automatically calculated at the retrieval time.
* - There may be (nested) multiple try blocks starting at the same address.
*
* See examples in tests/input/src/eh_tests.
*
*/
// We use end_ea=BADADDR if the exact boundaries are unknown of any range.
//----------------------------------------------------------------------------
// An exception handler clause (the body of __except or catch statement)
struct try_handler_t : public rangevec_t
{
sval_t disp; // displacement to the stack region of the guarded region.
// if it is valid, it is fpreg relative.
// -1 means unknown.
int fpreg; // frame register number used in handler. -1 means none.
try_handler_t() : disp(-1), fpreg(-1) {}
void clear(void)
{
rangevec_t::clear();
disp = -1;
fpreg = -1;
}
};
DECLARE_TYPE_AS_MOVABLE(try_handler_t);
//----------------------------------------------------------------------------
// __except() {} statement
struct seh_t : public try_handler_t
{
rangevec_t filter; // boundaries of the filter callback. if filter is empty,
ea_t seh_code; // then use seh_code
#define SEH_CONTINUE BADADDR // EXCEPTION_CONTINUE_EXECUTION (-1)
#define SEH_SEARCH ea_t(0) // EXCEPTION_CONTINUE_SEARCH (0) (alias of __finally)
#define SEH_HANDLE ea_t(1) // EXCEPTION_EXECUTE_HANDLER (1)
void clear(void)
{
try_handler_t::clear();
filter.clear();
seh_code = SEH_CONTINUE;
}
};
DECLARE_TYPE_AS_MOVABLE(seh_t);
//----------------------------------------------------------------------------
// catch() {} statement
struct catch_t : public try_handler_t
{
sval_t obj; // fpreg relative displacement to the exception object. -1 if unknown.
sval_t type_id; // the type caught by this catch. -1 means "catch(...)"
#define CATCH_ID_ALL sval_t(-1) // catch(...)
#define CATCH_ID_CLEANUP sval_t(-2) // a cleanup handler invoked if exception occures
catch_t() : obj(-1), type_id(-1) {}
};
DECLARE_TYPE_AS_MOVABLE(catch_t);
typedef qvector<catch_t> catchvec_t;
//----------------------------------------------------------------------------
class tryblk_t : public rangevec_t // block guarded by try/__try {...} statements
{
#ifndef SWIG
char reserve[qmax(sizeof(catchvec_t), sizeof(seh_t))]; // seh_t or catchvec_t
#endif
uchar cb; // size of tryblk_t
uchar kind; // one of the following kinds
#define TB_NONE 0 // empty
#define TB_SEH 1 // MS SEH __try/__except/__finally
#define TB_CPP 2 // C++ language try/catch
public:
uchar level; // nesting level, calculated by get_tryblks()
// C++ try/catch block (TB_CPP)
catchvec_t &cpp() { return *(( catchvec_t *)reserve); }
const catchvec_t &cpp() const { return *((const catchvec_t *)reserve); }
// SEH __except/__finally case (TB_SEH)
seh_t &seh() { return *(( seh_t *)reserve); }
const seh_t &seh() const { return *((const seh_t *)reserve); }
tryblk_t() : rangevec_t(), cb(sizeof(*this)), kind(TB_NONE), level(0) { reserve[0] = '\0'; }
~tryblk_t() { clear(); }
tryblk_t(const tryblk_t &r) : rangevec_t(), kind(TB_NONE) { *this = r; }
uchar get_kind(void) const { return kind; }
bool empty(void) const { return kind == TB_NONE; }
bool is_seh(void) const { return kind == TB_SEH; }
bool is_cpp(void) const { return kind == TB_CPP; }
//-------------------------------------------------------------------------
tryblk_t &operator=(const tryblk_t &r)
{
if ( this != &r ) // don't copy yourself
{
if ( kind != TB_NONE )
clear();
kind = r.kind;
level = r.level;
rangevec_t::operator=(r);
if ( kind == TB_SEH )
new (reserve) seh_t(r.seh());
else if ( kind == TB_CPP )
new (reserve) catchvec_t(r.cpp());
}
return *this;
}
//-------------------------------------------------------------------------
void clear(void)
{
if ( kind == TB_CPP )
cpp().~catchvec_t();
else if ( kind == TB_SEH )
seh().~seh_t();
kind = TB_NONE;
}
//-------------------------------------------------------------------------
seh_t &set_seh(void)
{
if ( kind != TB_SEH )
{
clear();
new (reserve) seh_t;
kind = TB_SEH;
}
else
{
seh().clear();
}
return seh();
}
//-------------------------------------------------------------------------
catchvec_t &set_cpp(void)
{
if ( kind != TB_CPP )
{
clear();
new (reserve) catchvec_t;
kind = TB_CPP;
}
else
{
cpp().clear();
}
return cpp();
}
};
DECLARE_TYPE_AS_MOVABLE(tryblk_t);
typedef qvector<tryblk_t> tryblks_t;
///-------------------------------------------------------------------------
/// Retrieve try block information from the specified address range.
/// Try blocks are sorted by starting address and their nest levels calculated.
/// \param tbv output buffer; may be NULL
/// \param range address range to change
/// \return number of found try blocks
idaman size_t ida_export get_tryblks(tryblks_t *tbv, const range_t &range);
/// Delete try block information in the specified range.
/// \param range the range to be cleared
idaman void ida_export del_tryblks(const range_t &range);
/// Add one try block information.
/// \param tb try block to add.
/// \return error code; 0 means good
idaman int ida_export add_tryblk(const tryblk_t &tb);
/// \defgroup TBERR_ Try block handling error codes
//@{
#define TBERR_OK 0 ///< ok
#define TBERR_START 1 ///< bad start address
#define TBERR_END 2 ///< bad end address
#define TBERR_ORDER 3 ///< bad address order
#define TBERR_EMPTY 4 ///< empty try block
#define TBERR_KIND 5 ///< illegal try block kind
#define TBERR_NO_CATCHES 6 ///< no catch blocks at all
#define TBERR_INTERSECT 7 ///< range would intersect inner tryblk
//@}
/// Find the start address of the system eh region including the argument.
/// \param ea search address
/// \return start address of surrounding tryblk, otherwise BADADDR
idaman ea_t ida_export find_syseh(ea_t ea);
#endif // TRYBLKS_HPP

Some files were not shown because too many files have changed in this diff Show More