mirror of
https://github.com/cemu-project/idapython.git
synced 2025-01-13 18:39:13 +01:00
IDAPython 1.4.1:
- added AUTHORS.txt and changed the banner - IDAPython_ExecFile() will print script execution errors to the log window too - added 'ph' into idaapi. It is a replacement for idaapi.cvar.ph - added runscript to init.py for backward compatibility - added cli_t support
This commit is contained in:
parent
8495e5205b
commit
6b0dfd84c0
13
AUTHORS.txt
Normal file
13
AUTHORS.txt
Normal file
@ -0,0 +1,13 @@
|
||||
The IDAPython Team:
|
||||
|
||||
* Gergely Erdelyi - http://d-dome.net/idapython/
|
||||
|
||||
Original IDAPython author.
|
||||
|
||||
* Hex-Rays - http://www.hex-rays.com/
|
||||
|
||||
Hex-Rays joined the project in September 2009 and started contributing.
|
||||
|
||||
* Ero Carrera - http://dkbza.org/
|
||||
|
||||
Project contributor
|
5
build.py
5
build.py
@ -36,7 +36,7 @@ else:
|
||||
# IDAPython version
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 4
|
||||
VERSION_PATCH = 0
|
||||
VERSION_PATCH = 1
|
||||
|
||||
# Determine Python version
|
||||
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
|
||||
@ -66,12 +66,15 @@ BINDIST_MANIFEST = [
|
||||
"README.txt",
|
||||
"COPYING.txt",
|
||||
"CHANGES.txt",
|
||||
"AUTHORS.txt",
|
||||
"STATUS.txt",
|
||||
"docs/notes.txt",
|
||||
"examples/chooser.py",
|
||||
"examples/colours.py",
|
||||
"examples/debughook.py",
|
||||
"examples/ex_cli.py",
|
||||
"examples/ex1.idc",
|
||||
"examples/ex_custdata.py",
|
||||
"examples/ex1_idaapi.py",
|
||||
"examples/ex1_idautils.py",
|
||||
"examples/hotkey.py",
|
||||
|
100
examples/ex_cli.py
Normal file
100
examples/ex_cli.py
Normal file
@ -0,0 +1,100 @@
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to implement a CLI
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
from idaapi import NW_OPENIDB, NW_CLOSEIDB, NW_TERMIDA, NW_REMOVE, COLSTR, cli_t
|
||||
|
||||
#<pycode(ex_cli_ex1)>
|
||||
class mycli_t(cli_t):
|
||||
flags = 0
|
||||
sname = "pycli"
|
||||
lname = "Python CLI"
|
||||
hint = "pycli hint"
|
||||
|
||||
def OnExecuteLine(self, line):
|
||||
"""
|
||||
The user pressed Enter. The CLI is free to execute the line immediately or ask for more lines.
|
||||
|
||||
This callback is mandatory.
|
||||
|
||||
@param line: typed line(s)
|
||||
@return Boolean: True-executed line, False-ask for more lines
|
||||
"""
|
||||
print "OnExecute:", line
|
||||
return True
|
||||
|
||||
def OnKeydown(self, line, x, sellen, vkey, shift):
|
||||
"""
|
||||
A keyboard key has been pressed
|
||||
This is a generic callback and the CLI is free to do whatever it wants.
|
||||
|
||||
This callback is optional.
|
||||
|
||||
@param line: current input line
|
||||
@param x: current x coordinate of the cursor
|
||||
@param sellen: current selection length (usually 0)
|
||||
@param vkey: virtual key code. if the key has been handled, it should be returned as zero
|
||||
@param shift: shift state
|
||||
|
||||
@return:
|
||||
None - Nothing was changed
|
||||
tuple(line, x, sellen, vkey): if either of the input line or the x coordinate or the selection length has been modified.
|
||||
It is possible to return a tuple with None elements to preserve old values. Example: tuple(new_line, None, None, None) or tuple(new_line)
|
||||
"""
|
||||
print "Onkeydown: line=%s x=%d sellen=%d vkey=%d shift=%d" % (line, x, sellen, vkey, shift)
|
||||
return None
|
||||
|
||||
def OnCompleteLine(self, prefix, n, line, prefix_start):
|
||||
"""
|
||||
The user pressed Tab. Find a completion number N for prefix PREFIX
|
||||
|
||||
This callback is optional.
|
||||
|
||||
@param prefix: Line prefix at x (string)
|
||||
@param n: completion number (int)
|
||||
@param line: the current line (string)
|
||||
@param prefix_start: the index where PREFIX starts in LINE (int)
|
||||
|
||||
@return: None if no completion could be generated otherwise a String with the completion suggestion
|
||||
"""
|
||||
print "OnCompleteLine: prefix=%s n=%d line=%s prefix_start=%d" % (prefix, n, line, prefix_start)
|
||||
return None
|
||||
#</pycode(ex_cli_ex1)>
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def nw_handler(code, old=0):
|
||||
if code == NW_OPENIDB:
|
||||
print "nw_handler(): installing CLI"
|
||||
mycli.register()
|
||||
elif code == NW_CLOSEIDB:
|
||||
print "nw_handler(): removing CLI"
|
||||
mycli.unregister()
|
||||
elif code == NW_TERMIDA:
|
||||
print "nw_handler(): uninstalled nw handler"
|
||||
idaapi.notify_when(NW_TERMIDA | NW_OPENIDB | NW_CLOSEIDB | NW_REMOVE, nw_handler)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# Already installed?
|
||||
try:
|
||||
mycli
|
||||
# remove previous CLI
|
||||
mycli.unregister()
|
||||
del mycli
|
||||
# remove previous handler
|
||||
nw_handler(NW_TERMIDA)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
mycli = mycli_t()
|
||||
|
||||
# register CLI
|
||||
if mycli.register():
|
||||
print "CLI installed"
|
||||
# install new handler
|
||||
idaapi.notify_when(NW_TERMIDA | NW_OPENIDB | NW_CLOSEIDB, nw_handler)
|
||||
else:
|
||||
del mycli
|
||||
print "Failed to install CLI"
|
||||
|
216
examples/ex_custdata.py
Normal file
216
examples/ex_custdata.py
Normal file
@ -0,0 +1,216 @@
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to use custom data types in Python
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
from idaapi import data_type_t, data_format_t, NW_OPENIDB, NW_CLOSEIDB, NW_TERMIDA, NW_REMOVE, COLSTR
|
||||
import struct
|
||||
import ctypes
|
||||
import platform
|
||||
|
||||
#<pycode(ex_custdata)>
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class pascal_data_type(data_type_t):
|
||||
def __init__(self):
|
||||
data_type_t.__init__(self, name="py_pascal_string",
|
||||
value_size = 2, menu_name = "Pascal string",
|
||||
asm_keyword = "pstr")
|
||||
|
||||
def calc_item_size(self, ea, maxsize):
|
||||
# Custom data types may be used in structure definitions. If this case
|
||||
# ea is a member id. Check for this situation and return 1
|
||||
if _idaapi.is_member_id(ea):
|
||||
return 1
|
||||
|
||||
# get the length byte
|
||||
n = _idaapi.get_byte(ea)
|
||||
|
||||
# string too big?
|
||||
if n > maxsize:
|
||||
return 0
|
||||
# ok, accept the string
|
||||
return n + 1
|
||||
|
||||
class pascal_data_format(data_format_t):
|
||||
FORMAT_NAME = "py_pascal_string_pstr"
|
||||
def __init__(self):
|
||||
data_format_t.__init__(self, name=pascal_data_format.FORMAT_NAME)
|
||||
|
||||
def printf(self, value, current_ea, operand_num, dtid):
|
||||
# Take the length byte
|
||||
n = ord(value[0])
|
||||
o = ['"']
|
||||
for ch in value[1:]:
|
||||
b = ord(ch)
|
||||
if b < 0x20 or b > 128:
|
||||
o.append(r'\x%02x' % ord(ch))
|
||||
else:
|
||||
o.append(ch)
|
||||
o.append('"')
|
||||
return "".join(o)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class simplevm_data_type(data_type_t):
|
||||
ASM_KEYWORD = "svm_emit"
|
||||
def __init__(self):
|
||||
data_type_t.__init__(self,
|
||||
name="py_simple_vm",
|
||||
value_size = 1,
|
||||
menu_name = "SimpleVM",
|
||||
asm_keyword = simplevm_data_type.ASM_KEYWORD)
|
||||
|
||||
def calc_item_size(self, ea, maxsize):
|
||||
if _idaapi.is_member_id(ea):
|
||||
return 1
|
||||
# get the opcode and see if it has an imm
|
||||
n = 5 if (_idaapi.get_byte(ea) & 3) == 0 else 1
|
||||
# string too big?
|
||||
if n > maxsize:
|
||||
return 0
|
||||
# ok, accept
|
||||
return n
|
||||
|
||||
class simplevm_data_format(data_format_t):
|
||||
def __init__(self):
|
||||
data_format_t.__init__(self,
|
||||
name="py_simple_vm_format",
|
||||
menu_name = "SimpleVM")
|
||||
|
||||
# Some tables for the disassembler
|
||||
INST = {1: 'add', 2: 'mul', 3: 'sub', 4: 'xor', 5: 'mov'}
|
||||
REGS = {1: 'r1', 2: 'r2', 3: 'r3'}
|
||||
def disasm(self, inst):
|
||||
"""A simple local disassembler. In reality one can use a full-blown disassembler to render the text"""
|
||||
opbyte = ord(inst[0])
|
||||
op = opbyte >> 4
|
||||
if not (1<=op<=5):
|
||||
return None
|
||||
r1 = (opbyte & 0xf) >> 2
|
||||
r2 = opbyte & 3
|
||||
sz = 0
|
||||
if r2 == 0:
|
||||
if len(inst) != 5:
|
||||
return None
|
||||
imm = struct.unpack_from('L', inst, 1)[0]
|
||||
sz = 5
|
||||
else:
|
||||
imm = None
|
||||
sz = 1
|
||||
text = "%s %s, %s" % (
|
||||
COLSTR(simplevm_data_format.INST[op], idaapi.SCOLOR_INSN),
|
||||
COLSTR(simplevm_data_format.REGS[r1], idaapi.SCOLOR_REG),
|
||||
COLSTR("0x%08X" % imm, idaapi.SCOLOR_NUMBER) if imm is not None else COLSTR(simplevm_data_format.REGS[r2], idaapi.SCOLOR_REG))
|
||||
return (sz, text)
|
||||
|
||||
def printf(self, value, current_ea, operand_num, dtid):
|
||||
r = self.disasm(value)
|
||||
if not r:
|
||||
return None
|
||||
if dtid == 0:
|
||||
return "%s(%s)" % (simplevm_data_type.ASM_KEYWORD, r[1])
|
||||
return r[1]
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# This format will display DWORD values as MAKE_DWORD(0xHI, 0xLO)
|
||||
class makedword_data_format(data_format_t):
|
||||
def __init__(self):
|
||||
data_format_t.__init__(self,
|
||||
name="py_makedword",
|
||||
value_size = 4,
|
||||
menu_name = "Make DWORD")
|
||||
|
||||
def printf(self, value, current_ea, operand_num, dtid):
|
||||
if len(value) != 4: return None
|
||||
w1 = struct.unpack_from("H", value, 0)[0]
|
||||
w2 = struct.unpack_from("H", value, 2)[0]
|
||||
return "MAKE_DWORD(0x%04X, 0x%04X)" % (w2, w1)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# This format will try to load a resource string given a number
|
||||
# So instead of displaying:
|
||||
# push 66h
|
||||
# call message_box_from_rsrc_string
|
||||
# It can be rendered as;
|
||||
# push RSRC("The message")
|
||||
# call message_box_from_rsrc_string
|
||||
#
|
||||
# The get_rsrc_string() is not optimal since it loads/unloads the
|
||||
# DLL each time for a new string. It can be improved in many ways.
|
||||
class rsrc_string_format(data_format_t):
|
||||
def __init__(self):
|
||||
data_format_t.__init__(self,
|
||||
name="py_w32rsrcstring",
|
||||
value_size = 1,
|
||||
menu_name = "Resource string")
|
||||
self.cache_node = idaapi.netnode("$ py_w32rsrcstring", 0, 1)
|
||||
|
||||
def get_rsrc_string(self, fn, id):
|
||||
"""
|
||||
Simple method that loads the input file as a DLL with LOAD_LIBRARY_AS_DATAFILE flag.
|
||||
It then tries to LoadString()
|
||||
"""
|
||||
k32 = ctypes.windll.kernel32
|
||||
u32 = ctypes.windll.user32
|
||||
|
||||
hinst = k32.LoadLibraryExA(fn, 0, 0x2)
|
||||
if hinst == 0:
|
||||
return ""
|
||||
buf = ctypes.create_string_buffer(1024)
|
||||
r = u32.LoadStringA(hinst, id, buf, 1024-1)
|
||||
k32.FreeLibrary(hinst)
|
||||
return buf.value if r else ""
|
||||
|
||||
def printf(self, value, current_ea, operand_num, dtid):
|
||||
# Is it already cached?
|
||||
val = self.cache_node.supval(current_ea)
|
||||
|
||||
# Not cached?
|
||||
if val == None:
|
||||
# Retrieve it
|
||||
num = idaapi.struct_unpack(value)
|
||||
val = self.get_rsrc_string(idaapi.get_input_file_path(), num)
|
||||
# Cache it
|
||||
self.cache_node.supset(current_ea, val)
|
||||
|
||||
# Failed to retrieve?
|
||||
if val == "" or val == "\x00":
|
||||
return None
|
||||
# Return the format
|
||||
return "RSRC_STR(\"%s\")" % COLSTR(val, idaapi.SCOLOR_IMPNAME)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Table of formats and types to be registered/unregistered
|
||||
# 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, the tuple[0] is the data type and tuple[1:] are the data formats
|
||||
new_formats = [
|
||||
(pascal_data_type(), pascal_data_format()),
|
||||
(simplevm_data_type(), simplevm_data_format()),
|
||||
(makedword_data_format(),),
|
||||
(simplevm_data_format(),)
|
||||
]
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
new_formats.append((rsrc_string_format(),))
|
||||
|
||||
#</pycode(ex_custdata)>
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def nw_handler(code, old=0):
|
||||
# delete notifications
|
||||
if code == NW_OPENIDB:
|
||||
idaapi.register_data_types_and_formats(new_formats)
|
||||
elif code == NW_CLOSEIDB:
|
||||
idaapi.unregister_data_types_and_formats(new_formats)
|
||||
elif code == NW_TERMIDA:
|
||||
idaapi.notify_when(NW_TERMIDA | NW_OPENIDB | NW_CLOSEIDB | NW_REMOVE, nw_handler)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Check if already installed
|
||||
if idaapi.find_custom_data_type(pascal_data_format.FORMAT_NAME) == -1:
|
||||
if not idaapi.register_data_types_and_formats(new_formats):
|
||||
print "Failed to register types!"
|
||||
else:
|
||||
idaapi.notify_when(NW_TERMIDA | NW_OPENIDB | NW_CLOSEIDB, nw_handler)
|
||||
print "Formats installed!"
|
||||
else:
|
||||
print "Formats already installed!"
|
@ -39,16 +39,27 @@ class IDAPythonStdOut:
|
||||
def isatty(self):
|
||||
return False
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def runscript(script):
|
||||
"""
|
||||
Executes a script.
|
||||
This function is present for backward compatiblity. Please use idaapi.IDAPython_ExecScript() instead
|
||||
|
||||
@param script: script path
|
||||
|
||||
@return: Error string or None on success
|
||||
"""
|
||||
|
||||
import idaapi
|
||||
return idaapi.IDAPython_ExecScript(script, globals())
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def print_banner():
|
||||
banner = [
|
||||
"Python interpreter version %d.%d.%d %s (serial %d)" % sys.version_info,
|
||||
"Copyright (c) 1990-2010 Python Software Foundation - http://www.python.org/",
|
||||
"",
|
||||
"IDAPython" + (" 64-bit" if __EA64__ else "") + " version %d.%d.%d %s (serial %d)" % IDAPYTHON_VERSION,
|
||||
"Copyright (c) 2004-2010 Gergely Erdelyi - http://code.google.com/p/idapython/"
|
||||
"Python %d.%d.%d %s (serial %d) (c) 1990-2010 Python Software Foundation" % sys.version_info,
|
||||
"IDAPython" + (" 64-bit" if __EA64__ else "") + " v%d.%d.%d %s (serial %d) (c) The IDAPython Team <idapython@googlegroups.com>" % IDAPYTHON_VERSION
|
||||
]
|
||||
sepline = '-' * max([len(s) for s in banner])
|
||||
sepline = '-' * (max([len(s) for s in banner])+1)
|
||||
|
||||
print sepline
|
||||
print "\n".join(banner)
|
||||
|
@ -726,7 +726,7 @@ void pyg_select_node(PyObject *self, int nid)
|
||||
}
|
||||
//</code(py_graph)>
|
||||
%}
|
||||
#endif
|
||||
#endif // __NT__
|
||||
|
||||
#ifdef __NT__
|
||||
%inline %{
|
||||
@ -739,9 +739,8 @@ void pyg_select_node(PyObject *self, int nid);
|
||||
bool pyg_show(PyObject *self);
|
||||
//</inline(py_graph)>
|
||||
%}
|
||||
#endif
|
||||
#endif // __NT__
|
||||
|
||||
#ifdef __NT__
|
||||
%pythoncode %{
|
||||
#<pycode(py_graph)>
|
||||
class GraphViewer:
|
||||
@ -907,4 +906,4 @@ class GraphViewer:
|
||||
#</pydoc>
|
||||
#</pycode(py_graph)>
|
||||
%}
|
||||
#endif
|
||||
|
||||
|
@ -1919,6 +1919,7 @@ def IDAPython_ExecScript(script, g):
|
||||
execfile(script, g)
|
||||
except Exception, e:
|
||||
PY_COMPILE_ERR = str(e) + "\n" + traceback.format_exc()
|
||||
print PY_COMPILE_ERR
|
||||
finally:
|
||||
# Restore the globals to the state before the script was run
|
||||
g['__file__'] = old__file__
|
||||
@ -2132,7 +2133,5 @@ static bool notify_when(int when, PyObject *py_callable)
|
||||
%include "typeinf.i"
|
||||
%include "ua.i"
|
||||
%include "xref.i"
|
||||
#ifdef __NT__
|
||||
%include "graph.i"
|
||||
#endif
|
||||
%include "graph.i"
|
||||
%include "fpro.i"
|
||||
|
225
swig/idp.i
225
swig/idp.i
@ -143,21 +143,6 @@ static PyObject *AssembleLine(ea_t ea, ea_t cs, ea_t ip, bool use32, const char
|
||||
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>
|
||||
@ -173,6 +158,216 @@ static size_t ph_get_id()
|
||||
return ph.id;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_version():
|
||||
"""
|
||||
Returns the 'ph.version'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_version()
|
||||
{
|
||||
return ph.version;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_flag():
|
||||
"""
|
||||
Returns the 'ph.flag'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_flag()
|
||||
{
|
||||
return ph.flag;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_cnbits():
|
||||
"""
|
||||
Returns the 'ph.cnbits'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_cnbits()
|
||||
{
|
||||
return ph.cnbits;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_dnbits():
|
||||
"""
|
||||
Returns the 'ph.dnbits'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_dnbits()
|
||||
{
|
||||
return ph.dnbits;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_regFirstSreg():
|
||||
"""
|
||||
Returns the 'ph.regFirstSreg'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_regFirstSreg()
|
||||
{
|
||||
return ph.regFirstSreg;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_regLastSreg():
|
||||
"""
|
||||
Returns the 'ph.regLastSreg'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_regLastSreg()
|
||||
{
|
||||
return ph.regLastSreg;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_segreg_size():
|
||||
"""
|
||||
Returns the 'ph.segreg_size'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_segreg_size()
|
||||
{
|
||||
return ph.segreg_size;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_regCodeSreg():
|
||||
"""
|
||||
Returns the 'ph.regCodeSreg'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_regCodeSreg()
|
||||
{
|
||||
return ph.regCodeSreg;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_regDataSreg():
|
||||
"""
|
||||
Returns the 'ph.regDataSreg'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_regDataSreg()
|
||||
{
|
||||
return ph.regDataSreg;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_high_fixup_bits():
|
||||
"""
|
||||
Returns the 'ph.high_fixup_bits'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_high_fixup_bits()
|
||||
{
|
||||
return ph.high_fixup_bits;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_icode_return():
|
||||
"""
|
||||
Returns the 'ph.icode_return'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_icode_return()
|
||||
{
|
||||
return ph.icode_return;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_instruc_start():
|
||||
"""
|
||||
Returns the 'ph.instruc_start'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_instruc_start()
|
||||
{
|
||||
return ph.instruc_start;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def ph_get_instruc_end():
|
||||
"""
|
||||
Returns the 'ph.instruc_end'
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static size_t ph_get_instruc_end()
|
||||
{
|
||||
return ph.instruc_end;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<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>
|
||||
|
381
swig/kernwin.i
381
swig/kernwin.i
@ -22,8 +22,12 @@
|
||||
%ignore skipSpaces;
|
||||
%ignore stristr;
|
||||
|
||||
// Ignore the cli_t class
|
||||
// CLI
|
||||
%ignore cli_t;
|
||||
%ignore install_command_interpreter;
|
||||
%rename (install_command_interpreter) py_install_command_interpreter;
|
||||
%ignore remove_command_interpreter;
|
||||
%rename (remove_command_interpreter) py_remove_command_interpreter;
|
||||
|
||||
%include "typemaps.i"
|
||||
|
||||
@ -755,6 +759,262 @@ PyObject *choose2_find(const char *title)
|
||||
|
||||
#ifdef __NT__
|
||||
%{
|
||||
//<code(py_cli)>
|
||||
//--------------------------------------------------------------------------
|
||||
#define MAX_PY_CLI 12
|
||||
|
||||
// Callbacks table
|
||||
// This structure was devised because the cli callbacks have no user-data parameter
|
||||
struct py_cli_cbs_t
|
||||
{
|
||||
bool (idaapi *execute_line)(const char *line);
|
||||
bool (idaapi *complete_line)(
|
||||
qstring *completion,
|
||||
const char *prefix,
|
||||
int n,
|
||||
const char *line,
|
||||
int x);
|
||||
bool (idaapi *keydown)(
|
||||
qstring *line,
|
||||
int *p_x,
|
||||
int *p_sellen,
|
||||
uint16 *vk_key,
|
||||
int shift);
|
||||
};
|
||||
|
||||
// CLI Python wrapper class
|
||||
class py_cli_t
|
||||
{
|
||||
private:
|
||||
//--------------------------------------------------------------------------
|
||||
cli_t cli;
|
||||
PyObject *self;
|
||||
qstring cli_sname, cli_lname, cli_hint;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static py_cli_t *py_clis[MAX_PY_CLI];
|
||||
static const py_cli_cbs_t py_cli_cbs[MAX_PY_CLI];
|
||||
//--------------------------------------------------------------------------
|
||||
#define IMPL_PY_CLI_CB(CBN) \
|
||||
static bool idaapi s_keydown##CBN(qstring *line, int *p_x, int *p_sellen, uint16 *vk_key, int shift) \
|
||||
{ \
|
||||
return py_clis[CBN]->on_keydown(line, p_x, p_sellen, vk_key, shift); \
|
||||
} \
|
||||
static bool idaapi s_execute_line##CBN(const char *line) \
|
||||
{ \
|
||||
return py_clis[CBN]->on_execute_line(line); \
|
||||
} \
|
||||
static bool idaapi s_complete_line##CBN(qstring *completion, const char *prefix, int n, const char *line, int x) \
|
||||
{ \
|
||||
return py_clis[CBN]->on_complete_line(completion, prefix, n, line, x); \
|
||||
}
|
||||
|
||||
IMPL_PY_CLI_CB(0); IMPL_PY_CLI_CB(1); IMPL_PY_CLI_CB(2); IMPL_PY_CLI_CB(3);
|
||||
IMPL_PY_CLI_CB(4); IMPL_PY_CLI_CB(5); IMPL_PY_CLI_CB(6); IMPL_PY_CLI_CB(7);
|
||||
IMPL_PY_CLI_CB(8); IMPL_PY_CLI_CB(9); IMPL_PY_CLI_CB(10); IMPL_PY_CLI_CB(11);
|
||||
#undef IMPL_PY_CLI_CB
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// callback: the user pressed Enter
|
||||
// CLI is free to execute the line immediately or ask for more lines
|
||||
// Returns: true-executed line, false-ask for more lines
|
||||
bool on_execute_line(const char *line)
|
||||
{
|
||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_EXECUTE_LINE, "s", line);
|
||||
bool ok = result != NULL && PyObject_IsTrue(result);
|
||||
PyW_ShowErr(S_ON_EXECUTE_LINE);
|
||||
Py_XDECREF(result);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// callback: a keyboard key has been pressed
|
||||
// This is a generic callback and the CLI is free to do whatever
|
||||
// it wants.
|
||||
// line - current input line (in/out argument)
|
||||
// p_x - pointer to current x coordinate of the cursor (in/out)
|
||||
// p_sellen - pointer to current selection length (usually 0)
|
||||
// p_vk_key - pointer to virtual key code (in/out)
|
||||
// if the key has been handled, it should be reset to 0 by CLI
|
||||
// shift - shift state
|
||||
// Returns: true-modified input line or x coordinate or selection length
|
||||
// This callback is optional
|
||||
bool on_keydown(
|
||||
qstring *line,
|
||||
int *p_x,
|
||||
int *p_sellen,
|
||||
uint16 *vk_key,
|
||||
int shift)
|
||||
{
|
||||
PyObject *result = PyObject_CallMethod(
|
||||
self,
|
||||
(char *)S_ON_KEYDOWN,
|
||||
"siiHi",
|
||||
line->c_str(),
|
||||
*p_x,
|
||||
*p_sellen,
|
||||
*vk_key,
|
||||
shift);
|
||||
|
||||
bool ok = result != NULL && PyTuple_Check(result);
|
||||
|
||||
PyW_ShowErr(S_ON_KEYDOWN);
|
||||
|
||||
if ( ok )
|
||||
{
|
||||
Py_ssize_t sz = PyTuple_Size(result);
|
||||
PyObject *item;
|
||||
|
||||
if ( sz > 0 && (item = PyTuple_GetItem(result, 0)) != NULL && PyString_Check(item) )
|
||||
*line = PyString_AsString(item);
|
||||
|
||||
if ( sz > 1 && (item = PyTuple_GetItem(result, 1)) != NULL && PyInt_Check(item) )
|
||||
*p_x = PyInt_AsLong(item);
|
||||
|
||||
if ( sz > 2 && (item = PyTuple_GetItem(result, 2)) != NULL && PyInt_Check(item) )
|
||||
*p_sellen = PyInt_AsLong(item);
|
||||
|
||||
if ( sz > 3 && (item = PyTuple_GetItem(result, 3)) != NULL && PyInt_Check(item) )
|
||||
*vk_key = PyInt_AsLong(item) & 0xffff;
|
||||
}
|
||||
|
||||
Py_XDECREF(result);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// callback: the user pressed Tab
|
||||
// Find a completion number N for prefix PREFIX
|
||||
// LINE is given as context information. X is the index where PREFIX starts in LINE
|
||||
// New prefix should be stored in PREFIX.
|
||||
// Returns: true if generated a new completion
|
||||
// This callback is optional
|
||||
bool on_complete_line(
|
||||
qstring *completion,
|
||||
const char *prefix,
|
||||
int n,
|
||||
const char *line,
|
||||
int x)
|
||||
{
|
||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_COMPLETE_LINE, "sisi", prefix, n, line, x);
|
||||
bool ok = result != NULL && PyString_Check(result);
|
||||
PyW_ShowErr(S_ON_COMPLETE_LINE);
|
||||
if ( ok )
|
||||
*completion = PyString_AsString(result);
|
||||
|
||||
Py_XDECREF(result);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Private ctor (use bind())
|
||||
py_cli_t()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
//---------------------------------------------------------------------------
|
||||
static int bind(PyObject *py_obj)
|
||||
{
|
||||
int cli_idx;
|
||||
// Find an empty slot
|
||||
for ( cli_idx = 0; cli_idx < MAX_PY_CLI; ++cli_idx )
|
||||
{
|
||||
if ( py_clis[cli_idx] == NULL )
|
||||
break;
|
||||
}
|
||||
py_cli_t *py_cli = NULL;
|
||||
do
|
||||
{
|
||||
// No free slots?
|
||||
if ( cli_idx >= MAX_PY_CLI )
|
||||
break;
|
||||
|
||||
// Create a new instance
|
||||
py_cli = new py_cli_t();
|
||||
PyObject *attr;
|
||||
|
||||
// Start populating the 'cli' member
|
||||
py_cli->cli.size = sizeof(cli_t);
|
||||
|
||||
// Store 'flags'
|
||||
if ( (attr = PyW_TryGetAttrString(py_obj, S_FLAGS)) == NULL )
|
||||
{
|
||||
py_cli->cli.flags = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
py_cli->cli.flags = PyLong_AsLong(attr);
|
||||
Py_DECREF(attr);
|
||||
}
|
||||
|
||||
// Store 'sname'
|
||||
if ( !PyW_GetStringAttr(py_obj, "sname", &py_cli->cli_sname) )
|
||||
break;
|
||||
py_cli->cli.sname = py_cli->cli_sname.c_str();
|
||||
|
||||
// Store 'lname'
|
||||
if ( !PyW_GetStringAttr(py_obj, "lname", &py_cli->cli_lname) )
|
||||
break;
|
||||
py_cli->cli.lname = py_cli->cli_lname.c_str();
|
||||
|
||||
// Store 'hint'
|
||||
if ( !PyW_GetStringAttr(py_obj, "hint", &py_cli->cli_hint) )
|
||||
break;
|
||||
py_cli->cli.hint = py_cli->cli_hint.c_str();
|
||||
|
||||
// Store callbacks
|
||||
if ( !PyObject_HasAttrString(py_obj, S_ON_EXECUTE_LINE) )
|
||||
break;
|
||||
py_cli->cli.execute_line = py_cli_cbs[cli_idx].execute_line;
|
||||
|
||||
py_cli->cli.complete_line = PyObject_HasAttrString(py_obj, S_ON_COMPLETE_LINE) ? py_cli_cbs[cli_idx].complete_line : NULL;
|
||||
py_cli->cli.keydown = PyObject_HasAttrString(py_obj, S_ON_KEYDOWN) ? py_cli_cbs[cli_idx].keydown : NULL;
|
||||
|
||||
// install CLI
|
||||
install_command_interpreter(&py_cli->cli);
|
||||
|
||||
// Take reference to this object
|
||||
py_cli->self = py_obj;
|
||||
Py_INCREF(py_obj);
|
||||
|
||||
// Save the instance
|
||||
py_clis[cli_idx] = py_cli;
|
||||
|
||||
return cli_idx;
|
||||
} while (false);
|
||||
|
||||
delete py_cli;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static void unbind(int cli_idx)
|
||||
{
|
||||
// Out of bounds or not set?
|
||||
if ( cli_idx < 0 || cli_idx >= MAX_PY_CLI || py_clis[cli_idx] == NULL )
|
||||
return;
|
||||
|
||||
py_cli_t *py_cli = py_clis[cli_idx];
|
||||
remove_command_interpreter(&py_cli->cli);
|
||||
|
||||
Py_DECREF(py_cli->self);
|
||||
delete py_cli;
|
||||
|
||||
py_clis[cli_idx] = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
py_cli_t *py_cli_t::py_clis[MAX_PY_CLI] = {NULL};
|
||||
#define DECL_PY_CLI_CB(CBN) { s_execute_line##CBN, s_complete_line##CBN, s_keydown##CBN }
|
||||
const py_cli_cbs_t py_cli_t::py_cli_cbs[MAX_PY_CLI] =
|
||||
{
|
||||
DECL_PY_CLI_CB(0), DECL_PY_CLI_CB(1), DECL_PY_CLI_CB(2), DECL_PY_CLI_CB(3),
|
||||
DECL_PY_CLI_CB(4), DECL_PY_CLI_CB(5), DECL_PY_CLI_CB(6), DECL_PY_CLI_CB(7),
|
||||
DECL_PY_CLI_CB(8), DECL_PY_CLI_CB(9), DECL_PY_CLI_CB(10), DECL_PY_CLI_CB(11)
|
||||
};
|
||||
#undef DECL_PY_CLI_CB
|
||||
//</code(py_cli)>
|
||||
|
||||
//<code(py_custviewer)>
|
||||
//---------------------------------------------------------------------------
|
||||
// Base class for all custviewer place_t providers
|
||||
@ -1619,6 +1879,18 @@ public:
|
||||
|
||||
#ifdef __NT__
|
||||
%inline %{
|
||||
//<inline(py_cli)>
|
||||
static int py_install_command_interpreter(PyObject *py_obj)
|
||||
{
|
||||
return py_cli_t::bind(py_obj);
|
||||
}
|
||||
|
||||
static void py_remove_command_interpreter(int cli_idx)
|
||||
{
|
||||
py_cli_t::unbind(cli_idx);
|
||||
}
|
||||
//</inline(py_cli)>
|
||||
|
||||
//<inline(py_custviewer)>
|
||||
//
|
||||
// Pywraps Simple Custom Viewer functions
|
||||
@ -2348,8 +2620,112 @@ class Choose2(object):
|
||||
#</pycode(py_kernwin)>
|
||||
%}
|
||||
|
||||
#ifdef __NT__
|
||||
%pythoncode %{
|
||||
#<pycode(py_cli)>
|
||||
class cli_t(pyidc_opaque_object_t):
|
||||
"""
|
||||
cli_t wrapper class.
|
||||
|
||||
This class allows you to implement your own command line interface handlers.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.__cli_idx = -1
|
||||
self.__clink__ = None
|
||||
|
||||
|
||||
def register(self, flags = 0, sname = None, lname = None, hint = None):
|
||||
"""
|
||||
Registers the CLI.
|
||||
|
||||
@param flags: Feature bits. No bits are defined yet, must be 0
|
||||
@param sname: Short name (displayed on the button)
|
||||
@param lname: Long name (displayed in the menu)
|
||||
@param hint: Hint for the input line
|
||||
|
||||
@return Boolean: True-Success, False-Failed
|
||||
"""
|
||||
|
||||
# Already registered?
|
||||
if self.__cli_idx >= 0:
|
||||
return True
|
||||
|
||||
if sname is not None: self.sname = sname
|
||||
if lname is not None: self.lname = lname
|
||||
if hint is not None: self.hint = hint
|
||||
|
||||
# Register
|
||||
self.__cli_idx = _idaapi.install_command_interpreter(self)
|
||||
return False if self.__cli_idx < 0 else True
|
||||
|
||||
|
||||
def unregister(self):
|
||||
"""
|
||||
Unregisters the CLI (if it was registered)
|
||||
"""
|
||||
if self.__cli_idx < 0:
|
||||
return False
|
||||
|
||||
_idaapi.remove_command_interpreter(self.__cli_idx)
|
||||
self.__cli_idx = -1
|
||||
return True
|
||||
|
||||
|
||||
def __del__(self):
|
||||
self.unregister()
|
||||
|
||||
#
|
||||
# Implement these methods in the subclass:
|
||||
#
|
||||
#<pydoc>
|
||||
# def OnExecuteLine(self, line):
|
||||
# """
|
||||
# The user pressed Enter. The CLI is free to execute the line immediately or ask for more lines.
|
||||
#
|
||||
# This callback is mandatory.
|
||||
#
|
||||
# @param line: typed line(s)
|
||||
# @return Boolean: True-executed line, False-ask for more lines
|
||||
# """
|
||||
# return True
|
||||
#
|
||||
# def OnKeydown(self, line, x, sellen, vkey, shift):
|
||||
# """
|
||||
# A keyboard key has been pressed
|
||||
# This is a generic callback and the CLI is free to do whatever it wants.
|
||||
#
|
||||
# This callback is optional.
|
||||
#
|
||||
# @param line: current input line
|
||||
# @param x: current x coordinate of the cursor
|
||||
# @param sellen: current selection length (usually 0)
|
||||
# @param vkey: virtual key code. if the key has been handled, it should be returned as zero
|
||||
# @param shift: shift state
|
||||
#
|
||||
# @return:
|
||||
# None - Nothing was changed
|
||||
# tuple(line, x, sellen, vkey): if either of the input line or the x coordinate or the selection length has been modified.
|
||||
# It is possible to return a tuple with None elements to preserve old values. Example: tuple(new_line, None, None, None) or tuple(new_line)
|
||||
# """
|
||||
# return None
|
||||
#
|
||||
# def OnCompleteLine(self, prefix, n, line, prefix_start):
|
||||
# """
|
||||
# The user pressed Tab. Find a completion number N for prefix PREFIX
|
||||
#
|
||||
# This callback is optional.
|
||||
#
|
||||
# @param prefix: Line prefix at x (string)
|
||||
# @param n: completion number (int)
|
||||
# @param line: the current line (string)
|
||||
# @param prefix_start: the index where PREFIX starts in LINE (int)
|
||||
#
|
||||
# @return: None if no completion could be generated otherwise a String with the completion suggestion
|
||||
# """
|
||||
# return None
|
||||
#</pydoc>
|
||||
|
||||
#</pycode(py_cli)>
|
||||
#<pycode(py_custviewer)>
|
||||
class simplecustviewer_t(object):
|
||||
"""The base class for implementing simple custom viewers"""
|
||||
@ -2586,4 +2962,3 @@ class simplecustviewer_t(object):
|
||||
#</pydoc>
|
||||
#</pycode(py_custviewer)>
|
||||
%}
|
||||
#endif
|
||||
|
23
swig/ua.i
23
swig/ua.i
@ -1347,5 +1347,28 @@ class processor_t(pyidc_opaque_object_t):
|
||||
"""This function returns cmd.auxpref value"""
|
||||
return self.cmd.auxpref
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
class __ph(object):
|
||||
id = property(lambda self: ph_get_id())
|
||||
cnbits = property(lambda self: ph_get_cnbits())
|
||||
dnbits = property(lambda self: ph_get_dnbits())
|
||||
flag = property(lambda self: ph_get_flag())
|
||||
high_fixup_bits = property(lambda self: ph_get_high_fixup_bits())
|
||||
icode_return = property(lambda self: ph_get_icode_return())
|
||||
instruc = property(lambda self: ph_get_instruc())
|
||||
instruc_end = property(lambda self: ph_get_instruc_end())
|
||||
instruc_start = property(lambda self: ph_get_instruc_start())
|
||||
regCodeSreg = property(lambda self: ph_get_regCodeSreg())
|
||||
regDataSreg = property(lambda self: ph_get_regDataSreg())
|
||||
regFirstSreg = property(lambda self: ph_get_regFirstSreg())
|
||||
regLastSreg = property(lambda self: ph_get_regLastSreg())
|
||||
regnames = property(lambda self: ph_get_regnames())
|
||||
segreg_size = property(lambda self: ph_get_segreg_size())
|
||||
tbyte_size = property(lambda self: ph_get_tbyte_size())
|
||||
version = property(lambda self: ph_get_version())
|
||||
|
||||
ph = __ph()
|
||||
|
||||
#</pycode(py_ua)>
|
||||
%}
|
||||
|
Loading…
x
Reference in New Issue
Block a user