mirror of
https://github.com/cemu-project/idapython.git
synced 2024-12-25 01:01:52 +01:00
IDAPython 1.4.0 - IDA Pro 5.7 support
This commit is contained in:
parent
5f2262fad9
commit
3a5063330c
@ -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
|
||||
|
||||
|
16
CHANGES.txt
16
CHANGES.txt
@ -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
|
||||
------------------------------------
|
||||
|
81
build.py
81
build.py
@ -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)
|
||||
|
18
examples/ex_add_menu_item.py
Normal file
18
examples/ex_add_menu_item.py
Normal 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!"
|
@ -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
1281
python.cpp
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
|
245
python/idc.py
245
python/idc.py
@ -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
|
||||
|
179
python/init.py
179
python/init.py
@ -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.
|
46
pywraps.hpp
46
pywraps.hpp
@ -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
|
954
swig/bytes.i
954
swig/bytes.i
@ -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)>
|
||||
%}
|
32
swig/dbg.i
32
swig/dbg.i
@ -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;
|
||||
}
|
||||
|
120
swig/diskio.i
120
swig/diskio.i
@ -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)>
|
||||
%}
|
||||
|
@ -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;
|
||||
|
12
swig/expr.i
12
swig/expr.i
@ -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;
|
||||
|
80
swig/fpro.i
80
swig/fpro.i
@ -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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
10
swig/frame.i
10
swig/frame.i
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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):
|
||||
"""
|
||||
|
167
swig/graph.i
167
swig/graph.i
@ -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
|
||||
|
1558
swig/idaapi.i
1558
swig/idaapi.i
File diff suppressed because it is too large
Load Diff
406
swig/idd.i
406
swig/idd.i
@ -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
|
||||
|
425
swig/idp.i
425
swig/idp.i
@ -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)>
|
||||
%}
|
2956
swig/kernwin.i
2956
swig/kernwin.i
File diff suppressed because it is too large
Load Diff
49
swig/lines.i
49
swig/lines.i
@ -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)>
|
||||
|
@ -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;
|
||||
|
612
swig/nalt.i
612
swig/nalt.i
@ -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)>
|
||||
%}
|
@ -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;
|
||||
|
52
swig/pro.i
52
swig/pro.i
@ -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"
|
||||
|
||||
|
@ -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"
|
@ -2,6 +2,7 @@
|
||||
%ignore createSRarea;
|
||||
%ignore killSRareas;
|
||||
%ignore delSRarea;
|
||||
%ignore splitSRarea;
|
||||
%ignore SRareaStart;
|
||||
%ignore SRareaEnd;
|
||||
%ignore repairSRarea;
|
||||
|
124
swig/typeinf.i
124
swig/typeinf.i
@ -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)>
|
||||
|
@ -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
85
tools/swigdocs.py
Normal 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')
|
Loading…
Reference in New Issue
Block a user