IDAPython 1.4.0 - IDA Pro 5.7 support

This commit is contained in:
elias.bachaalany 2010-06-28 12:36:40 +00:00
parent 5f2262fad9
commit 3a5063330c
40 changed files with 20591 additions and 15275 deletions

View File

@ -53,10 +53,7 @@ Make sure all the needed tools (compiler, swig) are on the PATH.
It is possible to build the plugin for different Python versions by
running build.py with the corresponding Python binary.
Some build options:
--ea64: builds the 64-bit version
--no-early-load: builds the IDAPython plugin w/o PLUGIN_FIX plugin flag
(This flag disables the ability to write file loaders in IDAPython)
Run 'build.py --help' for more information.
4, Install the components as described in README.txt

View File

@ -1,5 +1,17 @@
Please see http://code.google.com/p/idapython/source/list for a
detailed list of changes.
Please see http://code.google.com/p/idapython/source/list for a detailed list of changes.
Changes from version 1.3.0 to 1.4.0
------------------------------------
- IDA Pro 5.7 support
- idaapi.cvar.cmd is now accessible via idapi.cmd instead
- Python statement (Alt-8) is now 16kb long
- Dropped script box and File/Python file. IDA has this functionality now.
- Refactored the code
- It is possible to turn off script timeout
- All scripts are executed via 'IDAPython_ExecScript' (check idaapi.i)
- Added '--doc' switch to "build.py" script
- Documented all manually wrapped functions (check 'pywraps' module in the docs)
- Lots of cleanups and fixes
Changes from version 1.2.0 to 1.3.0
------------------------------------

View File

