idc.py: Merge from Ilfak. Implemented and fixed Eval(), SaveBase(), MakeData(), FirstSeg(), GetNextSeg(), SegCreate(), SetFChunkAttr(), SetLocalType(), GetFchunkReferer()

This commit is contained in:
gergely.erdelyi 2009-01-25 16:32:58 +00:00
parent 43af79132f
commit 04492e420c

View File

@ -36,6 +36,7 @@ import os
import re
import struct
import time
import types
class DeprecatedIDCError(Exception):
"""
@ -389,7 +390,7 @@ def Wait():
return idaapi.autoWait()
def CompileEx(filename):
def CompileEx(input, isfile):
"""
Compile an IDC script
@ -399,24 +400,56 @@ def CompileEx(filename):
@param input: if isfile != 0, then this is the name of file to compile
otherwise it holds the text to compile
@param isfile: specify if 'input' holds a filename or the expression itself
@return: 0 - ok, otherwise it returns an error message
FIXME: This needs to be updated to latest doc
"""
res = idaapi.Compile(filename)
if isfile:
res = idaapi.Compile(input)
else:
res = idaapi.CompileLine(input)
if res:
return res
else:
return 0
def Eval(expr):
"""
FIXME: this
// Macro to check for evaluation failures:
#define EVAL_FAILURE(code) (IsString(code) && substr(code, 0, 13) == "IDC_FAILURE: ")
#ifdef _notdefinedsymbol
Evaluate an IDC expression
@param expr: an expression
@return: the expression value. If there are problems, the returned value will be "IDC_FAILURE: xxx"
where xxx is the error description
@note: Python implementation evaluates IDC only, while IDC can call other registered languages
"""
rv = idaapi.idc_value_t()
err = idaapi.calc_idc_expr(BADADDR, expr, rv)
if err:
return "IDC_FAILURE: "+err
else:
if rv.vtype == '\x01': # string
return rv.str
elif rv.vtype == '\x02': # long
return rv.num
else:
raise NotImplementedError, "Eval() supports only expressions returning strings or longs"
def EVAL_FAILURE(code):
"""
Check the result of Eval() for evaluation failures
@param code: result of Eval()
@return: True if there was an evaluation error
"""
return type(code) == types.StringType and code.startswith("IDC_FAILURE: ")
def SaveBase(idbname, flags=0):
"""
@ -425,12 +458,17 @@ def SaveBase(idbname, flags=0):
@param idbname: name of the idb file. if empty, the current idb
file will be used.
@param flags: DBFL_BAK or 0
FIXME: backup might not work at all
"""
if flags == DBFL_BAK:
if len(idbname)==0:
idbname = idaapi.cvar.database_idb
saveflags = idaapi.cvar.database_flags
if flags & DBFL_BAK:
idaapi.cvar.database_flags |= DBFL_BAK
return idaapi.save_database(idbname, 0)
else:
idaapi.cvar.database_flags &= ~DBFL_BAK
res = idaapi.save_database(idbname, 0)
idaapi.cvar.database_flags = saveflags
return res
DBFL_BAK = 0x04 # create backup file
@ -671,7 +709,7 @@ def MakeData(ea, flags, size, tid):
@return: 1-ok, 0-failure
"""
raise NotImplementedError, "Use the Make* functions to create data items"
return idaapi.do_data_ex(ea, flags, size, tid)
def MakeByte(ea):
@ -786,9 +824,6 @@ def MakeStructEx(ea, size, strname):
"""
strid = idaapi.get_struc_id(strname)
if strid == idaapi.BADNODE:
return False
if size == -1:
size = idaapi.get_struc_size(strid)
@ -916,8 +951,10 @@ def SetArrayFormat(ea, flags, litems, align):
other values: element width
@return: 1-ok, 0-failure
FIXME: This idaapi function is not exported yet
"""
raise NotImplementedError
return idaapi.set_array_params(ea, flags, litems, align)
AP_ALLOWDUPS = 0x00000001L # use 'dup' construct
AP_SIGNED = 0x00000002L # treats numbers as signed
@ -2308,8 +2345,10 @@ def ChangeConfig(directive):
@note: If the directives are erroneous, a fatal error will be generated.
The changes will be effective only for the current session.
FIXME: This idaapi function is not exported yet
"""
raise NotImplementedError, "not implemented yet"
return idaapi.process_config_line(directive)
# The following functions allow you to set/get common parameters.
@ -2608,7 +2647,6 @@ INF_SPECSEGS : 'specsegs',
INF_VOIDS : 's_void', # char; Display void marks?
INF_SHOWAUTO : 's_showauto', # char; Display autoanalysis indicator?
INF_AUTO : 's_auto', # char; Autoanalysis is enabled?
# FIXME: This might be incorrect
INF_BORDER : 's_limiter', # char; Generate borders?
INF_NULL : 's_null', # char; Generate empty lines?
INF_GENFLAGS : 's_genflags', # char; General flags:
@ -2931,13 +2969,7 @@ def FirstSeg():
@return: address of the start of the first segment
BADADDR - no segments are defined
"""
segn = idaapi.get_segm_qty()
if segn == 0:
return BADADDR
else:
seg = idaapi.getnseg(0)
seg = idaapi.get_first_seg()
if not seg:
return BADADDR
else:
@ -2952,15 +2984,8 @@ def NextSeg(ea):
@return: start of the next segment
BADADDR - no next segment
TODO: Any better way of doing this?
"""
for n in range(idaapi.get_segm_qty()):
currseg = idaapi.getnseg(n)
if ea >= currseg.startEA and ea < currseg.endEA:
nextseg = idaapi.getnseg(n+1)
nextseg = idaapi.get_next_seg(ea)
if not nextseg:
return BADADDR
else:
@ -3042,21 +3067,14 @@ def SegCreate(startea, endea, base, use32, align, comb):
@return: 0-failed, 1-ok
"""
success = idaapi.add_segm(base, startea, endea, "Segment", "CODE")
if success != 1:
return 0
seg = idaapi.getseg(startea)
if not seg:
return 0
seg.bitness = use32
seg.align = align
seg.comb = comb
return 1
s = idaapi.segment_t()
s.startEA = startea
s.endEA = endea
s.sel = idaapi.setup_selector(base)
s.bitness = use32
s.align = align
s.comb = comb
return idaapi.add_segm_ex(s, "", "", idaapi.ADDSEG_NOSREG)
def SegDelete(ea, flags):
@ -3717,7 +3735,7 @@ FUNCATTR_ARGSIZE = 20 # number of bytes purged from the stack
FUNCATTR_FPD = 24 # frame pointer delta
FUNCATTR_COLOR = 28 # function color code
FUNCATTR_OWNER = 10 # chunk owner (valid only for tail chunks)
FUNCATTR_REFQTY = 14 # number of chunk parents (valid only for ta
FUNCATTR_REFQTY = 14 # number of chunk parents (valid only for tail chunks)
_FUNCATTRMAP = {
FUNCATTR_START : 'startEA',
@ -3730,7 +3748,7 @@ _FUNCATTRMAP = {
FUNCATTR_FPD : 'fpd',
FUNCATTR_COLOR : 'color',
FUNCATTR_OWNER : 'owner',
FUNCATTR_REFQTY : 'refwty'
FUNCATTR_REFQTY : 'refqty'
}
@ -4865,25 +4883,26 @@ def SetStrucComment(sid, comment, repeatable):
return idaapi.set_struc_cmt(sid, comment, repeatable)
def _IDC_PrepareStrucMemberTypeinfo(flag, typeid):
def _IDC_PrepareStrucMemberTypeinfo(flag, typeid, target=None, tdelta=None, reftype=None):
""" Internal function to prepare typeinfo_t for adding/setting structure members """
simple_types = [ FF_BYTE, FF_WORD, FF_DWRD, FF_QWRD, FF_OWRD, FF_TBYT, FF_FLOAT, FF_DOUBLE, FF_PACKREAL ]
if idaapi.isASCII(flag):
ti = idaapi.typeinfo_t()
ti.strtype = typeid
elif idaapi.isStruct(flag):
ti = idaapi.typeinfo_t()
ti.tid = typeid
elif idaapi.isOff0(flag):
if idaapi.isOff0(flag):
ti = idaapi.typeinfo_t()
ri = idaapi.refinfo_t()
ri.target = BADADDR
ri.base = typeid
if target != None:
ri.target = target
ri.tdelta = 0
ri.flags = reftype
else:
ri.target = BADADDR
ri.tdelta = 0
if (flag & FF_WORD):
ri.flags = REF_OFF16
elif (flag & FF_BYTE):
ri.flags = REF_OFF8
elif (flag & FF_QWRD):
ri.flags = REF_OFF64
else:
ri.flags = REF_OFF32
ti.ri = ri
@ -4891,19 +4910,17 @@ def _IDC_PrepareStrucMemberTypeinfo(flag, typeid):
ti = idaapi.typeinfo_t()
ec = idaapi.enum_const_t()
ec.tid = typeid
ec.serial = 0
ti.ec = ec
elif idaapi.isStroff0(flag):
ti = idaapi.typeinfo_t()
ti.path.len = 2
ti.path.len = 1
target_struct = idaapi.get_struc(typeid)
assert target_struct, "Target structure is invalid"
target_member = idaapi.get_member(target_struct, 0)
assert target_member, "Target member is not found"
ti.path.ids = [ typeid, target_member.id ]
elif ((flag & 0xFFFFFF) & idaapi.DT_TYPE) in simple_types:
ti = None
ti.path.ids = [ typeid ]
else:
assert False, "Unknown type flag 0x%08x" % flag
ti = idaapi.typeinfo_t()
ti.tid = typeid
return ti
@ -4935,11 +4952,10 @@ def AddStrucMember(sid, name, offset, flag, typeid, nbytes, target=None, tdelta=
@return: 0 - ok, otherwise error code (one of STRUC_ERROR_*)
FIXME: This needs fixing
"""
struc = idaapi.get_struc(sid)
assert struct, "get_struc() failed"
ti = _IDC_PrepareStrucMemberTypeinfo(flag, typeid)
ti = _IDC_PrepareStrucMemberTypeinfo(flag, typeid, target, tdelta, reftype)
return idaapi.add_struc_member(struc, name, offset, flag, ti, nbytes)
@ -5014,13 +5030,10 @@ def SetMemberType(sid, member_offset, flag, typeid, nitems, target=None, tdelta=
to specify a complex offset expression
@return: !=0 - ok.
FIXME: Fix this too
"""
struc = idaapi.get_struc(sid)
assert struct, "get_struc() failed"
ti = _IDC_PrepareStrucMemberTypeinfo(flag, typeid)
return idaapi.set_member_type(struc, member_offset, flag, ti, nitems)
ti = _IDC_PrepareStrucMemberTypeinfo(flag, typeid, target, tdelta, reftype)
elsize = idaapi.get_data_elsize(BADADDR, flag, ti);
return idaapi.set_member_type(idaapi.get_struc(sid), member_offset, flag, ti, elsize*nitems)
def SetMemberComment(sid, member_offset, comment, repeatable):
@ -5051,11 +5064,11 @@ def GetFchunkAttr(ea, attr):
Get a function chunk attribute
@param ea: any address in the chunk
@param attr: one of: FUNCATTR_START, FUNCATTR_END, FUNCATTR_COLOR, FUNCATTR_OWNER, FUNCATTR_REFQTY
@param attr: one of: FUNCATTR_START, FUNCATTR_END, FUNCATTR_OWNER, FUNCATTR_REFQTY
@return: desired attribute or -1
"""
if attr in [ FUNCATTR_START, FUNCATTR_END, FUNCATTR_COLOR ]:
if attr in [ FUNCATTR_START, FUNCATTR_END, FUNCATTR_OWNER, FUNCATTR_REFQTY ]:
return GetFunctionAttr(ea, attr)
else:
return -1
@ -5066,17 +5079,15 @@ def SetFchunkAttr(ea, attr, value):
Set a function chunk attribute
@param ea: any address in the chunk
@param attr: only FUNCATTR_COLOR
@param attr: only FUNCATTR_START, FUNCATTR_END, FUNCATTR_OWNER
@param value: desired bg color (RGB)
@return: 0 if failed, 1 if success
FIXME: Check if this works
"""
if attr in [ FUNCATTR_COLOR ]:
return SetFunctionAttr(ea, attr, value)
if attr in [ FUNCATTR_START, FUNCATTR_END, FUNCATTR_OWNER ]:
return SetFunctionAttr(ea, attr)
else:
return 0
return -1
def GetFchunkReferer(ea, idx):
@ -5088,7 +5099,14 @@ def GetFchunkReferer(ea, idx):
@return: referer address or BADADDR
"""
raise NotImplmentedError
pfn = idaapi.get_fchunk(ea)
if pfn:
dummy = idaapi.func_parent_iterator_t(pfn); # read referer info
if idx >= pfn.refqty or len(pfn.referers) == 0:
return BADADDR
# FIXME: swig didn't make referers into an array
return pfn.referers[idx]
return BADADDR
def NextFchunk(ea):
@ -6069,6 +6087,10 @@ def SetLocalType(ordinal, input, flags):
@return: slot number or 0 if error
"""
if input:
idaapi.del_numbered_type(idaapi.cvar.idati, ordinal)
else:
# FIXME: Emptying the slot is not implemented yet
raise NotImplementedError
@ -6522,7 +6544,7 @@ def RefreshDebuggerMemory():
information, memory contents, or names of a non-suspended process.
This is an expensive call.
"""
raise NotImplementedError
return idaapi.refresh_debugger_memory()
def TakeMemorySnapshot(only_loader_segs):
@ -6532,7 +6554,7 @@ def TakeMemorySnapshot(only_loader_segs):
@param only_loader_segs: 0-copy all segments to idb
1-copy only SFL_LOADER segments
"""
raise NotImplementedError
return idaapi.take_memory_snapshot(only_loader_segs)
def GetProcessState():
@ -6635,7 +6657,7 @@ def GetExceptionQty():
"""
Get number of defined exception codes
"""
raise NotImplementedError
return iddapi.get_exception_qty()
def GetExceptionCode(idx):
@ -6646,7 +6668,7 @@ def GetExceptionCode(idx):
@return: exception code (0 - error)
"""
raise NotImplementedError
return idaapi.get_exception_code(idx)
def GetExceptionName(code):
@ -6657,7 +6679,7 @@ def GetExceptionName(code):
@return: "" on error
"""
raise NotImplementedError
return idaapi.get_exception_name(code)
def GetExceptionFlags(code):
@ -6668,8 +6690,7 @@ def GetExceptionFlags(code):
@return: -1 on error
"""
raise NotImplementedError
return idaapi.get_exception_flags(code)
def DefineException(code, name, desc, flags):
"""
@ -6695,7 +6716,7 @@ def SetExceptionFlags(code, flags):
@param code: exception code
@param flags: exception flags (combination of EXC_...)
"""
raise NotImplementedError
return idaapi.set_exception_flags(code, flags)
def ForgetException(code):
@ -6704,7 +6725,7 @@ def ForgetException(code):
@param code: exception code
"""
raise NotImplementedError
return idaapi.forget_exception(code)
def GetRegValue(name):
@ -6739,7 +6760,7 @@ def SetRegValue(value, name):
"""
rv = idaapi.regval_t()
rv.ival = value
return idaapi.set_reg_val(name, value)
return idaapi.set_reg_val(name, rv)
def GetBptQty():
@ -6913,7 +6934,7 @@ def CheckBpt(ea):
@return: one of BPTCK_... constants
"""
raise NotImplementedError
return idaapi.check_bpt(ea)
BPTCK_NONE = -1 # breakpoint does not exist
BPTCK_NO = 0 # breakpoint is disabled
@ -7076,7 +7097,7 @@ def ArmForceBLJump(ea):
@return: 1-ok, 0-failed
"""
raise NotImplementedError
return Eval("ArmForceBLJump(0x%x)"%ea)
def ArmForceBLCall(ea):
@ -7087,7 +7108,7 @@ def ArmForceBLCall(ea):
@return: 1-ok, 0-failed
"""
raise NotImplementedError
return Eval("ArmForceBLCall(0x%x)"%ea)
#--------------------------------------------------------------------------