@ -17,12 +17,15 @@ import shutil
import sys
import types
import zipfile
import glob
from distutils import sysconfig
# Start of user configurable options
VERBOSE = True
IDA_MAJOR_VERSION = 5
IDA_MINOR_VERSION = 6
IDA_MINOR_VERSION = 7
if 'IDA' in os.environ:
IDA_SDK = os.environ['IDA']
else:
@ -32,8 +35,8 @@ else:
# IDAPython version
VERSION_MAJOR = 1
VERSION_MINOR = 3
VERSION_PATCH = 2
VERSION_MINOR = 4
VERSION_PATCH = 0
# Determine Python version
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
@ -43,7 +46,7 @@ PYTHON_MINOR_VERSION = int(platform.python_version()[2])
PYTHON_INCLUDE_DIRECTORY = sysconfig.get_config_var('INCLUDEPY')
# Swig command-line parameters
SWIG_OPTIONS = '-modern -python -c++ -w451 -shadow -D__GNUC__'
SWIG_OPTIONS = '-modern -python -c++ -w451 -shadow -D__GNUC__ -DNO_OBSOLETE_FUNCS'
# Common macros for all compilations
COMMON_MACROS = [
@ -75,6 +78,7 @@ BINDIST_MANIFEST = [
"examples/structure.py",
"examples/ex_gdl_qflow_chart.py",
"examples/ex_strings.py",
"examples/ex_add_menu_item.py",
"examples/ex_func_chooser.py",
"examples/ex_choose2.py",
"examples/ex_debug_names.py",
@ -162,7 +166,8 @@ class BuilderBase:
includestring,
macrostring)
if VERBOSE: print cmdstring
if VERBOSE:
print cmdstring
return os.system(cmdstring)
def link(self, objects, outfile, libpaths=[], libraries=[], extra_parameters=None):
@ -413,7 +418,73 @@ def build_source_package():
srcmanifest.extend([(x, "python") for x in "python/init.py", "python/idc.py", "python/idautils.py"])
build_distribution(srcmanifest, SRCDISTDIR, ea64=False, nukeold=True)
def gen_docs(z = False):
print "Generating documentation....."
old_dir = os.getcwd()
try:
curdir = os.getcwd() + os.sep
docdir = 'idapython-reference-%d.%d.%d' % (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
sys.path.append(curdir + 'python')
sys.path.append(curdir + 'tools')
sys.path.append(curdir + 'docs')
import epydoc.cli
import swigdocs
os.chdir('docs')
PYWRAPS_FN = 'pywraps'
swigdocs.gen_docs(outfn = PYWRAPS_FN + '.py')
epydoc.cli.optparse.sys.argv = [ 'epydoc',
'--no-sourcecode',
'-u', 'http://code.google.com/p/idapython/',
'--navlink', '<a href="http://www.hex-rays.com/idapro/idapython_docs/">IDAPython Reference</a>',
'--no-private',
'--simple-term',
'-o', docdir,
'--html',
'idc', 'idautils', PYWRAPS_FN, 'idaapi']
# Generate the documentation
epydoc.cli.cli()
print "Documentation generated!"
# Clean temp files
for f in [PYWRAPS_FN + '.py', PYWRAPS_FN + '.pyc']:
if os.path.exists(f):
os.unlink(f)
if z:
z = docdir + '-doc.zip'
zip = zipfile.ZipFile(z, "w", zipfile.ZIP_DEFLATED)
for fn in glob.glob(docdir + os.sep + '*'):
zip.write(fn)
zip.close()
print "Documentation compressed to", z
except Exception, e:
print 'Failed to generate documentation:', e
finally:
os.chdir(old_dir)
return
def usage():
print """IDAPython build script.
Available switches:
--doc:
Generate documentation into the 'docs' directory
--zip:
Used with '--doc' switch. It will compress the generated documentation
--ea64:
Builds also the 64bit version of the plugin
--no-early-load:
The plugin will be compiled as normal plugin
This switch disables processor, plugin and loader scripts
"""
def main():
if '--help' in sys.argv:
return usage()
elif '--doc' in sys.argv:
return gen_docs(z = '--zip' in sys.argv)
# Do 64-bit build?
ea64 = '--ea64' in sys.argv
build_binary_package(ea64=False, nukeold=True)

View File

@ -0,0 +1,18 @@
import idaapi
def cb(*args):
print "Callback called!"
return 1
try:
if ctx:
idaapi.del_menu_item(ctx)
except:
pass
ctx = idaapi.add_menu_item("Search/", "X", "", 0, cb, tuple("hello world"))
if ctx is None:
print "Failed to add menu!"
del ctx
else:
print "Menu added successfully!"

View File

@ -15,7 +15,7 @@ class mycv_t(simplecustviewer_t):
if sn:
title += " %d" % sn
# Create the customview
# Create the customviewer
if not simplecustviewer_t.Create(self, title):
return False
self.menu_hello = self.AddPopupMenu("Hello")
@ -24,6 +24,8 @@ class mycv_t(simplecustviewer_t):
for i in xrange(0, 100):
self.AddLine("Line %d" % i)
# self.Jump(0)
return True
def OnClick(self, shift):
@ -71,6 +73,7 @@ class mycv_t(simplecustviewer_t):
# ESCAPE?
if vkey == 27:
self.Close()
# VK_DELETE
elif vkey == 46:
n = self.GetLineNo()
if n is not None:
@ -129,10 +132,10 @@ class mycv_t(simplecustviewer_t):
Hint requested for the given line number.
@param lineno: The line number (zero based)
@return:
- string: a string containing the hint
- tuple(number of important lines, hint string)
- None: if no hint available
"""
return "OnHint, line=%d" % lineno
return (1, "OnHint, line=%d" % lineno)
def OnPopupMenu(self, menu_id):
"""

1281
python.cpp

File diff suppressed because it is too large Load Diff

View File

@ -276,40 +276,13 @@ def DecodeInstruction(ea):
Decodes an instruction and returns an insn_t like class
@param ea: address to decode
@return: None or an insn_t like structure
@return: None or a new insn_t instance
"""
inslen = idaapi.decode_insn(ea)
if inslen == 0:
return None
insn = idaapi.get_current_instruction()
if not insn:
return None
class _insn(object):
def __getitem__(self, index):
if index > len(self.Operands):
raise StopIteration
return self.Operands[index]
class _op(_reg_dtyp_t):
def __init__(self, op):
_copy_obj(op, self)
_reg_dtyp_t.__init__(self, op.reg, op.dtyp)
def is_reg(self, r):
"""Checks if the operand is the given processor register"""
return self.type == idaapi.o_reg and self == r
def has_reg(self, r):
"""Checks if the operand accesses the given processor register"""
return self.reg == r.reg
r = _copy_obj(insn, _insn())
r.Operands = [] # to hold the operands
for n in xrange(0, idaapi.UA_MAXOP):
t = idaapi.get_instruction_operand(insn, n)
if t.type == idaapi.o_void:
break
r.Operands.append(_op(t))
return r
return idaapi.cmd.copy()
def GetDataList(ea, count, itemsize=1):
@ -498,7 +471,7 @@ def Assemble(ea, line):
idc.Batch(old_batch)
return ret
def _copy_obj(src, dest):
def _copy_obj(src, dest, skip_list = None):
"""
Copy non private/non callable attributes from a class instance to another
@param src: Source class to copy from
@ -507,11 +480,17 @@ def _copy_obj(src, dest):
@return: A new instance or "dest"
"""
if type(dest) == types.StringType:
# instantiate a new destination class of the specified type name?
dest = new.classobj(dest, (), {})
for x in dir(src):
# skip special and private fields
if x.startswith("__") and x.endswith("__"):
continue
# skip items in the skip list
if skip_list and x in skip_list:
continue
t = getattr(src, x)
# skip callable
if callable(t):
continue
setattr(dest, x, t)

View File

@ -237,7 +237,6 @@ NEF_NAME = idaapi.NEF_NAME # Rename entries
NEF_MAN = idaapi.NEF_MAN # Manual load
NEF_FILL = idaapi.NEF_FILL # Fill segment gaps
NEF_IMPS = idaapi.NEF_IMPS # Create imports section
NEF_TIGHT = idaapi.NEF_TIGHT # Don't align segments (OMF)
NEF_FIRST = idaapi.NEF_FIRST # This is the first file loaded
NEF_CODE = idaapi.NEF_CODE # for load_binary_file:
NEF_RELOAD = idaapi.NEF_RELOAD # reload the file at the same place:
@ -677,7 +676,7 @@ def MakeArray(ea, nitems):
if idaapi.isStruct(flags):
ti = idaapi.opinfo_t()
assert idaapi.get_typeinfo(ea, 0, flags, ti), "get_typeinfo() failed"
assert idaapi.get_opinfo(ea, 0, flags, ti), "get_opinfo() failed"
itemsize = idaapi.get_data_elsize(ea, flags, ti)
tid = ti.tid
else:
@ -1695,6 +1694,53 @@ def Byte(ea):
return idaapi.get_byte(ea)
def __DbgValue(ea, len):
if len not in idaapi.__struct_unpack_table:
return None
r = idaapi.dbg_read_memory(ea, len)
return None if r is None else struct.unpack((">" if idaapi.cvar.inf.mf else "<") + idaapi.__struct_unpack_table[len][1], r)[0]
def DbgByte(ea):
"""
Get value of program byte using the debugger memory
@param ea: linear address
@return: The value or None on failure.
"""
return __DbgValue(ea, 1)
def DbgWord(ea):
"""
Get value of program word using the debugger memory
@param ea: linear address
@return: The value or None on failure.
"""
return __DbgValue(ea, 2)
def DbgDword(ea):
"""
Get value of program double-word using the debugger memory
@param ea: linear address
@return: The value or None on failure.
"""
return __DbgValue(ea, 4)
def DbgQword(ea):
"""
Get value of program quadro-word using the debugger memory
@param ea: linear address
@return: The value or None on failure.
"""
return __DbgValue(ea, 8)
def GetOriginalByte(ea):
"""
Get original value of program byte
@ -2082,7 +2128,7 @@ def GetOpnd(ea, n):
@return: the current text representation of operand
"""
res = idaapi.ua_outop(ea, n)
res = idaapi.ua_outop2(ea, n)
if not res:
return ""
@ -2102,60 +2148,48 @@ def GetOpType(ea, n):
@return: any of o_* constants or -1 on error
"""
inslen = idaapi.decode_insn(ea)
return -1 if inslen == 0 else idaapi.cmd.Operands[n].type
if inslen == 0:
return -1
insn = idaapi.get_current_instruction()
if not insn:
return -1
op = idaapi.get_instruction_operand(insn, n)
if not op:
return -1
return op.type
o_void = 0 # No Operand ----------
o_reg = 1 # General Register (al,ax,es,ds...) reg
o_mem = 2 # Direct Memory Reference (DATA) addr
o_phrase = 3 # Memory Ref [Base Reg + Index Reg] phrase
o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
o_imm = 5 # Immediate Value value
o_far = 6 # Immediate Far Address (CODE) addr
o_near = 7 # Immediate Near Address (CODE) addr
o_idpspec0 = 8 # IDP specific type
o_idpspec1 = 9 # IDP specific type
o_idpspec2 = 10 # IDP specific type
o_idpspec3 = 11 # IDP specific type
o_idpspec4 = 12 # IDP specific type
o_idpspec5 = 13 # IDP specific type
o_void = idaapi.o_void # No Operand ----------
o_reg = idaapi.o_reg # General Register (al,ax,es,ds...) reg
o_mem = idaapi.o_mem # Direct Memory Reference (DATA) addr
o_phrase = idaapi.o_phrase # Memory Ref [Base Reg + Index Reg] phrase
o_displ = idaapi.o_displ # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
o_imm = idaapi.o_imm # Immediate Value value
o_far = idaapi.o_far # Immediate Far Address (CODE) addr
o_near = idaapi.o_near # Immediate Near Address (CODE) addr
o_idpspec0 = idaapi.o_idpspec0 # IDP specific type
o_idpspec1 = idaapi.o_idpspec1 # IDP specific type
o_idpspec2 = idaapi.o_idpspec2 # IDP specific type
o_idpspec3 = idaapi.o_idpspec3 # IDP specific type
o_idpspec4 = idaapi.o_idpspec4 # IDP specific type
o_idpspec5 = idaapi.o_idpspec5 # IDP specific type
o_last = idaapi.o_last # first unused type
# x86
o_trreg = o_idpspec0 # trace register
o_dbreg = o_idpspec1 # debug register
o_crreg = o_idpspec2 # control register
o_fpreg = o_idpspec3 # floating point register
o_mmxreg = o_idpspec4 # mmx register
o_xmmreg = o_idpspec5 # xmm register
o_trreg = idaapi.o_idpspec0 # trace register
o_dbreg = idaapi.o_idpspec1 # debug register
o_crreg = idaapi.o_idpspec2 # control register
o_fpreg = idaapi.o_idpspec3 # floating point register
o_mmxreg = idaapi.o_idpspec4 # mmx register
o_xmmreg = idaapi.o_idpspec5 # xmm register
# arm
o_reglist = o_idpspec1 # Register list (for LDM/STM)
o_creglist = o_idpspec2 # Coprocessor register list (for CDP)
o_creg = o_idpspec3 # Coprocessor register (for LDC/STC)
o_fpreg = o_idpspec4 # Floating point register
o_fpreglist = o_idpspec5 # Floating point register list
o_text = (o_idpspec5+1) # Arbitrary text stored in the operand
o_reglist = idaapi.o_idpspec1 # Register list (for LDM/STM)
o_creglist = idaapi.o_idpspec2 # Coprocessor register list (for CDP)
o_creg = idaapi.o_idpspec3 # Coprocessor register (for LDC/STC)
o_fpreg = idaapi.o_idpspec4 # Floating point register
o_fpreglist = idaapi.o_idpspec5 # Floating point register list
o_text = (idaapi.o_idpspec5+1) # Arbitrary text stored in the operand
# ppc
o_spr = o_idpspec0 # Special purpose register
o_twofpr = o_idpspec1 # Two FPRs
o_shmbme = o_idpspec2 # SH & MB & ME
o_crf = o_idpspec3 # crfield x.reg
o_crb = o_idpspec4 # crbit x.reg
o_dcr = o_idpspec5 # Device control register
o_spr = idaapi.o_idpspec0 # Special purpose register
o_twofpr = idaapi.o_idpspec1 # Two FPRs
o_shmbme = idaapi.o_idpspec2 # SH & MB & ME
o_crf = idaapi.o_idpspec3 # crfield x.reg
o_crb = idaapi.o_idpspec4 # crbit x.reg
o_dcr = idaapi.o_idpspec5 # Device control register
def GetOperandValue(ea, n):
"""
@ -2177,12 +2211,7 @@ def GetOperandValue(ea, n):
inslen = idaapi.decode_insn(ea)
if inslen == 0:
return -1
insn = idaapi.get_current_instruction()
if not insn:
return -1
op = idaapi.get_instruction_operand(insn, n)
op = idaapi.cmd.Operands[n]
if not op:
return -1
@ -2251,8 +2280,16 @@ def AltOp(ea, n):
"""
return idaapi.get_forced_operand(ea, n)
ASCSTR_C = idaapi.ASCSTR_TERMCHR # C-style ASCII string
ASCSTR_PASCAL = idaapi.ASCSTR_PASCAL # Pascal-style ASCII string (length byte)
ASCSTR_LEN2 = idaapi.ASCSTR_LEN2 # Pascal-style, length is 2 bytes
ASCSTR_UNICODE = idaapi.ASCSTR_UNICODE # Unicode string
ASCSTR_LEN4 = idaapi.ASCSTR_LEN4 # Pascal-style, length is 4 bytes
ASCSTR_ULEN2 = idaapi.ASCSTR_ULEN2 # Pascal-style Unicode, length is 2 bytes
ASCSTR_ULEN4 = idaapi.ASCSTR_ULEN4 # Pascal-style Unicode, length is 4 bytes
ASCSTR_LAST = idaapi.ASCSTR_LAST # Last string type
def GetString(ea, length = -1, strtype = idaapi.ASCSTR_TERMCHR):
def GetString(ea, length = -1, strtype = ASCSTR_C):
"""
Get string contents
@param ea: linear address
@ -2277,21 +2314,11 @@ def GetStringType(ea):
"""
ti = idaapi.opinfo_t()
if idaapi.get_typeinfo(ea, 0, GetFlags(ea), ti):
if idaapi.get_opinfo(ea, 0, GetFlags(ea), ti):
return ti.strtype
else:
return None
ASCSTR_C = idaapi.ASCSTR_TERMCHR # C-style ASCII string
ASCSTR_PASCAL = idaapi.ASCSTR_PASCAL # Pascal-style ASCII string (length byte)
ASCSTR_LEN2 = idaapi.ASCSTR_LEN2 # Pascal-style, length is 2 bytes
ASCSTR_UNICODE = idaapi.ASCSTR_UNICODE # Unicode string
ASCSTR_LEN4 = idaapi.ASCSTR_LEN4 # Pascal-style, length is 4 bytes
ASCSTR_ULEN2 = idaapi.ASCSTR_ULEN2 # Pascal-style Unicode, length is 2 bytes
ASCSTR_ULEN4 = idaapi.ASCSTR_ULEN4 # Pascal-style Unicode, length is 4 bytes
ASCSTR_LAST = idaapi.ASCSTR_LAST # Last string type
# The following functions search for the specified byte
# ea - address to start from
# flag is combination of the following bits
@ -3876,9 +3903,7 @@ def GetFunctionAttr(ea, attr):
"""
func = idaapi.get_func(ea)
if func:
return _IDC_GetAttr(func, _FUNCATTRMAP, attr)
return BADADDR
return _IDC_GetAttr(func, _FUNCATTRMAP, attr) if func else BADADDR
def SetFunctionAttr(ea, attr, value):
@ -3960,7 +3985,7 @@ def GetFunctionFlags(ea):
FUNC_NORET = idaapi.FUNC_NORET # function doesn't return
FUNC_FAR = idaapi.FUNC_FAR # far function
FUNC_LIB = idaapi.FUNC_LIB # library function
FUNC_STATIC = idaapi.FUNC_STATIC # static function
FUNC_STATICDEF= idaapi.FUNC_STATICDEF# static function
FUNC_FRAME = idaapi.FUNC_FRAME # function uses frame pointer (BP)
FUNC_USERFAR = idaapi.FUNC_USERFAR # user has specified far-ness
# of the function
@ -5514,7 +5539,7 @@ def GetConstByName(name):
@return: ID of constant or -1
"""
return idaapi.get_const_by_name(name)
return idaapi.get_enum_member_by_name(name)
def GetConstValue(const_id):
@ -5525,7 +5550,7 @@ def GetConstValue(const_id):
@return: value of constant or 0
"""
return idaapi.get_const_value(const_id)
return idaapi.get_enum_member_value(const_id)
def GetConstBmask(const_id):
@ -5537,7 +5562,7 @@ def GetConstBmask(const_id):
@return: bitmask of constant or 0
ordinary enums have bitmask = -1
"""
return idaapi.get_const_bmask(const_id)
return idaapi.get_enum_member_bmask(const_id)
def GetConstEnum(const_id):
@ -5549,7 +5574,7 @@ def GetConstEnum(const_id):
@return: id of enum the constant belongs to.
-1 if const_id is bad.
"""
return idaapi.get_const_enum(const_id)
return idaapi.get_enum_member_enum(const_id)
def GetConstEx(enum_id, value, serial, bmask):
@ -5565,7 +5590,7 @@ def GetConstEx(enum_id, value, serial, bmask):
@return: id of constant or -1 if error
"""
return idaapi.get_const(enum_id, value, serial, bmask)
return idaapi.get_enum_member(enum_id, value, serial, bmask)
def GetFirstBmask(enum_id):
@ -5685,7 +5710,7 @@ def GetFirstConst(enum_id, bmask):
@return: value of constant or -1 no constants are defined
All constants are sorted by their values as unsigned longs.
"""
return idaapi.get_first_const(enum_id, bmask)
return idaapi.get_first_enum_member(enum_id, bmask)
def GetLastConst(enum_id, bmask):
@ -5699,7 +5724,7 @@ def GetLastConst(enum_id, bmask):
All constants are sorted by their values
as unsigned longs.
"""
return idaapi.get_last_const(enum_id, bmask)
return idaapi.get_last_enum_member(enum_id, bmask)
def GetNextConst(enum_id, value, bmask):
@ -5714,7 +5739,7 @@ def GetNextConst(enum_id, value, bmask):
value. -1 no such constants exist.
All constants are sorted by their values as unsigned longs.
"""
return idaapi.get_next_const(enum_id, value, bmask)
return idaapi.get_next_enum_member(enum_id, value, bmask)
def GetPrevConst(enum_id, value, bmask):
@ -5730,7 +5755,7 @@ def GetPrevConst(enum_id, value, bmask):
value. -1 no such constants exist.
All constants are sorted by their values as unsigned longs.
"""
return idaapi.get_prev_const(enum_id, value, bmask)
return idaapi.get_prev_enum_member(enum_id, value, bmask)
def GetConstName(const_id):
@ -5741,7 +5766,7 @@ def GetConstName(const_id):
Returns: name of constant
"""
name = idaapi.get_const_name(const_id)
name = idaapi.get_enum_member_name(const_id)
if not name:
return ""
@ -5758,7 +5783,7 @@ def GetConstCmt(const_id, repeatable):
@return: comment string
"""
cmt = idaapi.get_const_cmt(const_id, repeatable)
cmt = idaapi.get_enum_member_cmt(const_id, repeatable)
if not cmt:
return ""
@ -5910,16 +5935,16 @@ def AddConstEx(enum_id, name, value, bmask):
ordinary enums accept only -1 as a bitmask
all bits set in value should be set in bmask too
@return: 0-ok, otherwise error code (one of CONST_ERROR_*)
@return: 0-ok, otherwise error code (one of ENUM_MEMBER_ERROR_*)
"""
return idaapi.add_const(enum_id, name, value, bmask)
return idaapi.add_enum_member(enum_id, name, value, bmask)
CONST_ERROR_NAME = idaapi.CONST_ERROR_NAME # already have member with this name (bad name)
CONST_ERROR_VALUE = idaapi.CONST_ERROR_VALUE # already have member with this value
CONST_ERROR_ENUM = idaapi.CONST_ERROR_ENUM # bad enum id
CONST_ERROR_MASK = idaapi.CONST_ERROR_MASK # bad bmask
CONST_ERROR_ILLV = idaapi.CONST_ERROR_ILLV # bad bmask and value combination (~bmask & value != 0)
ENUM_MEMBER_ERROR_NAME = idaapi.ENUM_MEMBER_ERROR_NAME # already have member with this name (bad name)
ENUM_MEMBER_ERROR_VALUE = idaapi.ENUM_MEMBER_ERROR_VALUE # already have member with this value
ENUM_MEMBER_ERROR_ENUM = idaapi.ENUM_MEMBER_ERROR_ENUM # bad enum id
ENUM_MEMBER_ERROR_MASK = idaapi.ENUM_MEMBER_ERROR_MASK # bad bmask
ENUM_MEMBER_ERROR_ILLV = idaapi.ENUM_MEMBER_ERROR_ILLV # bad bmask and value combination (~bmask & value != 0)
def DelConstEx(enum_id, value, serial, bmask):
@ -5935,7 +5960,7 @@ def DelConstEx(enum_id, value, serial, bmask):
@return: 1-ok, 0-failed
"""
return idaapi.del_const(enum_id, value, serial, bmask)
return idaapi.del_enum_member(enum_id, value, serial, bmask)
def SetConstName(const_id, name):
@ -5947,7 +5972,7 @@ def SetConstName(const_id, name):
@return: 1-ok, 0-failed
"""
return idaapi.set_const_name(const_id, name)
return idaapi.set_enum_member_name(const_id, name)
def SetConstCmt(const_id, cmt, repeatable):
@ -5962,7 +5987,7 @@ def SetConstCmt(const_id, cmt, repeatable):
@return: 1-ok, 0-failed
"""
return idaapi.set_const_cmt(const_id, cmt, repeatable)
return idaapi.set_enum_member_cmt(const_id, cmt, repeatable)
#----------------------------------------------------------------------------
# A R R A Y S I N I D C
@ -6116,19 +6141,14 @@ def DelLineNumber(ea):
# T Y P E L I B R A R I E S
#----------------------------------------------------------------------------
def LoadTil(name, tildir=None):
def LoadTil(name):
"""
Load a type library
@param name: name of type library.
@param tildir: drectory to load the TIL from (defaults to "til/pc")
@return: 1-ok, 0-failed.
"""
if not tildir:
tildir = "til" + os.sep + "pc"
til = idaapi.load_til(tildir, name)
til = idaapi.add_til2(name, idaapi.ADDTIL_DEFAULT)
if til:
return 1
@ -6192,7 +6212,7 @@ def SetType(ea, newtype):
@return: 1-ok, 0-failed.
"""
return idaapi.apply_cdecl(ea, newtype)
return idaapi.apply_cdecl2(idaapi.cvar.idati, ea, newtype)
def ParseType(inputtype, flags):
"""
@ -7140,19 +7160,11 @@ def GetBptAttr(ea, bptattr):
return -1
BPTATTR_EA = 0 # starting address of the breakpoint
BPTATTR_SIZE = 4 # size of the breakpoint (undefined for software breakpoint)
BPTATTR_TYPE = 8 # type of the breakpoint
BPTATTR_COUNT = 12 # number of times this breakpoint is hit before stopping
BPTATTR_FLAGS = 16 # Breakpoint attributes:
BPTATTR_COND = 20 # Breakpoint condition NOTE: the return value is a string in this case
BPTATTR_EA = 1 # starting address of the breakpoint
BPTATTR_SIZE = 2 # size of the breakpoint (undefined for software breakpoint)
if __EA64__:
BPTATTR_SIZE = 8
BPTATTR_TYPE = 16
BPTATTR_COUNT = 20
BPTATTR_FLAGS = 24
BPTATTR_COND = 28
# type of the breakpoint
BPTATTR_TYPE = 3
# Breakpoint types:
BPT_EXEC = 0 # Hardware: Execute instruction
@ -7160,8 +7172,14 @@ BPT_WRITE = 1 # Hardware: Write access
BPT_RDWR = 3 # Hardware: Read/write access
BPT_SOFT = 4 # Software breakpoint
BPTATTR_COUNT = 4
BPTATTR_FLAGS = 5
BPT_BRK = 0x01 # the debugger stops on this breakpoint
BPT_TRACE = 0x02 # the debugger adds trace information when this breakpoint is reached
BPT_UPDMEM = 0x04 # update memory contents before evaluating bpt condition
BPT_UPDSEG = 0x08 # update memory config before evaluating bpt condition
BPTATTR_COND = 6 # Breakpoint condition. NOTE: the return value is a string in this case
def SetBptAttr(address, bptattr, value):
@ -7527,4 +7545,7 @@ SEGDEL_PERM = 0x0001 # permanently, i.e. disable addresses
SEGDEL_KEEP = 0x0002 # keep information (code & data, etc)
SEGDEL_SILENT = 0x0004 # be silent
ARGV = []
"""The command line arguments passed to IDA via the -S switch."""
# END OF IDC COMPATIBILY CODE

View File

@ -15,70 +15,29 @@ import os
import sys
import time
import warnings
import _idaapi
# __EA64__ is set if IDA is running in 64-bit mode
__EA64__ = _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL
# -----------------------------------------------------------------------
def addscriptpath(script):
# Take over the standard text outputs
# -----------------------------------------------------------------------
class IDAPythonStdOut:
"""
Add the path part of the scriptfile to the system path to
allow modules to be loaded from the same place.
Each path is added only once.
Dummy file-like class that receives stout and stderr
"""
pathfound = 0
def write(self, text):
# Swap out the unprintable characters
text = text.decode('ascii', 'replace').encode('ascii', 'replace')
# Print to IDA message window
_idaapi.msg(text.replace("%", "%%"))
scriptpath = os.path.dirname(script)
def flush(self):
pass
for pathitem in sys.path:
if pathitem == scriptpath:
pathfound = 1
break
if pathfound == 0:
sys.path.append(scriptpath)
# Add the script to ScriptBox if it's not there yet
if not script in scriptbox.list:
scriptbox.list.insert(0, script)
# ------------------------------------------------------------
def runscript(script):
"""
Run the specified script after adding its directory path to
system path.
This function is used by the low-level plugin code.
"""
addscriptpath(script)
watchdog.reset()
# Save the argv, path, I/O and base modules for later cleanup
argv = sys.argv
path = sys.path
stdio = [sys.stdin, sys.stdout, sys.stderr]
basemodules = sys.modules.copy()
sys.argv = [ script ]
# Adjust the __file__ path in the globals we pass to the script
g = globals()
old__file__ = g['__file__'] if '__file__' in g else ''
g['__file__'] = script
try:
execfile(script, g)
except:
raise
finally:
# Restore the globals to the state before the script was run
g['__file__'] = old__file__
sys.argv = argv
sys.path = path
sys.stdin, sys.stdout, sys.stderr = stdio
# Clean up the modules loaded by the script
for module in sys.modules.keys():
if not module in basemodules:
del(sys.modules[module])
def isatty(self):
return False
# -----------------------------------------------------------------------
def print_banner():
@ -96,26 +55,9 @@ def print_banner():
print sepline
# -----------------------------------------------------------------------
# Take over the standard text outputs
# -----------------------------------------------------------------------
class MyStdOut:
"""
Dummy file-like class that receives stout and stderr
"""
def write(self, text):
# Swap out the unprintable characters
text = text.decode('ascii', 'replace').encode('ascii', 'replace')
# Print to IDA message window
_idaapi.msg(text.replace("%", "%%"))
def flush(self):
pass
def isatty(self):
return False
# Redirect stderr and stdout to the IDA message window
sys.stdout = sys.stderr = MyStdOut()
sys.stdout = sys.stderr = IDAPythonStdOut()
# Assign a default sys.argv
sys.argv = [""]
@ -123,106 +65,15 @@ sys.argv = [""]
# Have to make sure Python finds our modules
sys.path.append(_idaapi.idadir("python"))
# -----------------------------------------------------------------------
# Import all the required modules
# -----------------------------------------------------------------------
from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall
from idc import *
from idautils import *
import idaapi
# -----------------------------------------------------------------------
# Build up the ScriptBox tool
# -----------------------------------------------------------------------
class ScriptBox(Choose):
def __init__(self, list=None):
if list:
self.list = list
else:
self.list = []
Choose.__init__(self, self.list, "ScriptBox", 1)
self.width = 50
def run(self):
if len(self.list) == 0:
Warning("ScriptBox history is empty.\nRun some script with Alt-9 and try again.")
return None
n = self.choose()
if n > 0:
runscript(self.list[n-1])
def addscript(self, scriptpath):
self.list.append(scriptpath)
scriptbox = ScriptBox()
# -----------------------------------------------------------------------
# Watchdog to catch runaway scripts after a specified timeout
#
# Usage:
# watchdog.install()
# watchdog.activate(10) # Use 10-second timeout
#
# Note: The watchdog only works for code running inside
# functions, not in global/module namespace.
# -----------------------------------------------------------------------
class WatchDog():
"""
Python tracer-based watchdog class
"""
def __init__(self, timeout=10):
self.timestamp = 0
self.timeout = timeout
self.installed = False
self.active = False
def install(self):
""" Install the tracer function, required for the watchdog """
if not self.installed:
sys.settrace(self.tracer)
self.installed = True
def activate(self, timeout=None):
""" Activate the watchdog, with optional timeout change """
assert self.installed, "WatchDog must be installed before activating"
if timeout:
self.timeout = timeout
self.reset()
self.active = True
def deactivate(self):
""" Deactivate the watchdog """
self.active = True
def reset(self):
""" Reset the timer, useful for long-running scripts """
self.timestamp = time.clock()
def tracer(self, frame, event, arg):
""" Tracer function that receives the tracing events """
if not self.active:
return None
if event == 'line':
if time.clock() - self.timestamp > self.timeout:
if AskYN(0, "The script has not finished in %d seconds\nWould you like to stop it now?" % self.timeout) == 1:
raise KeyboardInterrupt
else:
self.timestamp = time.clock()
return self.tracer
watchdog = WatchDog(10)
# -----------------------------------------------------------------------
# Load the users personal init file
userrc = get_user_idadir() + os.sep + "idapythonrc.py"
# -----------------------------------------------------------------------
if os.path.exists(userrc):
runscript(userrc)
# Remove the user script from the history
del scriptbox.list[0]
idaapi.IDAPython_ExecScript(userrc, globals())
# All done, ready to rock.

View File

@ -7,17 +7,25 @@
#define PYUL_DEFINED
#ifdef __EA64__
typedef unsigned PY_LONG_LONG pyul_t;
typedef PY_LONG_LONG pyl_t;
#else
typedef unsigned long pyul_t;
typedef long pyl_t;
#endif
#endif
#ifdef __EA64__
#define PY_FMT64 "K"
#define PY_SFMT64 "L"
#else
#define PY_FMT64 "k"
#define PY_SFMT64 "l"
#endif
#define S_IDAAPI_MODNAME "idaapi"
#define S_IDC_MODNAME "idc"
#define S_IDAAPI_EXECSCRIPT "IDAPython_ExecScript"
// Vector of PyObject*
typedef qvector<PyObject *> ppyobject_vec_t;
@ -27,6 +35,19 @@ typedef qvector<PyObject *> ppyobject_vec_t;
#define PY_ICID_BYREF 1
#define PY_ICID_OPAQUE 2
//------------------------------------------------------------------------
// Constants used with the notify_when()
#define NW_OPENIDB 0x0001
#define NW_OPENIDB_SLOT 0
#define NW_CLOSEIDB 0x0002
#define NW_CLOSEIDB_SLOT 1
#define NW_INITIDA 0x0004
#define NW_INITIDA_SLOT 2
#define NW_TERMIDA 0x0008
#define NW_TERMIDA_SLOT 3
#define NW_REMOVE 0x0010 // Uninstall flag
#define NW_EVENTSCNT 4 // Count of notify_when codes
//------------------------------------------------------------------------
// Constants used by the pyvar_to_idcvar and idcvar_to_pyvar functions
#define CIP_FAILED -1 // Conversion error
@ -36,6 +57,8 @@ typedef qvector<PyObject *> ppyobject_vec_t;
//------------------------------------------------------------------------
// All the exported functions from PyWraps are forward declared here
insn_t *insn_t_get_clink(PyObject *self);
op_t *op_t_get_clink(PyObject *self);
// Tries to import a module and swallows the exception if it fails and returns NULL
PyObject *PyImport_TryImportModule(const char *name);
@ -58,6 +81,12 @@ bool PyGetError(qstring *out = NULL);
// If an error occured (it calls PyGetError) it displays it and return TRUE
bool PyShowErr(const char *cb_name);
// Utility function to create a class instance whose constructor takes zero arguments
PyObject *create_idaapi_class_instance0(const char *clsname);
// Utility function to create linked class instances
PyObject *create_idaapi_linked_class_instance(const char *clsname, void *lnk);
// [De]Initializes PyWraps
bool init_pywraps();
void deinit_pywraps();
@ -65,6 +94,10 @@ void deinit_pywraps();
// Returns the string representation of a PyObject
bool PyObjectToString(PyObject *obj, qstring *out);
// Utility function to convert a python object to an IDC object
// and sets a python exception on failure.
bool convert_pyobj_to_idc_exc(PyObject *py_obj, idc_value_t *idc_obj);
// Converts Python variable to IDC variable
// gvar_sn is used in case the Python object was a created from a call to idcvar_to_pyvar and the IDC object was a VT_REF
int pyvar_to_idcvar(
@ -78,5 +111,18 @@ int idcvar_to_pyvar(
const idc_value_t &idc_var,
PyObject **py_var);
// Walks a Python list or Sequence and calls the callback
Py_ssize_t pyvar_walk_list(
PyObject *py_list,
int (idaapi *cb)(PyObject *py_item, Py_ssize_t index, void *ud) = NULL,
void *ud = NULL);
// Returns a reference to a class
PyObject *get_idaapi_attr(const char *attr);
// notify_when()
bool pywraps_nw_term();
bool pywraps_nw_notify(int slot, ...);
bool pywraps_nw_init();
#endif

View File

@ -61,9 +61,17 @@
%ignore term_flags;
%ignore reset_flags;
%ignore flush_flags;
// TODO: These could be fixed if someone needs them.
%ignore data_type_t;
%ignore data_format_t;
%ignore get_custom_data_type;
%ignore get_custom_data_format;
%ignore unregister_custom_data_format;
%ignore register_custom_data_format;
%ignore unregister_custom_data_type;
%ignore register_custom_data_type;
%ignore get_many_bytes;
// TODO: This could be fixed (if needed)
%ignore set_dbgmem_source;
%include "bytes.hpp"
@ -76,6 +84,12 @@
%rename (nextthat) py_nextthat;
%rename (prevthat) py_prevthat;
%rename (get_custom_data_type) py_get_custom_data_type;
%rename (get_custom_data_format) py_get_custom_data_format;
%rename (unregister_custom_data_format) py_unregister_custom_data_format;
%rename (register_custom_data_format) py_register_custom_data_format;
%rename (unregister_custom_data_type) py_unregister_custom_data_type;
%rename (register_custom_data_type) py_register_custom_data_type;
%rename (get_many_bytes) py_get_many_bytes;
%{
@ -95,10 +109,505 @@ static bool idaapi py_testf_cb(flags_t flags, void *ud)
// Wraps the (next|prev)that()
static ea_t py_npthat(ea_t ea, ea_t bound, PyObject *py_callable, bool next)
{
if (!PyCallable_Check(py_callable))
if ( !PyCallable_Check(py_callable) )
return BADADDR;
return (next ? nextthat : prevthat)(ea, bound, py_testf_cb, py_callable);
}
//------------------------------------------------------------------------
class py_custom_data_type_t
{
data_type_t dt;
qstring name, menu_name, hotkey, asm_keyword;
int dtid; // The data format id
PyObject *py_self; // Associated Python object
// may create data? NULL means always may
static bool idaapi s_may_create_at(
void *ud, // user-defined data
ea_t ea, // address of the future item
size_t nbytes) // size of the future item
{
py_custom_data_type_t *_this = (py_custom_data_type_t *)ud;
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_MAY_CREATE_AT, PY_FMT64 PY_FMT64, pyul_t(ea), pyul_t(nbytes));
PyShowErr(S_MAY_CREATE_AT);
bool ok = py_result != NULL && PyObject_IsTrue(py_result);
Py_XDECREF(py_result);
return ok;
}
// !=NULL means variable size datatype
static asize_t idaapi s_calc_item_size(
// This function is used to determine
// size of the (possible) item at 'ea'
void *ud, // user-defined data
ea_t ea, // address of the item
asize_t maxsize) // maximal size of the item
{
// Returns: 0-no such item can be created/displayed
// this callback is required only for varsize datatypes
py_custom_data_type_t *_this = (py_custom_data_type_t *)ud;
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_CALC_ITEM_SIZE, PY_FMT64 PY_FMT64, pyul_t(ea), pyul_t(maxsize));
if ( PyShowErr(S_CALC_ITEM_SIZE) || py_result == NULL )
return 0;
uint64 num = 0;
PyGetNumber(py_result, &num);
Py_XDECREF(py_result);
return asize_t(num);
}
public:
const char *get_name() const { return name.c_str(); }
py_custom_data_type_t()
{
dtid = -1;
py_self = NULL;
}
int register_dt(PyObject *py_obj)
{
// Already registered?
if ( dtid >= 0 )
return dtid;
memset(&dt, 0, sizeof(dt));
dt.cbsize = sizeof(dt);
dt.ud = this;
PyObject *py_attr = NULL;
do
{
// name
py_attr = PyObject_TryGetAttrString(py_obj, S_NAME);
if ( py_attr == NULL || !PyString_Check(py_attr) )
break;
name = PyString_AsString(py_attr);
dt.name = name.c_str();
Py_DECREF(py_attr);
// value_size
py_attr = PyObject_TryGetAttrString(py_obj, S_VALUE_SIZE);
if ( py_attr != NULL )
dt.value_size = PyInt_AsLong(py_attr);
Py_XDECREF(py_attr);
// props
py_attr = PyObject_TryGetAttrString(py_obj, S_PROPS);
if ( py_attr != NULL )
dt.props = PyInt_AsLong(py_attr);
Py_XDECREF(py_attr);
// menu_name
py_attr = PyObject_TryGetAttrString(py_obj, S_MENU_NAME);
if ( py_attr != NULL && PyString_Check(py_attr) )
{
menu_name = PyString_AsString(py_attr);
dt.menu_name = menu_name.c_str();
}
Py_XDECREF(py_attr);
// asm_keyword
py_attr = PyObject_TryGetAttrString(py_obj, S_ASM_KEYWORD);
if ( py_attr != NULL && PyString_Check(py_attr) )
{
asm_keyword = PyString_AsString(py_attr);
dt.asm_keyword = asm_keyword.c_str();
}
Py_XDECREF(py_attr);
// hotkey
py_attr = PyObject_TryGetAttrString(py_obj, S_HOTKEY);
if ( py_attr != NULL && PyString_Check(py_attr) )
{
hotkey = PyString_AsString(py_attr);
dt.hotkey = hotkey.c_str();
}
Py_XDECREF(py_attr);
// may_create_at
py_attr = PyObject_TryGetAttrString(py_obj, S_MAY_CREATE_AT);
if ( py_attr != NULL && PyCallable_Check(py_attr) )
dt.may_create_at = s_may_create_at;
Py_XDECREF(py_attr);
// calc_item_size
py_attr = PyObject_TryGetAttrString(py_obj, S_CALC_ITEM_SIZE);
if ( py_attr != NULL && PyCallable_Check(py_attr) )
dt.calc_item_size = s_calc_item_size;
Py_XDECREF(py_attr);
// Clear attribute
py_attr = NULL;
// Now try to register
dtid = register_custom_data_type(&dt);
if ( dtid < 0 )
break;
// Hold reference to the PyObject
Py_INCREF(py_obj);
py_self = py_obj;
py_attr = PyInt_FromLong(dtid);
PyObject_SetAttrString(py_obj, S_ID, py_attr);
Py_DECREF(py_attr);
// Done with attribute
py_attr = NULL;
} while ( false );
Py_XDECREF(py_attr);
return dtid;
}
bool unregister_dt()
{
if ( dtid < 0 )
return true;
if ( !unregister_custom_data_type(dtid) )
return false;
// Release reference of Python object
Py_XDECREF(py_self);
py_self = NULL;
dtid = -1;
return true;
}
~py_custom_data_type_t()
{
unregister_dt();
}
};
typedef std::map<int, py_custom_data_type_t *> py_custom_data_type_map_t;
static py_custom_data_type_map_t py_dt_map;
//------------------------------------------------------------------------
class py_custom_data_format_t
{
private:
data_format_t df;
int dfid;
PyObject *py_self;
qstring name, menu_name, hotkey;
static bool idaapi s_print( // convert to colored string
void *ud, // user-defined data
qstring *out, // output buffer. may be NULL
const void *value, // value to print. may not be NULL
asize_t size, // size of value in bytes
ea_t current_ea, // current address (BADADDR if unknown)
int operand_num, // current operand number
int dtid) // custom data type id
{
// Build a string from the buffer
PyObject *py_value = PyString_FromStringAndSize((const char *)value, Py_ssize_t(size));
if ( py_value == NULL )
return false;
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
PyObject *py_result = PyObject_CallMethod(
_this->py_self,
(char *)S_PRINTF,
"O" PY_FMT64 "ii",
py_value,
pyul_t(current_ea),
operand_num,
dtid);
// Done with the string
Py_DECREF(py_value);
// Error while calling the function?
if ( PyShowErr(S_PRINTF) || py_result == NULL )
return false;
bool ok = false;
if ( PyString_Check(py_result) )
{
Py_ssize_t len;
char *buf;
if ( out != NULL && PyString_AsStringAndSize(py_result, &buf, &len) != -1 )
{
out->qclear();
out->append(buf, len);
}
ok = true;
}
Py_DECREF(py_result);
return ok;
}
static bool idaapi s_scan( // convert from uncolored string
void *ud, // user-defined data
bytevec_t *value, // output buffer. may be NULL
const char *input, // input string. may not be NULL
ea_t current_ea, // current address (BADADDR if unknown)
int operand_num, // current operand number (-1 if unknown)
qstring *errstr) // buffer for error message
{
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
PyObject *py_result = PyObject_CallMethod(
_this->py_self,
(char *)S_SCAN,
"s" PY_FMT64,
input,
pyul_t(current_ea),
operand_num);
// Error while calling the function?
if ( PyShowErr(S_SCAN) || py_result == NULL)
return false;
bool ok = false;
do
{
// We expect a tuple(bool, string|None)
if ( !PyTuple_Check(py_result) || PyTuple_Size(py_result) != 2 )
break;
// Borrow references
PyObject *py_bool = PyTuple_GetItem(py_result, 0);
PyObject *py_val = PyTuple_GetItem(py_result, 1);
// Get return code from Python
ok = PyObject_IsTrue(py_bool);
// We expect None or the value (depending on probe)
if ( ok )
{
// Probe-only? Then okay, no need to extract the 'value'
if ( value == NULL )
break;
Py_ssize_t len;
char *buf;
if ( PyString_AsStringAndSize(py_val, &buf, &len) != -1 )
{
value->qclear();
value->append(buf, len);
}
}
// An error occured?
else
{
// Make sure the user returned (False, String)
if ( py_bool != Py_False || !PyString_Check(py_val) )
{
*errstr = "Invalid return value returned from the Python callback!";
break;
}
// Get the error message
*errstr = PyString_AsString(py_val);
}
} while ( false );
Py_DECREF(py_result);
return ok;
}
static void idaapi s_analyze( // analyze custom data format occurrence
void *ud, // user-defined data
ea_t current_ea, // current address (BADADDR if unknown)
int operand_num) // current operand number
// this callback can be used to create
// xrefs from the current item.
// this callback may be missing.
{
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_ANALYZE, PY_FMT64 "i", pyul_t(current_ea),operand_num);
PyShowErr(S_ANALYZE);
Py_XDECREF(py_result);
}
public:
py_custom_data_format_t()
{
dfid = -1;
py_self = NULL;
}
const char *get_name() const { return name.c_str(); }
int register_df(int dtid, PyObject *py_obj)
{
// Already registered?
if ( dfid >= 0 )
return dfid;
memset(&df, 0, sizeof(df));
df.cbsize = sizeof(df);
df.ud = this;
PyObject *py_attr = NULL;
do
{
// name
py_attr = PyObject_TryGetAttrString(py_obj, S_NAME);
if ( py_attr == NULL || !PyString_Check(py_attr) )
break;
name = PyString_AsString(py_attr);
df.name = name.c_str();
Py_DECREF(py_attr);
// menu_name
py_attr = PyObject_TryGetAttrString(py_obj, S_MENU_NAME);
if ( py_attr != NULL && PyString_Check(py_attr) )
{
menu_name = PyString_AsString(py_attr);
df.menu_name = menu_name.c_str();
}
Py_XDECREF(py_attr);
// props
py_attr = PyObject_TryGetAttrString(py_obj, S_PROPS);
if ( py_attr != NULL )
df.props = PyInt_AsLong(py_attr);
Py_XDECREF(py_attr);
// hotkey
py_attr = PyObject_TryGetAttrString(py_obj, S_HOTKEY);
if ( py_attr != NULL && PyString_Check(py_attr) )
{
hotkey = PyString_AsString(py_attr);
df.hotkey = hotkey.c_str();
}
Py_XDECREF(py_attr);
// value_size
py_attr = PyObject_TryGetAttrString(py_obj, S_VALUE_SIZE);
if ( py_attr != NULL )
df.value_size = PyInt_AsLong(py_attr);
Py_XDECREF(py_attr);
// text_width
py_attr = PyObject_TryGetAttrString(py_obj, S_TEXT_WIDTH);
if ( py_attr != NULL )
df.text_width = PyInt_AsLong(py_attr);
Py_XDECREF(py_attr);
// print cb
py_attr = PyObject_TryGetAttrString(py_obj, S_PRINTF);
if ( py_attr != NULL && PyCallable_Check(py_attr) )
df.print = s_print;
Py_XDECREF(py_attr);
// scan cb
py_attr = PyObject_TryGetAttrString(py_obj, S_SCAN);
if ( py_attr != NULL && PyCallable_Check(py_attr) )
df.scan = s_scan;
Py_XDECREF(py_attr);
// analyze cb
py_attr = PyObject_TryGetAttrString(py_obj, S_ANALYZE);
if ( py_attr != NULL && PyCallable_Check(py_attr) )
df.analyze = s_analyze;
Py_XDECREF(py_attr);
// Done with attribute
py_attr = NULL;
// Now try to register
dfid = register_custom_data_format(dtid, &df);
if ( dfid < 0 )
break;
// Hold reference to the PyObject
Py_INCREF(py_obj);
py_self = py_obj;
py_attr = PyInt_FromLong(dfid);
PyObject_SetAttrString(py_obj, S_ID, py_attr);
Py_DECREF(py_attr);
py_attr = NULL;
} while ( false );
Py_XDECREF(py_attr);
return dfid;
}
bool unregister_df(int dtid)
{
// Never registered?
if ( dfid < 0 )
return true;
if ( !unregister_custom_data_format(dtid, dfid) )
return false;
// Release reference of Python object
Py_XDECREF(py_self);
py_self = NULL;
dfid = -1;
return true;
}
~py_custom_data_format_t()
{
}
};
//------------------------------------------------------------------------
// Helper class to bind <dtid, dfid> pairs to py_custom_data_format_t
class py_custom_data_format_list_t
{
struct py_custom_data_format_entry_t
{
int dtid;
int dfid;
py_custom_data_format_t *df;
};
typedef qvector<py_custom_data_format_entry_t> ENTRY;
ENTRY entries;
public:
typedef ENTRY::iterator POS;
void add(int dtid, int dfid, py_custom_data_format_t *df)
{
py_custom_data_format_entry_t &e = entries.push_back();
e.dtid = dtid;
e.dfid = dfid;
e.df = df;
}
py_custom_data_format_t *find(int dtid, int dfid, POS *loc = NULL)
{
for ( POS it=entries.begin(), it_end = entries.end(); it!=it_end; ++it )
{
if ( it->dfid == dfid && it->dtid == dtid )
{
if ( loc != NULL )
*loc = it;
return it->df;
}
}
return NULL;
}
void erase(POS &pos)
{
entries.erase(pos);
}
};
static py_custom_data_format_list_t py_df_list;
//------------------------------------------------------------------------
static PyObject *py_data_type_to_py_dict(const data_type_t *dt)
{
return Py_BuildValue("{s:" PY_FMT64 ",s:i,s:i,s:s,s:s,s:s,s:s}",
S_VALUE_SIZE, pyul_t(dt->value_size),
S_PROPS, dt->props,
S_CBSIZE, dt->cbsize,
S_NAME, dt->name == NULL ? "" : dt->name,
S_MENU_NAME, dt->menu_name == NULL ? "" : dt->menu_name,
S_HOTKEY, dt->hotkey == NULL ? "" : dt->hotkey,
S_ASM_KEYWORD, dt->asm_keyword == NULL ? "" : dt->asm_keyword);
}
//------------------------------------------------------------------------
static PyObject *py_data_format_to_py_dict(const data_format_t *df)
{
return Py_BuildValue("{s:i,s:i,s:i,s:" PY_FMT64 ",s:s,s:s,s:s}",
S_PROPS, df->props,
S_CBSIZE, df->cbsize,
S_TEXT_WIDTH, df->text_width,
S_VALUE_SIZE, pyul_t(df->value_size),
S_NAME, df->name == NULL ? "" : df->name,
S_MENU_NAME, df->menu_name == NULL ? "" : df->menu_name,
S_HOTKEY, df->hotkey == NULL ? "" : df->hotkey);
}
//</code(py_bytes)>
%}
@ -117,34 +626,441 @@ static ea_t py_prevthat(ea_t ea, ea_t minea, PyObject *callable)
}
//------------------------------------------------------------------------
// Get the specified number of bytes of the program into the buffer.
static PyObject *py_get_many_bytes(ea_t ea, int size)
/*
#<pydoc>
def get_many_bytes(ea):
"""
Get the specified number of bytes of the program into the buffer.
@param ea: program address
@param size: number of bytes to return
@return: None or the string buffer
"""
pass
#</pydoc>
*/
static PyObject *py_get_many_bytes(ea_t ea, unsigned int size)
{
do
{
if (size <= 0)
if ( size <= 0 )
break;
// Allocate memory
char *buf = (char *) qalloc(size);
if (buf == NULL)
// Allocate memory via Python
PyObject *py_buf = PyString_FromStringAndSize(NULL, Py_ssize_t(size));
if ( py_buf == NULL )
break;
// Read bytes
bool ok = get_many_bytes(ea, buf, size);
bool ok = get_many_bytes(ea, PyString_AsString(py_buf), size);
// If ok, create a python string
PyObject *py_buf;
if (ok)
py_buf = PyString_FromStringAndSize(buf, size);
// If failed, dispose the Python string
if ( !ok )
{
Py_DECREF(py_buf);
// Free buffer
qfree(buf);
py_buf = Py_None;
Py_INCREF(py_buf);
}
// Return buffer to Python
if (ok)
return py_buf;
} while (false);
} while ( false );
Py_RETURN_NONE;
}
//------------------------------------------------------------------------
/*
#<pydoc>
def register_custom_data_type(dt):
"""
Registers a custom data type.
@param dt: an instance of the data_type_t class
@return:
< 0 if failed to register
> 0 data type id
"""
pass
#</pydoc>
*/
// Given a py.data_format_t object, this function will register a datatype
static int py_register_custom_data_type(PyObject *py_dt)
{
py_custom_data_type_t *inst = new py_custom_data_type_t();
int r = inst->register_dt(py_dt);
if ( r < 0 )
{
delete inst;
return r;
}
// Insert the instance to the map
py_dt_map[r] = inst;
return r;
}
//------------------------------------------------------------------------
/*
#<pydoc>
def unregister_custom_data_type(dtid):
"""
Unregisters a custom data type.
@param dtid: the data type id
@return: Boolean
"""
pass
#</pydoc>
*/
static bool py_unregister_custom_data_type(int dtid)
{
py_custom_data_type_map_t::iterator it = py_dt_map.find(dtid);
// Maybe the user is trying to unregister a C api dt?
if ( it == py_dt_map.end() )
return unregister_custom_data_type(dtid);
py_custom_data_type_t *inst = it->second;
bool ok = inst->unregister_dt();
// Perhaps it was automatically unregistered because the idb was close?
if ( !ok )
{
// Is this type still registered with IDA?
// If not found then mark the context for deletion
ok = find_custom_data_type(inst->get_name()) < 0;
}
if ( ok )
{
py_dt_map.erase(it);
delete inst;
}
return ok;
}
//------------------------------------------------------------------------
/*
#<pydoc>
def register_custom_data_format(dtid, df):
"""
Registers a custom data format with a given data type.
@param dtid: data type id
@param df: an instance of data_format_t
@return:
< 0 if failed to register
> 0 data format id
"""
pass
#</pydoc>
*/
static int py_register_custom_data_format(int dtid, PyObject *py_df)
{
py_custom_data_format_t *inst = new py_custom_data_format_t();
int r = inst->register_df(dtid, py_df);
if ( r < 0 )
{
delete inst;
return r;
}
// Insert the instance
py_df_list.add(dtid, r, inst);
return r;
}
//------------------------------------------------------------------------
/*
#<pydoc>
def unregister_custom_data_format(dtid, dfid):
"""
Unregisters a custom data format
@param dtid: data type id
@param dfid: data format id
@return: Boolean
"""
pass
#</pydoc>
*/
static bool py_unregister_custom_data_format(int dtid, int dfid)
{
py_custom_data_format_list_t::POS pos;
py_custom_data_format_t *inst = py_df_list.find(dtid, dfid, &pos);
// Maybe the user is trying to unregister a C api data format?
if ( inst == NULL )
return unregister_custom_data_format(dtid, dfid);
bool ok = inst->unregister_df(dtid);
// Perhaps it was automatically unregistered because the type was unregistered?
if ( !ok )
{
// Is this format still registered with IDA?
// If not, mark the context for deletion
ok = find_custom_data_format(inst->get_name()) < 0;
}
if ( ok )
{
py_df_list.erase(pos);
delete inst;
}
return ok;
}
//------------------------------------------------------------------------
/*
#<pydoc>
def get_custom_data_format(dtid, dfid):
"""
Returns a dictionary populated with the data format values or None on failure.
@param dtid: data type id
@param dfid: data format id
"""
pass
#</pydoc>
*/
// Get definition of a registered custom data format and returns a dictionary
static PyObject *py_get_custom_data_format(int dtid, int fid)
{
const data_format_t *df = get_custom_data_format(dtid, fid);
if ( df == NULL )
Py_RETURN_NONE;
return py_data_format_to_py_dict(df);
}
//------------------------------------------------------------------------
/*
#<pydoc>
def get_custom_data_type(dtid):
"""
Returns a dictionary populated with the data type values or None on failure.
@param dtid: data type id
"""
pass
#</pydoc>
*/
// Get definition of a registered custom data format and returns a dictionary
static PyObject *py_get_custom_data_type(int dtid)
{
const data_type_t *dt = get_custom_data_type(dtid);
if ( dt == NULL )
Py_RETURN_NONE;
return py_data_type_to_py_dict(dt);
}
//</inline(py_bytes)>
%}
%pythoncode %{
#<pycode(py_bytes)>
DTP_NODUP = 0x0001
class data_type_t(object):
"""
Custom data type definition. All data types should inherit from this class.
"""
def __init__(self, name, value_size = 0, menu_name = None, hotkey = None, asm_keyword = None, props = 0):
"""Please refer to bytes.hpp / data_type_t in the SDK"""
self.name = name
self.props = props
self.menu_name = menu_name
self.hotkey = hotkey
self.asm_keyword = asm_keyword
self.value_size = value_size
self.id = -1 # Will be initialized after registration
"""Contains the data type id after the data type is registered"""
def register(self):
"""Registers the data type and returns the type id or < 0 on failure"""
return _idaapi.register_custom_data_type(self)
def unregister(self):
"""Unregisters the data type and returns True on success"""
# Not registered?
if self.id < 0:
return True
# Try to unregister
r = _idaapi.unregister_custom_data_type(self.id)
# Clear the ID
if r:
self.id = -1
return r
#<pydoc>
# def may_create_at(self, ea, nbytes):
# """
# (optional) If this callback is not defined then this means always may create data type at the given ea.
# @param ea: address of the future item
# @param nbytes: size of the future item
# @return: Boolean
# """
#
# return False
#
# def calc_item_size(self, ea, maxsize):
# """
# (optional) If this callback is defined it means variable size datatype
# This function is used to determine size of the (possible) item at 'ea'
# @param ea: address of the item
# @param maxsize: maximal size of the item
# @return: integer
# Returns: 0-no such item can be created/displayed
# this callback is required only for varsize datatypes
# """
# return 0
#</pydoc>
# -----------------------------------------------------------------------
# Uncomment the corresponding callbacks in the inherited class
class data_format_t(object):
"""Information about a data format"""
def __init__(self, name, value_size = 0, menu_name = None, props = 0, hotkey = None, text_width = 0):
"""Custom data format definition.
@param name: Format name, must be unique
@param menu_name: Visible format name to use in menus
@param props: properties (currently 0)
@param hotkey: Hotkey for the corresponding menu item
@param value_size: size of the value in bytes. 0 means any size is ok
@text_width: Usual width of the text representation
"""
self.name = name
self.menu_name = menu_name
self.props = props
self.hotkey = hotkey
self.value_size = value_size
self.text_width = text_width
self.id = -1 # Will be initialized after registration
"""contains the format id after the format gets registered"""
def register(self, dtid):
"""Registers the data format with the given data type id and returns the type id or < 0 on failure"""
return _idaapi.register_custom_data_format(dtid, self)
def unregister(self, dtid):
"""Unregisters the data format with the given data type id"""
# Not registered?
if self.id < 0:
return True
# Unregister
r = _idaapi.unregister_custom_data_format(dtid, self.id)
# Clear the ID
if r:
self.id = -1
return r
#<pydoc>
# def printf(self, value, current_ea, operand_num, dtid):
# """
# Convert a value buffer to colored string.
#
# @param value: The value to be printed
# @param current_ea: The ea of the value
# @param operand_num: The affected operand
# @param dtid: custom data type id (0-standard built-in data type)
# @return: a colored string representing the passed 'value' or None on failure
# """
# return None
#
# def scan(self, input, current_ea, operand_num):
# """
# Convert from uncolored string 'input' to byte value
#
# @param input: input string
# @param current_ea: current address (BADADDR if unknown)
# @param operand_num: current operand number (-1 if unknown)
#
# @return: tuple (Boolean, string)
# - (False, ErrorMessage) if conversion fails
# - (True, Value buffer) if conversion succeeds
# """
# return (False, "Not implemented")
#
# def analyze(self, current_ea, operand_num):
# """
# (optional) Analyze custom data format occurrence.
# It can be used to create xrefs from the current item.
#
# @param current_ea: current address (BADADDR if unknown)
# @param operand_num: current operand number
# @return: None
# """
#
# pass
#</pydoc>
# -----------------------------------------------------------------------
def __walk_types_and_formats(formats, type_action, format_action):
broken = False
for f in formats:
if len(f) == 1:
if not format_action(f[0], 0):
broken = True
break
else:
dt = f[0]
dfs = f[1:]
if not type_action(dt):
broken = True
break
for df in dfs:
if not format_action(df, dt.id):
broken = True
break
return not broken
# -----------------------------------------------------------------------
def register_data_types_and_formats(formats):
"""
Registers multiple data types and formats at once.
To register one type/format at a time use register_custom_data_type/register_custom_data_format
It employs a special table of types and formats described below:
The 'formats' is a list of tuples. If a tuple has one element then it is the format to be registered with dtid=0
If the tuple has more than one element, then tuple[0] is the data type and tuple[1:] are the data formats. For example:
many_formats = [
(pascal_data_type(), pascal_data_format()),
(simplevm_data_type(), simplevm_data_format()),
(makedword_data_format(),),
(simplevm_data_format(),)
]
The first two tuples describe data types and their associated formats.
The last two tuples describe two data formats to be used with built-in data types.
"""
def __reg_format(df, dtid):
df.register(dtid)
if dtid == 0:
print "Registering format '%s' with built-in types, ID=%d" % (df.name, df.id)
else:
print " Registering format '%s', ID=%d (dtid=%d)" % (df.name, df.id, dtid)
return df.id != -1
def __reg_type(dt):
dt.register()
print "Registering type '%s', ID=%d" % (dt.name, dt.id)
return dt.id != -1
ok = __walk_types_and_formats(formats, __reg_type, __reg_format)
return 1 if ok else -1
# -----------------------------------------------------------------------
def unregister_data_types_and_formats(formats):
"""As opposed to register_data_types_and_formats(), this function
unregisters multiple data types and formats at once.
"""
def __unreg_format(df, dtid):
df.unregister(dtid)
print "%snregistering format '%s'" % ("U" if dtid == 0 else " u", df.name)
return True
def __unreg_type(dt):
print "Unregistering type '%s', ID=%d" % (dt.name, dt.id)
dt.unregister()
return True
ok = __walk_types_and_formats(formats, __unreg_type, __unreg_format)
return 1 if ok else -1
#</pycode(py_bytes)>
%}

View File

@ -7,6 +7,9 @@ typedef struct
%ignore dbg;
%ignore get_manual_regions;
%ignore source_file_t;
%ignore source_item_t;
%ignore srcinfo_provider_t;
%rename (get_manual_regions) py_get_manual_regions;
%ignore set_manual_regions;
%include "dbg.hpp"
@ -22,7 +25,18 @@ static PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas);
%inline %{
//<inline(py_dbg)>
//-------------------------------------------------------------------------
/*
#<pydoc>
def get_manual_regions():
"""
Returns the manual memory regions
@return: list(startEA, endEA, name, sclass, sbase, bitness, perm)
"""
pass
#</pydoc>
*/
static PyObject *py_get_manual_regions()
{
meminfo_vec_t areas;
@ -31,12 +45,24 @@ static PyObject *py_get_manual_regions()
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def refresh_debugger_memory():
"""
Refreshes the debugger memory
@return: Nothing
"""
pass
#</pydoc>
*/
static PyObject *refresh_debugger_memory()
{
invalidate_dbgmem_config();
invalidate_dbgmem_contents(BADADDR, BADADDR);
invalidate_dbgmem_contents(BADADDR, 0);
if ( dbg != NULL && dbg->stopped_at_debug_event != NULL )
dbg->stopped_at_debug_event(true);
isEnabled(0);
Py_RETURN_NONE;
}
//</inline(py_dbg)>
@ -226,8 +252,8 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
case dbg_request_error:
{
int failed_command = (int)va_arg(va, ui_notification_t);
int failed_dbg_notification = (int)va_arg(va, dbg_notification_t);
int failed_command = (int)va_argi(va, ui_notification_t);
int failed_dbg_notification = (int)va_argi(va, dbg_notification_t);
proxy->dbg_request_error(failed_command, failed_dbg_notification);
return 0;
}

View File

@ -60,6 +60,96 @@ int idaapi py_enumerate_files_cb(const char *file, void *ud)
%inline %{
//<inline(py_diskio)>
/*
#<pydoc>
class loader_input_t(pyidc_opaque_object_t):
"""A helper class to work with linput_t related functions.
This class is also used by file loaders scripts.
"""
def __init__(self):
pass
def close(self):
"""Closes the file"""
pass
def open(self, filename, remote = False):
"""Opens a file (or a remote file)
@return: Boolean
"""
pass
def set_linput(self, linput):
"""Links the current loader_input_t instance to a linput_t instance"""
pass
@staticmethod
def from_fp(fp):
"""A static method to construct an instance from a FILE*"""
pass
def open_memory(self, start, size):
"""Create a linput for process memory (By internally calling idaapi.create_memory_linput())
This linput will use dbg->read_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
"""
pass
def seek(self, pos, whence = SEEK_SET):
"""Set input source position
@return: the new position (not 0 as fseek!)
"""
pass
def tell(self):
"""Returns the current position"""
pass
def getz(self, sz, fpos = -1):
"""Returns a zero terminated string at the given position
@param sz: maximum size of the string
@param fpos: if != -1 then seek will be performed before reading
@return: The string or None on failure.
"""
pass
def gets(self, len):
"""Reads a line from the input file. Returns the read line or None"""
pass
def read(self, size):
"""Reads from the file. Returns the buffer or None"""
pass
def readbytes(self, size, big_endian):
"""Similar to read() but it respect the endianness"""
pass
def file2base(self, pos, ea1, ea2, patchable):
"""
Load portion of file into the database
This function will include (ea1..ea2) into the addressing space of the
program (make it enabled)
@param li: pointer ot input source
@param pos: position in the file
@param (ea1..ea2): range of destination linear addresses
@param patchable: should the kernel remember correspondance of
file offsets to linear addresses.
@return: 1-ok,0-read error, a warning is displayed
"""
pass
def get_char(self):
"""Reads a single character from the file. Returns None if EOF or the read character"""
pass
def opened(self):
"""Checks if the file is opened or not"""
pass
#</pydoc>
*/
class loader_input_t
{
private:
@ -126,17 +216,17 @@ public:
}
//--------------------------------------------------------------------------
PyObject *open(const char *filename, bool remote = false)
bool open(const char *filename, bool remote = false)
{
close();
li = open_linput(filename, remote);
if ( li == NULL )
Py_RETURN_FALSE;
return false;
// Save file name
fn = filename;
own = OWN_CREATE;
Py_RETURN_TRUE;
return true;
}
//--------------------------------------------------------------------------
@ -188,16 +278,16 @@ public:
}
//--------------------------------------------------------------------------
PyObject *open_memory(ea_t start, asize_t size = 0)
bool open_memory(ea_t start, asize_t size = 0)
{
linput_t *l = create_memory_linput(start, size);
if ( l == NULL )
Py_RETURN_FALSE;
return false;
close();
li = l;
fn = "<memory>";
own = OWN_CREATE;
Py_RETURN_TRUE;
return true;
}
//--------------------------------------------------------------------------
@ -326,6 +416,23 @@ public:
//--------------------------------------------------------------------------
/*
#<pydoc>
def enumerate_files(path, fname, callback):
"""
Enumerate files in the specified directory while the callback returns 0.
@param path: directory to enumerate files in
@param fname: mask of file names to enumerate
@param callback: a callable object that takes the filename as
its first argument and it returns 0 to continue
enumeration or non-zero to stop enumeration.
@return:
None in case of script errors
tuple(code, fname) : If the callback returns non-zero
"""
pass
#</pydoc>
*/
PyObject *py_enumerate_files(PyObject *path, PyObject *fname, PyObject *callback)
{
do
@ -349,6 +456,7 @@ PyObject *py_enumerate_files(PyObject *path, PyObject *fname, PyObject *callback
%pythoncode %{
#<pycode(py_diskio)>
def enumerate_system_files(subdir, fname, callback):
"""Similar to enumerate_files() however it searches inside IDA directory or its subdirectories"""
return enumerate_files(idadir(subdir), fname, callback)
#</pycode(py_diskio)>
%}

View File

@ -5,7 +5,7 @@
%ignore term_enums;
%ignore set_enum_flag;
%ignore sync_from_enum;;
%ignore del_all_consts;
%ignore del_all_enum_members;
%ignore get_selected_enum;
%ignore add_selected_enum;
%ignore unmark_selected_enums;

View File

@ -7,8 +7,20 @@
%ignore register_extlang;
%ignore IDCFuncs;
%ignore set_idc_func;
%ignore set_idc_func_ex;
%ignore VarLong;
%ignore VarNum;
%ignore extlang_get_attr_exists;
%ignore extlang_create_object_exists;
%ignore create_script_object;
%ignore set_script_attr;
%ignore set_attr_exists;
%ignore get_script_attr;
%ignore extlang_get_attr_exists;
%ignore extlang_compile_file;
%ignore get_extlangs;
%ignore create_idc_object;
%ignore run_script_func;
%ignore VarString;
%ignore VarFloat;
%ignore VarFree;

View File

@ -1,5 +1,79 @@
%inline %{
//<inline(py_qfile)>
/*
#<pydoc>
class qfile_t(pyidc_opaque_object_t):
"""A helper class to work with FILE related functions."""
def __init__(self):
pass
def close(self):
"""Closes the file"""
pass
def open(self, filename, mode):
"""Opens a file
@param filename: the file name
@param mode: The mode string, ala fopen() style
@return: Boolean
"""
pass
def set_linput(self, linput):
"""Links the current loader_input_t instance to a linput_t instance"""
pass
@staticmethod
def tmpfile():
"""A static method to construct an instance using a temporary file"""
pass
def seek(self, pos, whence = SEEK_SET):
"""Set input source position
@return: the new position (not 0 as fseek!)
"""
pass
def tell(self):
"""Returns the current position"""
pass
def gets(self, len):
"""Reads a line from the input file. Returns the read line or None"""
pass
def read(self, size):
"""Reads from the file. Returns the buffer or None"""
pass
def write(self, buf):
"""Writes to the file. Returns 0 or the number of bytes written"""
pass
def readbytes(self, size, big_endian):
"""Similar to read() but it respect the endianness"""
pass
def writebytes(self, size, big_endian):
"""Similar to write() but it respect the endianness"""
pass
def flush(self):
pass
def get_char(self):
"""Reads a single character from the file. Returns None if EOF or the read character"""
pass
def put_char(self):
"""Writes a single character to the file"""
pass
def opened(self):
"""Checks if the file is opened or not"""
pass
#</pydoc>
*/
class qfile_t
{
private:
@ -71,16 +145,16 @@ public:
}
//--------------------------------------------------------------------------
PyObject *open(const char *filename, const char *mode)
bool open(const char *filename, const char *mode)
{
close();
fp = qfopen(filename, mode);
if ( fp == NULL )
Py_RETURN_FALSE;
return false;
// Save file name
fn = filename;
own = true;
Py_RETURN_TRUE;
return true;
}
//--------------------------------------------------------------------------

View File

@ -16,5 +16,15 @@
%ignore read_stkpnts;
%ignore write_stkpnts;
%ignore del_stkpnts;
%ignore rename_frame;
%ignore get_stkvar;
%rename (get_stkvar) py_get_stkvar;
%ignore add_stkvar3;
%rename (add_stkvar3) py_add_stkvar3;
%ignore calc_frame_offset;
%ignore add_stkvar;
%include "frame.hpp"

View File

@ -34,6 +34,12 @@
%clear(char *optlibs);
%inline %{
/*
#<pydoc>
def get_fchunk_referer(ea, idx):
pass
#</pydoc>
*/
ea_t get_fchunk_referer(ea_t ea, size_t idx)
{
func_t *pfn = get_fchunk(ea);

View File

@ -3,6 +3,8 @@
%ignore gdl_graph_t::gen_gdl;
%ignore gdl_graph_t::path;
%ignore gdl_graph_t::path_exists;
%ignore gdl_graph_t::gen_dot;
%ignore intmap_t::dstr;
%ignore intmap_t::print;
%ignore intseq_t::add_block;
@ -20,6 +22,7 @@
%ignore node_set_t::sub;
%ignore qflow_chart_t::blocks;
%ignore flow_chart_t;
%ignore default_graph_format;
%ignore setup_graph_subsystem;
%ignore qbasic_block_t::succ;
%ignore qbasic_block_t::pred;
@ -38,6 +41,7 @@
#<pycode(py_gdl)>
# -----------------------------------------------------------------------
class BasicBlock:
"""Basic block class. It is returned by the Flowchart class"""
def __init__(self, id, bb, f):
self._f = f
self.id = id
@ -68,7 +72,8 @@ class BasicBlock:
# -----------------------------------------------------------------------
class FlowChart:
"""
Flowchart class used to determine basic blocks
Flowchart class used to determine basic blocks.
Check ex_gdl_qflow_chart.py for sample usage.
"""
def __init__(self, f=None, bounds=None, flags=0):
"""

View File

@ -1,3 +1,4 @@
#ifdef __NT__
%{
//<code(py_graph)>
class py_graph_t
@ -28,7 +29,7 @@ private:
nodetext_cache_t *get(int node_id)
{
iterator it = find(node_id);
if (it == end())
if ( it == end() )
return NULL;
return &it->second;
}
@ -56,22 +57,26 @@ private:
private:
Py_ssize_t uid;
public:
cmdid_map_t()
{
uid = 1; // we start by one and keep zero for error id
}
void add(py_graph_t *pyg)
{
(*this)[uid] = pyg;
++uid;
}
const Py_ssize_t id() const { return uid; }
void clear(py_graph_t *pyg)
{
iterator e = end();
for (iterator it=begin();it!=end();)
{
if (it->second == pyg)
if ( it->second == pyg )
{
iterator temp = it++;
erase(temp);
@ -106,7 +111,7 @@ private:
{
Py_ssize_t id = (Py_ssize_t)ud;
py_graph_t *_this = cmdid_pyg.get(id);
if (_this != NULL)
if ( _this != NULL )
_this->on_command(id);
return true;
}
@ -123,7 +128,7 @@ private:
// the nodes and edges. The nodes and edges are retrieved and passed to IDA
void on_user_refresh(mutable_graph_t *g)
{
if (!refresh_needed)
if ( !refresh_needed )
return;
// Check return value to OnRefresh() call
@ -136,7 +141,7 @@ private:
// Refer to the nodes
PyObject *nodes = PyObject_TryGetAttrString(self, S_M_NODES);
if (ret == NULL || !PyList_Check(nodes))
if ( ret == NULL || !PyList_Check(nodes) )
{
Py_XDECREF(nodes);
return;
@ -144,7 +149,7 @@ private:
// Refer to the edges
PyObject *edges = PyObject_TryGetAttrString(self, S_M_EDGES);
if (ret == NULL || !PyList_Check(nodes))
if ( ret == NULL || !PyList_Check(nodes) )
{
Py_DECREF(nodes);
Py_XDECREF(edges);
@ -163,32 +168,32 @@ private:
node_cache.clear();
// Get the edges
for (int i=(int)PyList_Size(edges)-1;i>=0;i--)
for ( int i=(int)PyList_Size(edges)-1; i>=0; i-- )
{
// Each list item is a sequence (id1, id2)
PyObject *item = PyList_GetItem(edges, i);
if (!PySequence_Check(item))
if ( !PySequence_Check(item) )
continue;
// Get and validate each of the two elements in the sequence
int edge_ids[2];
int j;
for (j=0;j<qnumber(edge_ids);j++)
for ( j=0; j<qnumber(edge_ids); j++ )
{
PyObject *id = PySequence_GetItem(item, j);
if (id == NULL || !PyInt_Check(id))
if ( id == NULL || !PyInt_Check(id) )
{
Py_XDECREF(id);
break;
}
int v = int(PyInt_AS_LONG(id));
Py_DECREF(id);
if (v > max_nodes)
if ( v > max_nodes )
break;
edge_ids[j] = v;
}
// Incomplete?
if (j != qnumber(edge_ids))
if ( j != qnumber(edge_ids) )
break;
// Add the edge
g->add_edge(edge_ids[0], edge_ids[1], NULL);
@ -203,39 +208,39 @@ private:
{
// If already cached then return the value
nodetext_cache_t *c = node_cache.get(node);
if (c != NULL)
if ( c != NULL )
{
*str = c->text.c_str();
if (bg_color != NULL)
if ( bg_color != NULL )
*bg_color = c->bgcolor;
return true;
}
// Not cached, call Python
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_GETTEXT, "i", node);
if (result == NULL)
if ( result == NULL )
return false;
bgcolor_t cl = bg_color == NULL ? DEFCOLOR : *bg_color;
const char *s;
// User returned a string?
if (PyString_Check(result))
if ( PyString_Check(result) )
{
s = PyString_AsString(result);
if (s == NULL)
if ( s == NULL )
s = "";
c = node_cache.add(node, s, cl);
}
// User returned a sequence of text and bgcolor
else if (PySequence_Check(result) && PySequence_Size(result) == 2)
else if ( PySequence_Check(result) && PySequence_Size(result) == 2 )
{
PyObject *py_str = PySequence_GetItem(result, 0);
PyObject *py_color = PySequence_GetItem(result, 1);
if (py_str == NULL || !PyString_Check(py_str) || (s = PyString_AsString(py_str)) == NULL)
if ( py_str == NULL || !PyString_Check(py_str) || (s = PyString_AsString(py_str)) == NULL )
s = "";
if (py_color != NULL && PyNumber_Check(py_color))
if ( py_color != NULL && PyNumber_Check(py_color) )
cl = bgcolor_t(PyLong_AsUnsignedLong(py_color));
c = node_cache.add(node, s, cl);
@ -246,7 +251,7 @@ private:
Py_DECREF(result);
*str = c->text.c_str();
if (bg_color != NULL)
if ( bg_color != NULL )
*bg_color = c->bgcolor;
return true;
}
@ -259,12 +264,12 @@ private:
// out: 0-use default hint, 1-use proposed hint
// We dispatch hints over nodes only
if (mousenode == -1)
if ( mousenode == -1 )
return 0;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_HINT, "i", mousenode);
bool ok = result != NULL && PyString_Check(result);
if (!ok)
if ( !ok )
{
Py_XDECREF(result);
return 0;
@ -277,9 +282,9 @@ private:
// graph is being destroyed
void on_destroy(mutable_graph_t * /*g*/ = NULL)
{
if (self != NULL)
if ( self != NULL )
{
if (cb_flags & GR_HAVE_CLOSE)
if ( cb_flags & GR_HAVE_CLOSE )
{
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL);
Py_XDECREF(result);
@ -287,7 +292,7 @@ private:
unbind();
}
// Remove the TForm from list
if (form != NULL)
if ( form != NULL )
tform_pyg.erase(form);
// remove all associated commands from the list
cmdid_pyg.clear(this);
@ -307,7 +312,7 @@ private:
// current_item1, current_item2 point to the same thing
// item2 has more information.
// see also: kernwin.hpp, custom_viewer_click_t
if (item2->n == -1)
if ( item2->n == -1 )
return 1;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLICK, "i", item2->n);
@ -321,6 +326,7 @@ private:
return 0;
}
// a graph node has been double clicked
int on_dblclicked(graph_viewer_t * /*gv*/, selection_item_t *item)
{
@ -329,7 +335,7 @@ private:
// out: 0-ok, 1-ignore click
//graph_viewer_t *v = va_arg(va, graph_viewer_t *);
//selection_item_t *s = va_arg(va, selection_item_t *);
if (item == NULL || !item->is_node)
if ( item == NULL || !item->is_node )
return 1;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_DBL_CLICK, "i", item->node);
if ( result == NULL || !PyObject_IsTrue(result) )
@ -361,7 +367,7 @@ private:
// in: graph_viewer_t *gv
// int curnode
// out: 0-ok, 1-forbid to change the current node
if (curnode < 0)
if ( curnode < 0 )
return 0;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_SELECT, "i", curnode);
bool allow = (result != NULL && PyObject_IsTrue(result));
@ -372,7 +378,7 @@ private:
int gr_callback(int code, va_list va)
{
int ret;
switch (code)
switch ( code )
{
//
case grcode_user_text:
@ -391,7 +397,7 @@ private:
break;
//
case grcode_clicked:
if (cb_flags & GR_HAVE_CLICKED)
if ( cb_flags & GR_HAVE_CLICKED )
{
graph_viewer_t *gv = va_arg(va, graph_viewer_t *);
selection_item_t *item = va_arg(va, selection_item_t *);
@ -403,7 +409,7 @@ private:
break;
//
case grcode_dblclicked:
if (cb_flags & GR_HAVE_DBL_CLICKED)
if ( cb_flags & GR_HAVE_DBL_CLICKED )
{
graph_viewer_t *gv = va_arg(va, graph_viewer_t *);
selection_item_t *item = va_arg(va, selection_item_t *);
@ -414,13 +420,13 @@ private:
break;
//
case grcode_gotfocus:
if (cb_flags & GR_HAVE_GOTFOCUS)
if ( cb_flags & GR_HAVE_GOTFOCUS )
on_gotfocus(va_arg(va, graph_viewer_t *));
ret = 0;
break;
//
case grcode_lostfocus:
if (cb_flags & GR_HAVE_LOSTFOCUS)
if ( cb_flags & GR_HAVE_LOSTFOCUS )
on_lostfocus(va_arg(va, graph_viewer_t *));
ret = 0;
break;
@ -431,7 +437,7 @@ private:
break;
//
case grcode_user_hint:
if (cb_flags & GR_HAVE_USER_HINT)
if ( cb_flags & GR_HAVE_USER_HINT )
{
mutable_graph_t *g = va_arg(va, mutable_graph_t *);
int mousenode = va_arg(va, int);
@ -447,7 +453,7 @@ private:
break;
//
case grcode_changed_current:
if (cb_flags & GR_HAVE_CHANGED_CURRENT)
if ( cb_flags & GR_HAVE_CHANGED_CURRENT )
{
graph_viewer_t *gv = va_arg(va, graph_viewer_t *);
int cur_node = va_arg(va, int);
@ -473,7 +479,7 @@ private:
void unbind()
{
if (self == NULL)
if ( self == NULL )
return;
// Unbind this object from the python object
@ -493,7 +499,7 @@ private:
{
// Try to extract "this" from the python object
PyObject *py_this = PyObject_TryGetAttrString(self, S_M_THIS);
if (py_this == NULL || !PyCObject_Check(py_this))
if ( py_this == NULL || !PyCObject_Check(py_this) )
{
Py_XDECREF(py_this);
return NULL;
@ -558,19 +564,19 @@ private:
{S_ON_DEACTIVATE, GR_HAVE_LOSTFOCUS}
};
cb_flags = 0;
for (int i=0;i<qnumber(callbacks);i++)
for ( int i=0; i<qnumber(callbacks); i++ )
{
PyObject *attr = PyObject_TryGetAttrString(self, callbacks[i].name);
int have = callbacks[i].have;
// Mandatory fields not present?
if ((attr == NULL && have <= 0)
if ( (attr == NULL && have <= 0 )
// Mandatory callback fields present but not callable?
|| (attr != NULL && have >= 0 && PyCallable_Check(attr) == 0))
{
Py_XDECREF(attr);
return -1;
}
if (have > 0 && attr != NULL)
if ( have > 0 && attr != NULL )
cb_flags |= have;
Py_XDECREF(attr);
}
@ -592,14 +598,14 @@ private:
// Link "form" and "py_graph"
tform_pyg.add(form, this);
if (hwnd != NULL)
if ( hwnd != NULL )
{
// get a unique graph id
netnode id;
id.create();
gv = create_graph_viewer(form, id, s_callback, this, 0);
open_tform(form, FORM_MDI|FORM_TAB|FORM_MENU);
if (gv != NULL)
if ( gv != NULL )
viewer_fit_window(gv);
}
else
@ -616,7 +622,7 @@ private:
return 0;
Py_ssize_t cmd_id = cmdid_pyg.id();
bool ok = viewer_add_menu_item(gv, title, s_menucb, (void *)cmd_id, hotkey, 0);
if (!ok)
if ( !ok )
return 0;
cmdid_pyg.add(this);
return cmd_id;
@ -634,7 +640,7 @@ private:
static void SelectNode(PyObject *self, int nid)
{
py_graph_t *_this = extract_this(self);
if (_this == NULL || _this->form == NULL)
if ( _this == NULL || _this->form == NULL )
return;
_this->jump_to_node(0);
}
@ -642,7 +648,7 @@ private:
static Py_ssize_t AddCommand(PyObject *self, const char *title, const char *hotkey)
{
py_graph_t *_this = extract_this(self);
if (_this == NULL || _this->form == NULL)
if ( _this == NULL || _this->form == NULL )
return 0;
return _this->add_command(title, hotkey);
}
@ -650,7 +656,7 @@ private:
static void Close(PyObject *self)
{
py_graph_t *_this = extract_this(self);
if (_this == NULL || _this->form == NULL)
if ( _this == NULL || _this->form == NULL )
return;
close_tform(_this->form, 0);
}
@ -658,7 +664,7 @@ private:
static void Refresh(PyObject *self)
{
py_graph_t *_this = extract_this(self);
if (_this == NULL)
if ( _this == NULL )
return;
_this->refresh();
}
@ -666,10 +672,10 @@ private:
static py_graph_t *Show(PyObject *self)
{
py_graph_t *ret = extract_this(self);
if (ret == NULL)
if ( ret == NULL )
{
qstring title;
if (!extract_title(self, &title))
if ( !extract_title(self, &title) )
return NULL;
// Form already created? try to get associated py_graph instance
@ -677,7 +683,7 @@ private:
ret = tform_pyg.get(find_tform(title.c_str()));
// Instance not found? create a new one
if (ret == NULL)
if ( ret == NULL )
ret = new py_graph_t();
else
{
@ -685,7 +691,7 @@ private:
ret->unbind();
ret->refresh_needed = true;
}
if (ret->create(self, title.c_str()) < 0)
if ( ret->create(self, title.c_str()) < 0 )
{
delete ret;
ret = NULL;
@ -728,7 +734,22 @@ void pyg_select_node(PyObject *self, int nid)
}
//</code(py_graph)>
%}
#endif
#ifdef __NT__
%inline %{
//<inline(py_graph)>
void pyg_refresh(PyObject *self);
void pyg_close(PyObject *self);
PyObject *pyg_add_command(PyObject *self, const char *title, const char *hotkey);
void pyg_select_node(PyObject *self, int nid);
bool pyg_show(PyObject *self);
//</inline(py_graph)>
%}
#endif
#ifdef __NT__
%pythoncode %{
#<pycode(py_graph)>
class GraphViewer:
@ -814,13 +835,26 @@ class GraphViewer:
Event called when the graph is refreshed or first created.
From this event you are supposed to create nodes and edges.
This callback is mandatory.
@note: ***It is important to clear previous nodes before adding nodes.***
@return: Returning true tells the graph viewer to use the items. Otherwise old items will be used.
@return: Returning True tells the graph viewer to use the items. Otherwise old items will be used.
"""
self.Clear()
return True
#<pydoc>
# def OnGetText(self, node_id):
# """
# Triggered when the graph viewer wants the text and color for a given node.
# This callback is triggered one time for a given node (the value will be cached and used later without calling Python).
# When you call refresh then again this callback will be called for each node.
#
# This callback is mandatory.
#
# @return: Return a string to describe the node text or return a tuple (node_text, node_color) to describe both text and color
# """
# return str(self[node_id])
#
# def OnActivate(self):
# """
# Triggered when the graph window gets the focus
@ -841,17 +875,7 @@ class GraphViewer:
# """
# # allow selection change
# return True
# def OnGetText(self, node_id):
# """
# Triggered when the graph viewer wants the text and color for a given node.
# This callback is triggered one time for a given node (the value will be cached and used later without calling Python).
# When you call refresh then again this callback will be called for each node.
#
# @return: Return a string to describe the node text or return a tuple (node_text, node_color) to describe both text and color
# """
# return str(self[node_id])
# def OnHint(self, node_id):
# """
# Triggered when the graph viewer wants to retrieve hint text associated with a given node
@ -869,7 +893,7 @@ class GraphViewer:
# def OnClick(self, node_id):
# """
# Triggered when a node is clicked
# @return: False to ignore the click and true otherwise
# @return: False to ignore the click and True otherwise
# """
# print "clicked on", self[node_id]
# return True
@ -888,16 +912,7 @@ class GraphViewer:
# @return: None
# """
# print "command:", cmd_id
#</pydoc>
#</pycode(py_graph)>
%}
%inline %{
//<inline(py_graph)>
void pyg_refresh(PyObject *self);
void pyg_close(PyObject *self);
PyObject *pyg_add_command(PyObject *self, const char *title, const char *hotkey);
void pyg_select_node(PyObject *self, int nid);
bool pyg_show(PyObject *self);
//</inline(py_graph)>
%}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
%ignore memory_info_t;
%ignore register_info_t;
%ignore appcall;
%ignore gdecode_t;
%apply unsigned char { char dtyp };
%include "idd.hpp"
@ -16,7 +17,7 @@ static bool dbg_can_query()
{
// Reject the request only if no debugger is set
// or the debugger cannot be queried while not in suspended state
return !(dbg == NULL || (!dbg->may_disturb() && get_process_state() > DSTATE_SUSP));
return dbg != NULL && (dbg->may_disturb() || get_process_state() < DSTATE_NOTASK);
}
//-------------------------------------------------------------------------
@ -42,116 +43,6 @@ static PyObject *meminfo_vec_t_to_py(meminfo_vec_t &areas)
return py_list;
}
//-------------------------------------------------------------------------
PyObject *dbg_get_memory_info()
{
if (!dbg_can_query())
Py_RETURN_NONE;
// Invalidate memory
invalidate_dbgmem_config();
invalidate_dbgmem_contents(BADADDR, BADADDR);
meminfo_vec_t areas;
dbg->get_memory_info(areas);
return meminfo_vec_t_to_py(areas);
}
//-------------------------------------------------------------------------
PyObject *dbg_get_registers()
{
if (dbg == NULL)
Py_RETURN_NONE;
PyObject *py_list = PyList_New(dbg->registers_size);
for (int i=0;i<dbg->registers_size;i++)
{
register_info_t &ri = dbg->registers[i];
PyObject *py_bits;
// Does this register have bit strings?
if (ri.bit_strings != NULL)
{
int nbits = (int)b2a_width((int)get_dtyp_size(ri.dtyp), 0) * 4;
py_bits = PyList_New(nbits);
for (int i=0;i<nbits;i++)
{
const char *s = ri.bit_strings[i];
PyList_SetItem(py_bits, i, PyString_FromString(s == NULL ? "" : s));
}
}
else
{
Py_INCREF(Py_None);
py_bits = Py_None;
}
// name flags class dtyp bit_strings bit_strings_default_mask
PyList_SetItem(py_list, i,
Py_BuildValue("(sIIINI)",
ri.name,
ri.flags,
(unsigned int)ri.register_class,
(unsigned int)ri.dtyp,
py_bits,
(unsigned int)ri.bit_strings_default));
}
return py_list;
}
//-------------------------------------------------------------------------
PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value)
{
if (!dbg_can_query() || !PyInt_Check(py_tid) || !PyInt_Check(py_sreg_value))
Py_RETURN_NONE;
ea_t answer;
thid_t tid = PyInt_AsLong(py_tid);
int sreg_value = PyInt_AsLong(py_sreg_value);
if (dbg->thread_get_sreg_base(tid, sreg_value, &answer) != 1)
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, pyul_t(answer));
}
//-------------------------------------------------------------------------
PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
{
uint64 ea, sz;
if ( !dbg_can_query() || !PyGetNumber(py_ea, &ea) || !PyGetNumber(py_sz, &sz) )
Py_RETURN_NONE;
char *buf = new char[size_t(sz)];
if ( buf == NULL )
Py_RETURN_NONE;
PyObject *ret;
if ( (size_t)dbg->read_memory(ea_t(ea), buf, size_t(sz)) == sz )
{
ret = PyString_FromStringAndSize(buf, (Py_ssize_t)sz);
}
else
{
Py_INCREF(Py_None);
ret = Py_None;
}
delete [] buf;
return ret;
}
//-------------------------------------------------------------------------
PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
{
uint64 ea;
if ( !dbg_can_query() || !PyString_Check(py_buf) || !PyGetNumber(py_ea, &ea) )
Py_RETURN_NONE;
size_t sz = PyString_GET_SIZE(py_buf);
void *buf = (void *)PyString_AS_STRING(py_buf);
if ( dbg->write_memory(ea_t(ea), buf, sz) != sz )
Py_RETURN_FALSE;
Py_RETURN_TRUE;
}
//-------------------------------------------------------------------------
PyObject *py_appcall(
ea_t func_ea,
@ -202,7 +93,7 @@ PyObject *py_appcall(
msg("input variables:\n"
"----------------\n");
qstring s;
for (Py_ssize_t i=0;i<nargs;i++)
for ( Py_ssize_t i=0; i<nargs; i++ )
{
VarPrint(&s, &idc_args[i]);
msg("%d]\n%s\n-----------\n", int(i), s.c_str());
@ -220,10 +111,10 @@ PyObject *py_appcall(
idc_args.begin(),
&idc_result);
if (ret != eOk)
if ( ret != eOk )
{
// An exception was thrown?
if (ret == eExecThrow)
if ( ret == eExecThrow )
{
// Convert the result (which is a debug_event) into a Python object
PyObject *py_appcall_exc(NULL);
@ -247,7 +138,7 @@ PyObject *py_appcall(
msg("return variables:\n"
"-----------------\n");
qstring s;
for (Py_ssize_t i=0;i<nargs;i++)
for ( Py_ssize_t i=0; i<nargs; i++ )
{
VarPrint(&s, &idc_args[i]);
msg("%d]\n%s\n-----------\n", int(i), s.c_str());
@ -255,13 +146,13 @@ PyObject *py_appcall(
}
}
// Convert IDC values back to Python values
for (Py_ssize_t i=0;i<nargs;i++)
for ( Py_ssize_t i=0; i<nargs; i++ )
{
// Get argument
PyObject *py_item = PyList_GetItem(arg_list, i);
// We convert arguments but fail only on fatal errors
// (we ignore failure because of immutable objects)
if (idcvar_to_pyvar(idc_args[i], &py_item) == CIP_FAILED)
if ( idcvar_to_pyvar(idc_args[i], &py_item) == CIP_FAILED )
{
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed while converting IDC values to Python values");
return NULL;
@ -269,7 +160,7 @@ PyObject *py_appcall(
}
// Convert the result from IDC back to Python
PyObject *py_result(NULL);
if (idcvar_to_pyvar(idc_result, &py_result) <= CIP_IMMUTABLE)
if ( idcvar_to_pyvar(idc_result, &py_result) <= CIP_IMMUTABLE )
{
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed while converting IDC return value to Python return value");
return NULL;
@ -293,11 +184,165 @@ PyObject *py_appcall(
%inline %{
//<inline(py_idd)>
PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf);
PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz);
PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value);
PyObject *dbg_get_registers();
PyObject *dbg_get_memory_info();
//-------------------------------------------------------------------------
/*
#<pydoc>
def dbg_get_registers():
"""
This function returns the register definition from the currently loaded debugger.
Basically, it returns an array of structure similar to to idd.hpp / register_info_t
@return:
None if no debugger is loaded
tuple(name, flags, class, dtyp, bit_strings, bit_strings_default_mask)
The bit_strings can be a tuple of strings or None (if the register does not have bit_strings)
"""
pass
#</pydoc>
*/
static PyObject *dbg_get_registers()
{
if ( dbg == NULL )
Py_RETURN_NONE;
PyObject *py_list = PyList_New(dbg->registers_size);
for ( int i=0; i<dbg->registers_size; i++ )
{
register_info_t &ri = dbg->registers[i];
PyObject *py_bits;
// Does this register have bit strings?
if ( ri.bit_strings != NULL )
{
int nbits = (int)b2a_width((int)get_dtyp_size(ri.dtyp), 0) * 4;
py_bits = PyList_New(nbits);
for ( int i=0; i<nbits; i++ )
{
const char *s = ri.bit_strings[i];
PyList_SetItem(py_bits, i, PyString_FromString(s == NULL ? "" : s));
}
}
else
{
Py_INCREF(Py_None);
py_bits = Py_None;
}
// name, flags, class, dtyp, bit_strings, bit_strings_default_mask
PyList_SetItem(py_list, i,
Py_BuildValue("(sIIINI)",
ri.name,
ri.flags,
(unsigned int)ri.register_class,
(unsigned int)ri.dtyp,
py_bits,
(unsigned int)ri.bit_strings_default));
}
return py_list;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def dbg_get_thread_sreg_base(tid, sreg_value):
"""
Returns the segment register base value
@param tid: thread id
@param sreg_value: segment register (selector) value
@return:
- The base as an 'ea'
- Or None on failure
"""
pass
#</pydoc>
*/
static PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_value)
{
if ( !dbg_can_query() || !PyInt_Check(py_tid) || !PyInt_Check(py_sreg_value) )
Py_RETURN_NONE;
ea_t answer;
thid_t tid = PyInt_AsLong(py_tid);
int sreg_value = PyInt_AsLong(py_sreg_value);
if ( dbg->thread_get_sreg_base(tid, sreg_value, &answer) != 1 )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, pyul_t(answer));
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def dbg_read_memory(ea, sz):
"""
Reads from the debugee's memory at the specified ea
@return:
- The read buffer (as a string)
- Or None on failure
"""
pass
#</pydoc>
*/
static PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
{
uint64 ea, sz;
if ( !dbg_can_query() || !PyGetNumber(py_ea, &ea) || !PyGetNumber(py_sz, &sz) )
Py_RETURN_NONE;
// Create a Python string
PyObject *ret = PyString_FromStringAndSize(NULL, Py_ssize_t(sz));
if ( ret == NULL )
Py_RETURN_NONE;
// Get the internal buffer
Py_ssize_t len;
char *buf;
PyString_AsStringAndSize(ret, &buf, &len);
if ( (size_t)dbg->read_memory(ea_t(ea), buf, size_t(sz)) != sz )
{
// Release the string on failure
Py_DECREF(ret);
// Return None on failure
Py_RETURN_NONE;
}
return ret;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def dbg_write_memory(ea, buffer):
"""
Writes a buffer to the debugee's memory
@return: Boolean
"""
pass
#</pydoc>
*/
static PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
{
uint64 ea;
if ( !dbg_can_query() || !PyString_Check(py_buf) || !PyGetNumber(py_ea, &ea) )
Py_RETURN_NONE;
size_t sz = PyString_GET_SIZE(py_buf);
void *buf = (void *)PyString_AS_STRING(py_buf);
if ( dbg->write_memory(ea_t(ea), buf, sz) != sz )
Py_RETURN_FALSE;
Py_RETURN_TRUE;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def dbg_get_name():
"""
This function returns the current debugger's name.
@return: Debugger name or None if no debugger is active
"""
pass
#</pydoc>
*/
static PyObject *dbg_get_name()
{
if ( dbg == NULL )
@ -305,6 +350,47 @@ static PyObject *dbg_get_name()
return PyString_FromString(dbg->name);
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def dbg_get_memory_info():
"""
This function returns the memory configuration of a debugged process.
@return:
None if no debugger is active
tuple(startEA, endEA, name, sclass, sbase, bitness, perm)
"""
pass
#</pydoc>
*/
static PyObject *dbg_get_memory_info()
{
if ( !dbg_can_query() )
Py_RETURN_NONE;
// Invalidate memory
invalidate_dbgmem_config();
invalidate_dbgmem_contents(BADADDR, BADADDR);
meminfo_vec_t areas;
dbg->get_memory_info(areas);
return meminfo_vec_t_to_py(areas);
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def dbg_can_query():
"""
This function can be used to check if the debugger can be queried:
- debugger is loaded
- process is suspended
- process is not suspended but can take requests
@return: Boolean
"""
pass
#</pydoc>
*/
static bool dbg_can_query();
PyObject *py_appcall(
ea_t func_ea,
@ -368,15 +454,16 @@ bool can_exc_continue(const debug_event_t* ev)
import types
# -----------------------------------------------------------------------
# This class is used with |Appcall.array() method
class Appcall_array__(object):
"""This class is used with Appcall.array() method"""
def __init__(self, tp):
self.__type = tp
def pack(self, L):
"""Packs a list or tuple into a byref buffer"""
t = type(L)
if not (t == types.ListType or t == types.TupleType):
raise ValueError, "Either a list or a type must be passed"
raise ValueError, "Either a list or a tuple must be passed"
self.__size = len(L)
if self.__size == 1:
self.__typedobj = Appcall__.typedobj(self.__type + ";")
@ -390,6 +477,7 @@ class Appcall_array__(object):
return None
def try_to_convert_to_list(self, obj):
"""Is this object a list? We check for the existance of attribute zero and attribute self.size-1"""
if not (hasattr(obj, "0") and hasattr(obj, str(self.__size-1))):
return obj
# at this point, we are sure we have an "idc list"
@ -397,6 +485,7 @@ class Appcall_array__(object):
return [getattr(obj, str(x)) for x in xrange(0, self.__size)]
def unpack(self, buf, as_list=True):
"""Unpacks an array back into a list or an object"""
# take the value from the special ref object
if isinstance(buf, PyIdc_cvt_refclass__):
buf = buf.value
@ -412,15 +501,6 @@ class Appcall_array__(object):
return obj
return self.try_to_convert_to_list(obj)
# -----------------------------------------------------------------------
# This class is used with the obj() method
class Appcall_object__(object):
"""Helper class used to initialize empty objects"""
def __init__(self, **kwds):
self.__dict__ = kwds
def __getitem__(self, idx):
return getattr(self, idx)
# -----------------------------------------------------------------------
# Wrapper class for the appcall()
@ -444,13 +524,29 @@ class Appcall_callable__(object):
self.__type = tp
self.__fields = fld
self.__options = None # Appcall options
self.__timeout = None # Appcall timeout
def __get_timeout(self):
return self.__timeout
def __set_timeout(self, v):
self.__timeout = v
timeout = property(__get_timeout, __set_timeout)
"""An Appcall instance can change its timeout value with this attribute"""
def __get_options(self):
return self.__options if self.__options != None else Appcall__.get_appcall_options()
def __set_options(self, v):
if self.timeout:
# If timeout value is set, then put the timeout flag and encode the timeout value
v |= Appcall__.APPCALL_TIMEOUT | (self.timeout << 16)
else:
# Timeout is not set, then clear the timeout flag
v &= ~Appcall__.APPCALL_TIMEOUT
self.__options = v
"""Sets the Appcall options locally to this Appcall instance"""
options = property(__get_options, __set_options)
"""Sets the Appcall options locally to this Appcall instance"""
def __call__(self, *args):
"""Make object callable. We redirect execution to idaapi.appcall()"""
@ -488,8 +584,9 @@ class Appcall_callable__(object):
return self.__ea
def __set_ea(self, val):
self.__ea = val
"""Returns or sets the EA associated with this object"""
ea = property(__get_ea, __set_ea)
"""Returns or sets the EA associated with this object"""
def __get_size(self):
if self.__type == None:
@ -498,18 +595,20 @@ class Appcall_callable__(object):
if not r:
return -1
return r
"""Returns the size of the type"""
size = property(__get_size)
"""Returns the size of the type"""
def __get_type(self):
return self.__type
"""Returns the typestring"""
type = property(__get_type)
"""Returns the typestring"""
def __get_fields(self):
return self.__fields
"""Returns the typestring"""
fields = property(__get_fields)
"""Returns the field names"""
def retrieve(self, src=None, flags=0):
"""
@ -531,7 +630,8 @@ class Appcall_callable__(object):
"""
Packs an object into a given ea if provided or into a string if no address was passed.
@return: - If packing to a string then a Tuple(Boolean, packed_string or error code)
@return:
- If packing to a string then a Tuple(Boolean, packed_string or error code)
- If packing to the database then a return code is returned (0 is success)
"""
@ -543,6 +643,8 @@ class Appcall_callable__(object):
# -----------------------------------------------------------------------
class Appcall_consts__(object):
"""Helper class used by Appcall.Consts attribute
It is used to retrieve constants via attribute access"""
def __init__(self, default=0):
self.__default = default
@ -551,26 +653,34 @@ class Appcall_consts__(object):
# -----------------------------------------------------------------------
class Appcall__(object):
APPCALL_MANUAL = 0x1
"""
Only set up the appcall, do not run it.
you should call CleanupAppcall() when finished
"""
APPCALL_MANUAL = 0x1
APPCALL_DEBEV = 0x2
"""
Return debug event information
If this bit is set, exceptions during appcall
will generate idc exceptions with full
information about the exception
"""
APPCALL_DEBEV = 0x2
APPCALL_TIMEOUT = 0x4
"""
Appcall with timeout
The timeout value in milliseconds is specified
in the high 2 bytes of the 'options' argument:
If timed out, errbuf will contain "timeout".
"""
def __init__(self):
self.__consts = Appcall_consts__()
def __get_consts(self):
return self.__consts
"""Use Appcall.Consts.CONST_NAME to access constants"""
Consts = property(__get_consts)
"""Use Appcall.Consts.CONST_NAME to access constants"""
@staticmethod
def __name_or_ea(name_or_ea):
@ -591,7 +701,7 @@ class Appcall__(object):
@staticmethod
def proto(name_or_ea, prototype, flags = None):
"""Allows you to instantiate an appcall with the desired prototype"""
"""Allows you to instantiate an appcall (callable object) with the desired prototype"""
# resolve and raise exception on error
ea = Appcall__.__name_or_ea(name_or_ea)
@ -605,7 +715,7 @@ class Appcall__(object):
return Appcall_callable__(ea, result[1], result[2])
def __getattr__(self, name_or_ea):
"""Allows you to call functions as if they were member functions"""
"""Allows you to call functions as if they were member functions (by returning a callable object)"""
# resolve and raise exception on error
ea = self.__name_or_ea(name_or_ea)
if ea == _idaapi.BADADDR:
@ -663,7 +773,7 @@ class Appcall__(object):
@staticmethod
def obj(**kwds):
"""Returns an empty object or objects with attributes as passed via its keywords arguments"""
return Appcall_object__(**kwds)
return object_t(**kwds)
@staticmethod
def cstr(val):
@ -695,12 +805,14 @@ class Appcall__(object):
@staticmethod
def set_appcall_options(opt):
"""Method to change the Appcall options globally (not per Appcall)"""
old_opt = Appcall__.get_appcall_options()
_idaapi.cvar.inf.appcall_options = opt
return old_opt
@staticmethod
def get_appcall_options():
"""Return the global Appcall options"""
return _idaapi.cvar.inf.appcall_options
@staticmethod

View File

@ -31,6 +31,7 @@
%ignore processor_t;
%ignore ph;
%ignore IDB_Callback;
%ignore IDP_Callback;
%ignore free_processor_module;
%ignore read_config_file;
@ -38,9 +39,8 @@
%ignore gen_idb_event;
%include "idp.hpp"
%feature("director") IDB_Hooks;
%feature("director") IDP_Hooks;
%inline %{
int idaapi IDB_Callback(void *ud, int notification_code, va_list va);
class IDB_Hooks
@ -61,8 +61,8 @@ public:
virtual int enum_bf_changed(enum_t id) { return 0; };
virtual int enum_renamed(enum_t id) { return 0; };
virtual int enum_cmt_changed(enum_t id) { return 0; };
virtual int enum_const_created(enum_t id, const_t cid) { return 0; };
virtual int enum_const_deleted(enum_t id, const_t cid) { return 0; };
virtual int enum_member_created(enum_t id, const_t cid) { return 0; };
virtual int enum_member_deleted(enum_t id, const_t cid) { return 0; };
virtual int struc_created(tid_t struc_id) { return 0; };
virtual int struc_deleted(tid_t struc_id) { return 0; };
virtual int struc_renamed(struc_t *sptr) { return 0; };
@ -84,6 +84,277 @@ public:
virtual int segm_moved(ea_t from, ea_t to, asize_t size) { return 0; };
};
// Assemble an instruction into the database (display a warning if an error is found)
// args:
// ea_t ea - linear address of instruction
// ea_t cs - cs of instruction
// ea_t ip - ip of instruction
// bool use32 - is 32bit segment?
// const char *line - line to assemble
// returns: 1: success, 0: failure
inline const int assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
{
int inslen;
char buf[MAXSTR];
if (ph.notify != NULL)
{
inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf);
if (inslen > 0)
{
patch_many_bytes(ea, buf, inslen);
return 1;
}
}
return 0;
}
//<inline(py_idp)>
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
/*
#<pydoc>
def AssembleLine(ea, cs, ip, use32, line):
"""
Assemble an instruction to a buffer (display a warning if an error is found)
@param ea: linear address of instruction
@param cs: cs of instruction
@param ip: ip of instruction
@param use32: is 32bit segment
@param line: line to assemble
@return:
- None on failure
- or a string containing the assembled instruction
"""
pass
#</pydoc>
*/
static PyObject *AssembleLine(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
{
int inslen;
char buf[MAXSTR];
if (ph.notify != NULL &&
(inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf)) > 0)
{
return PyString_FromStringAndSize(buf, inslen);
}
Py_RETURN_NONE;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def ph_get_tbyte_size():
"""
Returns the 'ph.tbyte_size' field as defined in he processor module
"""
pass
#</pydoc>
*/
static size_t ph_get_tbyte_size()
{
return ph.tbyte_size;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def ph_get_id():
"""
Returns the 'ph.id' field
"""
pass
#</pydoc>
*/
static size_t ph_get_id()
{
return ph.id;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def ph_get_instruc():
"""
Returns a list of tuples (instruction_name, instruction_feature) containing the
instructions list as defined in he processor module
"""
pass
#</pydoc>
*/
static PyObject *ph_get_instruc()
{
Py_ssize_t i = 0;
PyObject *py_result = PyTuple_New(ph.instruc_end - ph.instruc_start);
for ( instruc_t *p = ph.instruc + ph.instruc_start, *end = ph.instruc + ph.instruc_end;
p != end;
++p )
{
PyTuple_SetItem(py_result, i++, Py_BuildValue("(sI)", p->name, p->feature));
}
return py_result;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def ph_get_regnames():
"""
Returns the list of register names as defined in the processor module
"""
pass
#</pydoc>
*/
static PyObject *ph_get_regnames()
{
Py_ssize_t i = 0;
PyObject *py_result = PyList_New(ph.regsNum);
for ( Py_ssize_t i=0; i<ph.regsNum; i++ )
PyList_SetItem(py_result, i, PyString_FromString(ph.regNames[i]));
return py_result;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
class IDP_Hooks(object):
def custom_ana(self):
"""
Analyzes and decodes an instruction at idaapi.cmd.ea
- cmd.itype must be set >= idaapi.CUSTOM_CMD_ITYPE
- cmd.size must be set to the instruction length
@return: Boolean
- False if the instruction is not recognized
- True if the instruction was decoded. idaapi.cmd should be filled in that case.
"""
pass
def custom_out(self):
"""
Outputs the instruction defined in idaapi.cmd
@return: Boolean (whether this instruction can be outputted or not)
"""
pass
def custom_emu(self):
"""
Emulate instruction, create cross-references, plan to analyze
subsequent instructions, modify flags etc. Upon entrance to this function
all information about the instruction is in 'cmd' structure.
@return: Boolean (whether this instruction has been emulated or not)
"""
pass
def custom_outop(self, op):
"""
Notification to generate operand text.
If False was returned, then the standard operand output function will be called.
The output buffer is inited with init_output_buffer()
and this notification may use out_...() functions to form the operand text
@return: Boolean (whether the operand has been outputted or not)
"""
def custom_mnem(self):
"""
Prints the mnemonic of the instruction defined in idaapi.cmd
@return:
- None: No mnemonic. IDA will use the default mnemonic value if present
- String: The desired mnemonic string
"""
def is_sane_insn(self, no_crefs):
"""
is the instruction sane for the current file type?
@param no_crefs:
- 1: the instruction has no code refs to it.
ida just tries to convert unexplored bytes
to an instruction (but there is no other
reason to convert them into an instruction)
- 0: the instruction is created because
of some coderef, user request or another
weighty reason.
@return: 1-ok, <=0-no, the instruction isn't likely to appear in the program
"""
pass
def is_sane_insn(self, no_crefs):
"""
can a function start here?
@param state: autoanalysis phase
0: creating functions
1: creating chunks
@return: integer (probability 0..100)
"""
pass
#</pydoc>
*/
int idaapi IDP_Callback(void *ud, int notification_code, va_list va);
class IDP_Hooks
{
public:
virtual ~IDP_Hooks()
{
}
bool hook()
{
return hook_to_notification_point(HT_IDP, IDP_Callback, this);
}
bool unhook()
{
return unhook_from_notification_point(HT_IDP, IDP_Callback, this);
}
virtual bool custom_ana()
{
return false;
}
virtual bool custom_out()
{
return false;
}
virtual bool custom_emu()
{
return false;
}
virtual bool custom_outop(PyObject *py_op)
{
return false;
}
virtual PyObject *custom_mnem()
{
return NULL;
}
virtual int is_sane_insn(int no_crefs)
{
return 0;
}
virtual int may_be_func(int state)
{
return 0;
}
};
//</inline(py_idp)>
%}
%{
int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
{
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
@ -149,15 +420,15 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
id = va_arg(va, enum_t);
return proxy->enum_cmt_changed(id);
case idb_event::enum_const_created:
case idb_event::enum_member_created:
id = va_arg(va, enum_t);
cid = va_arg(va, const_t);
return proxy->enum_const_created(id, cid);
return proxy->enum_member_created(id, cid);
case idb_event::enum_const_deleted:
case idb_event::enum_member_deleted:
id = va_arg(va, enum_t);
cid = va_arg(va, const_t);
return proxy->enum_const_deleted(id, cid);
return proxy->enum_member_deleted(id, cid);
case idb_event::struc_created:
struc_id = va_arg(va, tid_t);
@ -256,84 +527,86 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
return 0;
}
// Assemble an instruction into the database (display a warning if an error is found)
// args:
// ea_t ea - linear address of instruction
// ea_t cs - cs of instruction
// ea_t ip - ip of instruction
// bool use32 - is 32bit segment?
// const char *line - line to assemble
// returns: 1: success, 0: failure
inline const int assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
//<code(py_idp)>
//-------------------------------------------------------------------------
int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
{
int inslen;
char buf[MAXSTR];
IDP_Hooks *proxy = (IDP_Hooks *)ud;
int ret;
try
{
switch ( notification_code )
{
default:
ret = 0;
break;
if (ph.notify != NULL)
case processor_t::custom_ana:
ret = proxy->custom_ana() ? 1 + cmd.size : 0;
break;
case processor_t::custom_out:
ret = proxy->custom_out() ? 2 : 0;
break;
case processor_t::custom_emu:
ret = proxy->custom_emu() ? 2 : 0;
break;
case processor_t::custom_outop:
{
inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf);
if (inslen > 0)
op_t *op = va_arg(va, op_t *);
PyObject *py_obj = create_idaapi_linked_class_instance(S_PY_OP_T_CLSNAME, op);
if ( py_obj == NULL )
break;
ret = proxy->custom_outop(py_obj) ? 2 : 0;
Py_XDECREF(py_obj);
break;
}
case processor_t::custom_mnem:
{
patch_many_bytes(ea, buf, inslen);
return 1;
PyObject *py_ret = proxy->custom_mnem();
if ( py_ret != NULL && PyString_Check(py_ret) )
{
char *outbuffer = va_arg(va, char *);
size_t bufsize = va_arg(va, size_t);
qstrncpy(outbuffer, PyString_AS_STRING(py_ret), bufsize);
ret = 2;
}
else
{
ret = 0;
}
Py_XDECREF(py_ret);
break;
}
case processor_t::is_sane_insn:
{
int no_crefs = va_arg(va, int);
ret = proxy->is_sane_insn(no_crefs);
break;
}
case processor_t::may_be_func:
{
int state = va_arg(va, int);
ret = proxy->may_be_func(state);
break;
}
}
return 0;
}
//<inline(py_idp)>
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
// Assemble an instruction to a buffer (display a warning if an error is found)
// args:
// ea_t ea - linear address of instruction
// ea_t cs - cs of instruction
// ea_t ip - ip of instruction
// bool use32 - is 32bit segment?
// const char *line - line to assemble
// returns: 1: success, 0: failure
static PyObject *AssembleLine(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
{
int inslen;
char buf[MAXSTR];
if (ph.notify != NULL &&
(inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf)) > 0)
{
return PyString_FromStringAndSize(buf, inslen);
}
Py_RETURN_NONE;
}
//-------------------------------------------------------------------------
static size_t ph_get_tbyte_size()
{
return ph.tbyte_size;
}
//-------------------------------------------------------------------------
static PyObject *ph_get_instruc()
{
Py_ssize_t i = 0;
PyObject *py_result = PyTuple_New(ph.instruc_end - ph.instruc_start);
for ( instruc_t *p = ph.instruc + ph.instruc_start, *end = ph.instruc + ph.instruc_end;
p != end;
++p )
catch (Swig::DirectorException &)
{
PyTuple_SetItem(py_result, i++, Py_BuildValue("(sI)", p->name, p->feature));
msg("Exception in IDP Hook function:\n");
if ( PyErr_Occurred() )
PyErr_Print();
}
return py_result;
return ret;
}
//-------------------------------------------------------------------------
static PyObject *ph_get_regnames()
{
Py_ssize_t i = 0;
PyObject *py_result = PyList_New(ph.regsNum);
for ( Py_ssize_t i=0; i<ph.regsNum; i++ )
PyList_SetItem(py_result, i, PyString_FromString(ph.regNames[i]));
return py_result;
}
//</inline(py_idp)>
//</code(py_idp)>
%}

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,7 @@
%ignore align_down_to_stack;
%ignore align_up_to_stack;
%ignore remove_spaces;
%ignore bgcolors;
%include "lines.hpp"
@ -67,10 +68,22 @@
%rename (tag_advance) py_tag_advance;
%rename (generate_disassembly) py_generate_disassembly;
%inline
{
%inline %{
//<inline(py_lines)>
//-------------------------------------------------------------------------
/*
#<pydoc>
def tag_remove(colstr):
"""
Remove color escape sequences from a string
@param colstr: the colored string with embedded tags
@return:
None on failure
or a new string w/o the tags
"""
pass
#</pydoc>
*/
PyObject *py_tag_remove(const char *instr)
{
size_t sz = strlen(instr);
@ -119,7 +132,28 @@ int py_tag_advance(const char *line, int cnt)
}
//-------------------------------------------------------------------------
PyObject *py_generate_disassembly(ea_t ea, int max_lines, bool as_stack, bool notags)
/*
#<pydoc>
def generate_disassembly(ea, max_lines, as_stack, notags):
"""
Generate disassembly lines (many lines) and put them into a buffer
@param ea: address to generate disassembly for
@param max_lines: how many lines max to generate
@param as_stack: Display undefined items as 2/4/8 bytes
@return:
- None on failure
- tuple(most_important_line_number, tuple(lines)) : Returns a tuple containing
the most important line number and a tuple of generated lines
"""
pass
#</pydoc>
*/
PyObject *py_generate_disassembly(
ea_t ea,
int max_lines,
bool as_stack,
bool notags)
{
if ( max_lines <= 0 )
Py_RETURN_NONE;
@ -150,7 +184,7 @@ PyObject *py_generate_disassembly(ea_t ea, int max_lines, bool as_stack, bool no
}
//</inline(py_lines)>
}
%}
%pythoncode %{
#<pycode(py_lines)>
@ -178,7 +212,12 @@ def requires_color_esc(c):
t = ord(c[0])
return c >= COLOR_ON and c <= COLOR_INV
def COLSTR(str,tag):
def COLSTR(str, tag):
"""
Utility function to create a colored line
@param str: The string
@param tag: Color tag constant. One of SCOLOR_XXXX
"""
return SCOLOR_ON + tag + str + SCOLOR_OFF + tag
#</pycode(py_lines)>

View File

@ -72,12 +72,14 @@
%ignore save_fileregions;
%ignore add_fileregion;
%ignore move_fileregions;
%ignore del_fileregions;
%ignore local_gen_idc_file;
%ignore print_all_places;
%ignore save_text_line;
%ignore print_all_structs;
%ignore print_all_enums;
%ignore enum_processor_modules;
%ignore enum_plugins;
%ignore database_id0;
%ignore is_database_ext;
%ignore ida_database_memory;

View File

@ -45,13 +45,47 @@ static int idaapi py_import_enum_cb(
Py_XDECREF(py_result);
return r;
}
//-------------------------------------------------------------------------
switch_info_ex_t *switch_info_ex_t_get_clink(PyObject *self)
{
if ( !PyObject_HasAttrString(self, S_CLINK_NAME) )
return NULL;
switch_info_ex_t *r;
PyObject *attr = PyObject_GetAttrString(self, S_CLINK_NAME);
if ( PyCObject_Check(attr) )
r = (switch_info_ex_t *) PyCObject_AsVoidPtr(attr);
else
r = NULL;
Py_DECREF(attr);
return r;
}
//</code(py_nalt)>
%}
%rename (get_switch_info_ex) py_get_switch_info_ex;
%rename (set_switch_info_ex) py_set_switch_info_ex;
%rename (del_switch_info_ex) py_del_switch_info_ex;
%rename (create_switch_xrefs) py_create_switch_xrefs;
%rename (create_switch_table) py_create_switch_table;
%inline %{
//<inline(py_nalt)>
//-------------------------------------------------------------------------
PyObject *py_get_import_module_name(int mod_index)
/*
#<pydoc>
def get_import_module_name(path, fname, callback):
"""
Returns the name of an imported module given its index
@return: None or the module name
"""
pass
#</pydoc>
*/
static PyObject *py_get_import_module_name(int mod_index)
{
char buf[MAXSTR];
if ( !get_import_module_name(mod_index, buf, sizeof(buf)) )
@ -60,14 +94,584 @@ PyObject *py_get_import_module_name(int mod_index)
}
//-------------------------------------------------------------------------
// enumerate imports from specific module
// return: 1-finished ok, -1 on error, otherwise callback return value (<=0)
int py_enum_import_names(int mod_index, PyObject *py_cb)
/*
#<pydoc>
def get_switch_info_ex(ea):
"""
Returns the a switch_info_ex_t structure containing the information about the switch.
Please refer to the SDK sample 'uiswitch'
@return: None or switch_info_ex_t instance
"""
pass
#</pydoc>
*/
PyObject *py_get_switch_info_ex(ea_t ea)
{
switch_info_ex_t *ex = new switch_info_ex_t();
PyObject *py_obj;
if ( ::get_switch_info_ex(ea, ex, sizeof(switch_info_ex_t)) <= 0
|| (py_obj = create_idaapi_linked_class_instance(S_PY_SWIEX_CLSNAME, ex)) == NULL )
{
delete ex;
Py_RETURN_NONE;
}
return py_obj;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def create_switch_xrefs(insn_ea, si):
"""
This function creates xrefs from the indirect jump.
Usually there is no need to call this function directly because the kernel
will call it for switch tables
Note: Custom switch information are not supported yet.
@param insn_ea: address of the 'indirect jump' instruction
@param si: switch information
@return: Boolean
"""
pass
#</pydoc>
*/
idaman bool ida_export py_create_switch_xrefs(
ea_t insn_ea,
PyObject *py_swi)
{
switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi);
if ( swi == NULL )
return false;
create_switch_xrefs(insn_ea, swi);
return true;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def create_switch_table(insn_ea, si):
"""
Create switch table from the switch information
@param insn_ea: address of the 'indirect jump' instruction
@param si: switch information
@return: Boolean
"""
pass
#</pydoc>
*/
idaman bool ida_export py_create_switch_table(
ea_t insn_ea,
PyObject *py_swi)
{
switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi);
if ( swi == NULL )
return false;
create_switch_table(insn_ea, swi);
return true;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def set_switch_info_ex(ea, switch_info_ex):
"""
Saves the switch information in the database
Please refer to the SDK sample 'uiswitch'
@return: Boolean
"""
pass
#</pydoc>
*/
bool py_set_switch_info_ex(ea_t ea, PyObject *py_swi)
{
switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi);
if ( swi == NULL )
return false;
set_switch_info_ex(ea, swi);
return true;
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def del_switch_info_ex(ea):
"""
Deletes stored switch information
"""
pass
#</pydoc>
*/
void py_del_switch_info_ex(ea_t ea)
{
del_switch_info_ex(ea);
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def enum_import_names(mod_index, callback):
"""
Enumerate imports from a specific module.
Please refer to ex_imports.py example.
@param mod_index: The module index
@param callback: A callable object that will be invoked with an ea, name (could be None) and ordinal.
@return: 1-finished ok, -1 on error, otherwise callback return value (<=0)
"""
pass
#</pydoc>
*/
static int py_enum_import_names(int mod_index, PyObject *py_cb)
{
if ( !PyCallable_Check(py_cb) )
return -1;
return enum_import_names(mod_index, py_import_enum_cb, py_cb);
}
//-------------------------------------------------------------------------
static PyObject *switch_info_ex_t_create()
{
switch_info_ex_t *inst = new switch_info_ex_t();
return PyCObject_FromVoidPtr(inst, NULL);
}
static bool switch_info_ex_t_destroy(PyObject *py_obj)
{
if ( !PyCObject_Check(py_obj) )
return false;
switch_info_ex_t *inst = (switch_info_ex_t *) PyCObject_AsVoidPtr(py_obj);
delete inst;
return true;
}
static bool switch_info_ex_t_assign(PyObject *self, PyObject *other)
{
switch_info_ex_t *lhs = switch_info_ex_t_get_clink(self);
switch_info_ex_t *rhs = switch_info_ex_t_get_clink(other);
if (lhs == NULL || rhs == NULL)
return false;
*lhs = *rhs;
return true;
}
//-------------------------------------------------------------------------
// Auto generated - begin
//
static PyObject *switch_info_ex_t_get_regdtyp(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue("b", (char)link->regdtyp);
}
static void switch_info_ex_t_set_regdtyp(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
link->regdtyp = (char)PyInt_AsLong(value);
}
static PyObject *switch_info_ex_t_get_flags2(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue("i", link->flags2);
}
static void switch_info_ex_t_set_flags2(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
link->flags2 = (int)PyInt_AsLong(value);
}
static PyObject *switch_info_ex_t_get_jcases(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue("i", link->jcases);
}
static void switch_info_ex_t_set_jcases(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
link->jcases = (int)PyInt_AsLong(value);
}
static PyObject *switch_info_ex_t_get_regnum(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue("i", (int)link->regnum);
}
static void switch_info_ex_t_set_regnum(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
link->regnum = (int)PyInt_AsLong(value);
}
static PyObject *switch_info_ex_t_get_flags(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue("H", (ushort)link->flags);
}
static void switch_info_ex_t_set_flags(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
link->flags = (uint16)PyInt_AsLong(value);
}
static PyObject *switch_info_ex_t_get_ncases(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue("H", (uint16)link->ncases);
}
static void switch_info_ex_t_set_ncases(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
link->ncases = (ushort)PyInt_AsLong(value);
}
static PyObject *switch_info_ex_t_get_defjump(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, (pyul_t)link->defjump);
}
static void switch_info_ex_t_set_defjump(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
uint64 v(0); PyGetNumber(value, &v);
link->defjump = (pyul_t)v;
}
static PyObject *switch_info_ex_t_get_jumps(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, (pyul_t)link->jumps);
}
static void switch_info_ex_t_set_jumps(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
uint64 v(0); PyGetNumber(value, &v);
link->jumps = (pyul_t)v;
}
static PyObject *switch_info_ex_t_get_elbase(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, (pyul_t)link->elbase);
}
static void switch_info_ex_t_set_elbase(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
uint64 v(0);
PyGetNumber(value, &v);
link->elbase = (pyul_t)v;
}
static PyObject *switch_info_ex_t_get_startea(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, (pyul_t)link->startea);
}
static void switch_info_ex_t_set_startea(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
uint64 v(0);
PyGetNumber(value, &v);
link->startea = (pyul_t)v;
}
static PyObject *switch_info_ex_t_get_custom(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, (pyul_t)link->custom);
}
static void switch_info_ex_t_set_custom(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
uint64 v(0);
PyGetNumber(value, &v);
link->custom = (pyul_t)v;
}
static PyObject *switch_info_ex_t_get_ind_lowcase(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, (pyul_t)link->ind_lowcase);
}
static void switch_info_ex_t_set_ind_lowcase(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
uint64 v(0);
PyGetNumber(value, &v);
link->ind_lowcase = (pyul_t)v;
}
static PyObject *switch_info_ex_t_get_values_lowcase(PyObject *self)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, (pyul_t)link->values);
}
static void switch_info_ex_t_set_values_lowcase(PyObject *self, PyObject *value)
{
switch_info_ex_t *link = switch_info_ex_t_get_clink(self);
if ( link == NULL )
return;
uint64 v(0);
PyGetNumber(value, &v);
link->values = (pyul_t)v;
}
//
// Auto generated - end
//
//-------------------------------------------------------------------------
//</inline(py_nalt)>
%}
%pythoncode %{
#<pycode(py_nalt)>
SWI_SPARSE = 0x1
"""sparse switch ( value table present ) otherwise lowcase present"""
SWI_V32 = 0x2
"""32-bit values in table"""
SWI_J32 = 0x4
"""32-bit jump offsets"""
SWI_VSPLIT = 0x8
"""value table is split (only for 32-bit values)"""
SWI_DEFAULT = 0x10
"""default case is present"""
SWI_END_IN_TBL = 0x20
"""switchend in table (default entry)"""
SWI_JMP_INV = 0x40
"""jumptable is inversed (last entry is for first entry in values table)"""
SWI_SHIFT_MASK = 0x180
"""use formula (element*shift + elbase) to find jump targets"""
SWI_ELBASE = 0x200
"""elbase is present (if not and shift!=0, endof(jumpea) is used)"""
SWI_JSIZE = 0x400
"""jump offset expansion bit"""
SWI_VSIZE = 0x800
"""value table element size expansion bit"""
SWI_SEPARATE = 0x1000
"""do not create an array of individual dwords"""
SWI_SIGNED = 0x2000
"""jump table entries are signed"""
SWI_CUSTOM = 0x4000
"""custom jump table - ph.create_switch_xrefs will be called to create code xrefs for the table. it must return 2. custom jump table must be created by the module"""
SWI_EXTENDED = 0x8000
"""this is switch_info_ex_t"""
SWI2_INDIRECT = 0x0001
"""value table elements are used as indexes into the jump table"""
SWI2_SUBTRACT = 0x0002
"""table values are subtracted from the elbase instead of being addded"""
# --------------------------------------------------------------------------
class switch_info_ex_t(py_clinked_object_t):
def __init__(self, lnk = None):
py_clinked_object_t.__init__(self, lnk)
def _create_clink(self):
return _idaapi.switch_info_ex_t_create()
def _del_clink(self, lnk):
return _idaapi.switch_info_ex_t_destroy(lnk)
def assign(self, other):
return _idaapi.switch_info_ex_t_assign(self, other)
def is_indirect(self):
return (self.flags & SWI_EXTENDED) != 0 and (self.flags2 & SWI2_INDIRECT) != 0
def is_subtract(self):
return (self.flags & SWI_EXTENDED) != 0 and (self.flags2 & SWI2_SUBTRACT) != 0
def get_jtable_size(self):
return self.jcases if self.is_indirect() else ncases
def get_lowcase(self):
return self.ind_lowcase if is_indirect() else self.lowcase
def set_expr(self, r, dt):
self.regnum = r
self.regdtyp = dt
def get_shift(self):
return (self.flags & SWI_SHIFT_MASK) >> 7
def set_shift(self, shift):
self.flags &= ~SWI_SHIFT_MASK
self.flags |= ((shift & 3) << 7)
def get_jtable_element_size(self):
code = self.flags & (SWI_J32|SWI_JSIZE)
if code == 0: return 2
elif code == SWI_J32: return 4
elif code == SWI_JSIZE: return 1
else: return 8
def set_jtable_element_size(self, size):
self.flags &= ~(SWI_J32|SWI_JSIZE)
if size == 4: self.flags |= SWI_J32
elif size == 1: self.flags |= SWI_JSIZE
elif size == 8: self.flags |= SWI_J32|SWI_JSIZE
elif size != 2: return False
return True
def get_vtable_element_size(self):
code = self.flags & (SWI_V32|SWI_VSIZE)
if code == 0: return 2
elif code == SWI_V32: return 4
elif code == SWI_VSIZE: return 1
return 8
def set_vtable_element_size(self, size):
self.flags &= ~SWI_V32|SWI_VSIZE
if size == 4: self.flags |= SWI_V32
elif size == 1: self.flags |= SWI_VSIZE
elif size == 8: self.flags |= SWI_V32|SWI_VSIZE
elif size != 2: return False
return True
#
# Autogenerated
#
def __get_regdtyp__(self):
return _idaapi.switch_info_ex_t_get_regdtyp(self)
def __set_regdtyp__(self, v):
_idaapi.switch_info_ex_t_set_regdtyp(self, v)
def __get_flags2__(self):
return _idaapi.switch_info_ex_t_get_flags2(self)
def __set_flags2__(self, v):
_idaapi.switch_info_ex_t_set_flags2(self, v)
def __get_jcases__(self):
return _idaapi.switch_info_ex_t_get_jcases(self)
def __set_jcases__(self, v):
_idaapi.switch_info_ex_t_set_jcases(self, v)
def __get_regnum__(self):
return _idaapi.switch_info_ex_t_get_regnum(self)
def __set_regnum__(self, v):
_idaapi.switch_info_ex_t_set_regnum(self, v)
def __get_flags__(self):
return _idaapi.switch_info_ex_t_get_flags(self)
def __set_flags__(self, v):
_idaapi.switch_info_ex_t_set_flags(self, v)
def __get_ncases__(self):
return _idaapi.switch_info_ex_t_get_ncases(self)
def __set_ncases__(self, v):
_idaapi.switch_info_ex_t_set_ncases(self, v)
def __get_defjump__(self):
return _idaapi.switch_info_ex_t_get_defjump(self)
def __set_defjump__(self, v):
_idaapi.switch_info_ex_t_set_defjump(self, v)
def __get_jumps__(self):
return _idaapi.switch_info_ex_t_get_jumps(self)
def __set_jumps__(self, v):
_idaapi.switch_info_ex_t_set_jumps(self, v)
def __get_elbase__(self):
return _idaapi.switch_info_ex_t_get_elbase(self)
def __set_elbase__(self, v):
_idaapi.switch_info_ex_t_set_elbase(self, v)
def __get_startea__(self):
return _idaapi.switch_info_ex_t_get_startea(self)
def __set_startea__(self, v):
_idaapi.switch_info_ex_t_set_startea(self, v)
def __get_custom__(self):
return _idaapi.switch_info_ex_t_get_custom(self)
def __set_custom__(self, v):
_idaapi.switch_info_ex_t_set_custom(self, v)
def __get_ind_lowcase__(self):
return _idaapi.switch_info_ex_t_get_ind_lowcase(self)
def __set_ind_lowcase__(self, v):
_idaapi.switch_info_ex_t_set_ind_lowcase(self, v)
def __get_values_lowcase__(self):
return _idaapi.switch_info_ex_t_get_values_lowcase(self)
def __set_values_lowcase__(self, v):
_idaapi.switch_info_ex_t_set_values_lowcase(self, v)
regdtyp = property(__get_regdtyp__, __set_regdtyp__)
"""size of the switch expression register as dtyp"""
flags2 = property(__get_flags2__, __set_flags2__)
jcases = property(__get_jcases__, __set_jcases__)
"""number of entries in the jump table (SWI2_INDIRECT)"""
regnum = property(__get_regnum__, __set_regnum__)
"""the switch expression as a register number"""
flags = property(__get_flags__, __set_flags__)
"""the switch expression as a register number"""
ncases = property(__get_ncases__, __set_ncases__)
"""number of cases (excluding default)"""
defjump = property(__get_defjump__, __set_defjump__)
"""default jump address"""
jumps = property(__get_jumps__, __set_jumps__)
"""jump table address"""
elbase = property(__get_elbase__, __set_elbase__)
"""element base"""
startea = property(__get_startea__, __set_startea__)
"""start of switch idiom"""
custom = property(__get_custom__, __set_custom__)
"""information for custom tables (filled and used by modules)"""
ind_lowcase = property(__get_ind_lowcase__, __set_ind_lowcase__)
values = property(__get_values_lowcase__, __set_values_lowcase__)
lowcase = property(__get_values_lowcase__, __set_values_lowcase__)
#</pycode(py_nalt)>
%}

View File

@ -39,6 +39,8 @@
%ignore netnode_suplast_idx8;
%ignore netnode_supprev_idx8;
%ignore netnode_supdel_all;
%ignore netnode_supdel_range;
%ignore netnode_supdel_range_idx8;
%ignore netnode_hashval;
%ignore netnode_hashstr;
%ignore netnode_hashval_long;

View File

@ -1,5 +1,57 @@
%ignore wchar2char;
%ignore hit_counter_t;
%ignore reg_hit_counter;
%ignore create_hit_counter;
%ignore hit_counter_timer;
%ignore print_all_counters;
%ignore incrementer_t;
%ignore reloc_info_t; // swig under mac chokes on this
%ignore qstrlen;
%ignore qstrcmp;
%ignore qstrstr;
%ignore qstrchr;
%ignore qstrrchr;
%ignore qstring;
%ignore qvector;
%ignore bytevec_t;
%ignore reloc_info_t;
%ignore relobj_t;
%ignore wchar2char;
%ignore u2cstr;
%ignore c2ustr;
%ignore utf8_unicode;
%ignore win_utf2idb;
%ignore char2oem;
%ignore oem2char;
%ignore set_codepages;
%ignore get_codepages;
%ignore convert_codepage;
%ignore test_bit;
%ignore set_bit;
%ignore clear_bit;
%ignore set_all_bits;
%ignore clear_all_bits;
%ignore interval::overlap;
%ignore interval::includes;
%ignore interval::contains;
%ignore qrotl;
%ignore qrotr;
%ignore setflag;
%ignore read2bytes;
%ignore rotate_left;
%ignore qswap;
%ignore swap32;
%ignore swap16;
%ignore swap_value;
%ignore qalloc_or_throw;
%ignore qrealloc_or_throw;
%ignore launch_process_t;
%ignore init_process;
%ignore term_process;
%ignore get_process_exit_code;
%ignore BELOW_NORMAL_PRIORITY_CLASS;
%ignore parse_command_line;
%rename (parse_command_line) py_parse_command_line;
%include "pro.h"

View File

@ -10,10 +10,8 @@
%ignore queue_del;
%ignore mark_rollback;
%ignore get_rollback_type;
%ignore mark_ida_decision;
%ignore unmark_ida_decision;
%ignore had_rolled_back;
%ignore ever_rolled_back;
%include "queue.hpp"

View File

@ -2,6 +2,7 @@
%ignore createSRarea;
%ignore killSRareas;
%ignore delSRarea;
%ignore splitSRarea;
%ignore SRareaStart;
%ignore SRareaEnd;
%ignore repairSRarea;

View File

@ -113,7 +113,10 @@
%ignore get_struct_member;
%ignore idb_type_to_til;
%ignore get_idb_type;
%ignore apply_type_to_stkarg;
%rename (apply_type_to_stkarg) py_apply_type_to_stkarg;
%ignore use_regarg_type_cb;
%ignore set_op_type_t;
%ignore is_stkarg_load_t;
@ -144,23 +147,6 @@
%include "typeinf.hpp"
%{
//<code(py_typeinf)>
//-------------------------------------------------------------------------
// Utility function to convert a python object to an IDC object
// and sets a python exception on failure.
static bool convert_pyobj_to_idc_exc(PyObject *py_obj, idc_value_t *idc_obj)
{
int sn = 0;
if (pyvar_to_idcvar(py_obj, idc_obj, &sn) < CIP_OK)
{
PyErr_SetString(PyExc_ValueError, "Could not convert Python object to IDC object!");
return false;
}
return true;
}
//</code(py_typeinf)>
%}
// Custom wrappers
%rename (load_til) load_til_wrap;
@ -177,7 +163,7 @@ PyObject *idc_parse_decl(til_t *ti, const char *decl, int flags)
qtype fields, type;
qstring name;
bool ok = parse_decl(ti, decl, &name, &type, &fields, flags);
if (!ok)
if ( !ok )
Py_RETURN_NONE;
return Py_BuildValue("(sss)",
name.c_str(),
@ -186,9 +172,23 @@ PyObject *idc_parse_decl(til_t *ti, const char *decl, int flags)
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def get_type_size0(ti, tp):
"""
Returns the size of a type
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string
@return:
- None on failure
- The size of the type
"""
pass
#</pydoc>
*/
PyObject *py_get_type_size0(const til_t *ti, PyObject *tp)
{
if (!PyString_Check(tp))
if ( !PyString_Check(tp) )
{
PyErr_SetString(PyExc_ValueError, "String expected!");
return NULL;
@ -200,13 +200,22 @@ PyObject *py_get_type_size0(const til_t *ti, PyObject *tp)
}
//-------------------------------------------------------------------------
// Read a typed idc object from the database
/*
#<pydoc>
def py_unpack_object_from_idb(ti, tp, fields, ea, pio_flags = 0):
"""
Unpacks from the database at 'ea' to an object.
Please refer to unpack_object_from_bv()
"""
pass
#</pydoc>
*/
PyObject *py_unpack_object_from_idb(
til_t *ti,
PyObject *py_type,
PyObject *py_fields,
ea_t ea,
int pio_flags)
int pio_flags = 0)
{
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) )
{
@ -236,13 +245,30 @@ PyObject *py_unpack_object_from_idb(
}
//-------------------------------------------------------------------------
// Read a typed idc object from the byte vector
/*
#<pydoc>
def unpack_object_from_bv(ti, tp, fields, bytes, pio_flags = 0):
"""
Unpacks a buffer into an object.
Returns the error_t returned by idaapi.pack_object_to_idb
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string
@param fields: type fields
@param bytes: the bytes to unpack
@param pio_flags: flags used while unpacking
@return:
- tuple(0, err) on failure
- tuple(1, obj) on success
"""
pass
#</pydoc>
*/
PyObject *py_unpack_object_from_bv(
til_t *ti,
PyObject *py_type,
PyObject *py_fields,
PyObject *py_bytes,
int pio_flags)
int pio_flags = 0)
{
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) && !PyString_Check(py_bytes) )
{
@ -278,18 +304,31 @@ PyObject *py_unpack_object_from_bv(
}
//-------------------------------------------------------------------------
// Write a typed idc object to the database
// Raises an exception if wrong parameters were passed or conversion fails
// Returns the error_t returned by idasdk.pack_object_to_idb
/*
#<pydoc>
def pack_object_to_idb(obj, ti, tp, fields, ea, pio_flags = 0):
"""
Write a typed object to the database.
Raises an exception if wrong parameters were passed or conversion fails
Returns the error_t returned by idaapi.pack_object_to_idb
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string
@param fields: type fields
@param ea: ea to be used while packing
@param pio_flags: flags used while unpacking
"""
pass
#</pydoc>
*/
PyObject *py_pack_object_to_idb(
PyObject *py_obj,
til_t *ti,
PyObject *py_type,
PyObject *py_fields,
ea_t ea,
int pio_flags)
int pio_flags = 0)
{
if (!PyString_Check(py_type) && !PyString_Check(py_fields))
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) )
{
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL;
@ -297,7 +336,7 @@ PyObject *py_pack_object_to_idb(
// Convert Python object to IDC object
idc_value_t idc_obj;
if (!convert_pyobj_to_idc_exc(py_obj, &idc_obj))
if ( !convert_pyobj_to_idc_exc(py_obj, &idc_obj) )
return NULL;
// Get type strings
@ -310,6 +349,23 @@ PyObject *py_pack_object_to_idb(
}
//-------------------------------------------------------------------------
/*
#<pydoc>
def pack_object_to_bv(obj, ti, tp, fields, ea, pio_flags = 0):
"""
Packs a typed object to a string
@param ti: Type info. 'idaapi.cvar.idati' can be passed.
@param tp: type string
@param fields: type fields
@param ea: ea to be used while packing
@param pio_flags: flags used while unpacking
@return:
tuple(0, err_code) on failure
tuple(1, packed_buf) on success
"""
pass
#</pydoc>
*/
// Returns a tuple(Boolean, PackedBuffer or Error Code)
PyObject *py_pack_object_to_bv(
PyObject *py_obj,
@ -319,7 +375,7 @@ PyObject *py_pack_object_to_bv(
ea_t base_ea,
int pio_flags=0)
{
if (!PyString_Check(py_type) && !PyString_Check(py_fields))
if ( !PyString_Check(py_type) && !PyString_Check(py_fields) )
{
PyErr_SetString(PyExc_ValueError, "Typestring must be passed!");
return NULL;
@ -327,7 +383,7 @@ PyObject *py_pack_object_to_bv(
// Convert Python object to IDC object
idc_value_t idc_obj;
if (!convert_pyobj_to_idc_exc(py_obj, &idc_obj))
if ( !convert_pyobj_to_idc_exc(py_obj, &idc_obj) )
return NULL;
// Get type strings
@ -346,15 +402,15 @@ PyObject *py_pack_object_to_bv(
pio_flags);
do
{
if (err != eOk)
if ( err != eOk )
break;
if (!bytes.relocate(base_ea, inf.mf))
if ( !bytes.relocate(base_ea, inf.mf) )
{
err = -1;
break;
}
return Py_BuildValue("(is#)", 1, bytes.begin(), bytes.size());
} while (false);
} while ( false );
return Py_BuildValue("(ii)", 0, err);
}
//</inline(py_typeinf)>

1367
swig/ua.i

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,8 @@
%ignore has_jump_or_flow_xref;
%ignore has_call_xref;
%ignore destroy_switch_info;
%ignore create_switch_xrefs;
%ignore create_switch_table;
// These functions should not be called directly (according to docs)
%ignore xrefblk_t_first_from;

85
tools/swigdocs.py Normal file
View File

@ -0,0 +1,85 @@
# -----------------------------------------------------------------------
# This script is used to extract embedded documentation strings
# from SWIG interface files.
# (c) Hex-Rays
#
import glob
import sys
# ---------------------------------------------------------------------------
def extract_docs(lines, out):
S_SWIG_CLOSE = '%}'
S_PYDOC_START = '#<pydoc>'
S_PYDOC_END = '#</pydoc>'
S_COMMENT = '#'
S_INLINE = '%inline %{'
S_PYCODE_START = '%pythoncode %{'
in_inline = False
in_pythoncode = False
in_pydoc = False
for line in lines:
line = line.rstrip()
# skip empty lines
if not line:
continue
# Inside pythoncode tag?
if in_pythoncode:
if line == S_PYDOC_START:
in_pydoc = True
continue
elif line == S_PYDOC_END:
in_pydoc = False
continue
elif line == S_SWIG_CLOSE:
in_pythoncode = False
continue
# Skip unneeded tags
elif line[:8] == '#<pycode' or line[:9] == '#</pycode':
continue
# In pydoc? uncomment the lines
elif in_pydoc:
if line[0] == S_COMMENT:
line = line[1:]
# All lines in pythoncode section are extracted
out.append(line)
# Inside inline tag?
elif in_inline:
if line == S_PYDOC_START:
in_pydoc = True
continue
elif line == S_SWIG_CLOSE:
in_inline = False
continue
elif line == S_PYDOC_END:
in_pydoc = False
continue
# Extract lines in cpydoc only
elif in_pydoc:
out.append(line)
# Detect tags
elif line == S_PYCODE_START:
in_pythoncode = True
continue
elif line == S_INLINE:
in_inline = True
# ---------------------------------------------------------------------------
def gen_docs(path = '../swig/', outfn = 'idaapi.py', mask = '*.i'):
out = []
for fn in glob.glob(path + mask):
f = open(fn, 'r')
lines = f.readlines()
f.close()
extract_docs(lines, out)
f = open(outfn, 'w')
f.write('"""This is a placeholder module used to document all the IDA SDK functions that are wrapped manually. You still need to import \'idaapi\' and not this module to use the functions"""\n')
f.write('\n'.join(out))
f.close()
if __name__ == '__main__':
gen_docs(mask='idaapi.i')