1809 lines
64 KiB
Python
1809 lines
64 KiB
Python
#---------------------------------------------------------------------
|
|
# xmlldr.py - IDA XML Import loader and plugin
|
|
#---------------------------------------------------------------------
|
|
"""
|
|
Loader and plugin for IDA to import a XML PROGRAM file to a database.
|
|
"""
|
|
|
|
import idaapi
|
|
import sys
|
|
import time
|
|
from xml.etree import cElementTree
|
|
|
|
|
|
XML_IMPORTER_VERSION = "2.1.1"
|
|
BASELINE_IDA_VERSION = 620
|
|
IDA_SDK_VERSION = idaapi.IDA_SDK_VERSION
|
|
BADADDR = idaapi.BADADDR
|
|
|
|
|
|
"""
|
|
Loader functions
|
|
"""
|
|
def accept_file(li, n):
|
|
"""
|
|
Check if the file is of supported format
|
|
|
|
@param li: a file-like object which can be used to access the input data
|
|
@param n : format number. The function will be called with incrementing
|
|
number until it returns zero
|
|
@return: 0 - no more supported formats
|
|
string "name" - format name to display in the chooser dialog
|
|
dictionary { 'format': "name", 'options': integer }
|
|
options: should be 1, possibly ORed with ACCEPT_FIRST (0x8000)
|
|
to indicate preferred format
|
|
"""
|
|
if IDA_SDK_VERSION < BASELINE_IDA_VERSION:
|
|
return 0
|
|
# we support only one format per file
|
|
if n > 0: return 0
|
|
# read 16K bytes to allow for the DTD
|
|
data = li.read(0x4000)
|
|
# look for start of <PROGRAM> element
|
|
start = data.find("<PROGRAM")
|
|
if start >= 0: return "XML PROGRAM file"
|
|
return 0
|
|
|
|
|
|
def load_file(li, neflags, format):
|
|
"""
|
|
Load the file into database
|
|
|
|
@param li: a file-like object which can be used to access the input data
|
|
@param neflags: options selected by the user, see loader.hpp
|
|
@return: 0-failure, 1-ok
|
|
"""
|
|
global event, element
|
|
plugin = False
|
|
status = 0
|
|
st = idaapi.setStat(idaapi.st_Work)
|
|
xml = XmlImporter(False, 0)
|
|
try:
|
|
status = xml.import_xml()
|
|
except Cancelled:
|
|
msg = "XML PROGRAM import cancelled!"
|
|
print "\n" + msg
|
|
idaapi.warning(msg)
|
|
except MultipleAddressSpacesNotSupported:
|
|
msg = "XML Import cancelled!"
|
|
msg += "\n\nXML Import does not currently support"
|
|
msg += "\nimporting multiple address spaces."
|
|
print "\n" + msg
|
|
idaapi.warning(msg)
|
|
except:
|
|
print "\nHouston, we have a problem!"
|
|
msg = "***** Exception occurred: XML loader failed! *****"
|
|
print "\n" + msg + "\n", sys.exc_type, sys.exc_value
|
|
print event, element.tag, element.attrib
|
|
idaapi.warning(msg)
|
|
finally:
|
|
idaapi.setStat(st)
|
|
xml.cleanup()
|
|
return status
|
|
|
|
|
|
class XmlImporterPlugin(idaapi.plugin_t):
|
|
"""
|
|
XML Importer plugin class
|
|
"""
|
|
flags = 0
|
|
comment = "Import XML PROGRAM file"
|
|
help = "Import XML <PROGRAM> document to database"
|
|
wanted_name = "XML Importer"
|
|
wanted_hotkey = "Ctrl-Alt-l"
|
|
|
|
def init(self):
|
|
"""
|
|
init function for XML Importer plugin.
|
|
|
|
Returns:
|
|
Constant PLUGIN_OK if this IDA version supports the plugin,
|
|
else returns PLUGIN_SKIP if this IDA is older than the supported
|
|
baseline version.
|
|
"""
|
|
if IDA_SDK_VERSION < BASELINE_IDA_VERSION:
|
|
idaapi.msg('\nXML Importer plugin (xmlldr.py) not supported ' +
|
|
'by this version of IDA\n')
|
|
return idaapi.PLUGIN_SKIP
|
|
return idaapi.PLUGIN_OK
|
|
|
|
def run(self, arg):
|
|
"""
|
|
run function for XML Importer plugin.
|
|
|
|
Args:
|
|
arg: Integer, a non-zero value enables auto-run feature for
|
|
IDA batch (no gui) processing mode. Default is 0.
|
|
"""
|
|
st = idaapi.setStat(idaapi.st_Work)
|
|
xml = XmlImporter(True, arg)
|
|
try:
|
|
try:
|
|
xml.import_xml()
|
|
except Cancelled:
|
|
msg = "XML Import cancelled!"
|
|
print "\n" + msg
|
|
idaapi.warning(msg)
|
|
except MultipleAddressSpacesNotSupported:
|
|
msg = "XML Import cancelled!"
|
|
msg += "\n\nXML Import does not currently support"
|
|
msg += "\nimporting multiple address spaces."
|
|
print "\n" + msg
|
|
idaapi.warning(msg)
|
|
except:
|
|
msg = "***** Exception occurred: XML Importer failed! *****"
|
|
print "\n" + msg + "\n", sys.exc_type, sys.exc_value
|
|
idaapi.warning(msg)
|
|
finally:
|
|
xml.cleanup()
|
|
idaapi.setStat(st)
|
|
|
|
|
|
def term(self):
|
|
pass
|
|
|
|
|
|
def PLUGIN_ENTRY():
|
|
return XmlImporterPlugin()
|
|
|
|
|
|
class Cancelled(Exception):
|
|
pass
|
|
|
|
|
|
class FileError(Exception):
|
|
pass
|
|
|
|
|
|
class MultipleAddressSpacesNotSupported(Exception):
|
|
pass
|
|
|
|
|
|
class XmlImporter:
|
|
"""
|
|
XmlImporter class contains methods to import an XML PROGRAM
|
|
document into IDA.
|
|
"""
|
|
def __init__(self, plugin, arg):
|
|
"""
|
|
Initializes the XmlImporter attributes
|
|
|
|
Args:
|
|
arg: Integer, non-zero value enables auto-run feature for
|
|
IDA batch (no gui) processing mode. Default is 0.
|
|
"""
|
|
self.plugin = plugin
|
|
self.autorun = False
|
|
self.debug = False # set this to True for debug prints
|
|
self.Elements = {}
|
|
self.Counters = []
|
|
self.Tags = []
|
|
self.Timers = dict()
|
|
self.xmlfile = 0
|
|
self.addr_mode = 1
|
|
self.create = True
|
|
self.dataseg = None
|
|
self.deferred = []
|
|
self.callbacks = {
|
|
'start' : {
|
|
BOOKMARKS : self.update_import,
|
|
CODE : self.update_import,
|
|
COMMENTS : self.update_import,
|
|
COMPILER : self.import_compiler,
|
|
DATA : self.update_import,
|
|
DATATYPES : self.update_import,
|
|
EQUATES : self.update_import,
|
|
FUNCTIONS : self.update_import,
|
|
INFO_SOURCE : self.import_info_source,
|
|
MARKUP : self.update_import,
|
|
MEMORY_MAP : self.import_memory_map,
|
|
PROCESSOR : self.import_processor,
|
|
PROGRAM : self.import_program,
|
|
PROGRAM_ENTRY_POINTS: self.update_import,
|
|
REGISTER_VALUES : self.update_import,
|
|
SYMBOL_TABLE : self.update_import },
|
|
'end' : {
|
|
BOOKMARK : self.import_bookmark,
|
|
CODE_BLOCK : self.import_codeblock,
|
|
COMMENT : self.import_comment,
|
|
DEFINED_DATA : self.import_defined_data,
|
|
ENUM : self.import_enum,
|
|
EQUATE_GROUP : self.import_equate_group,
|
|
EQUATE_REFERENCE : self.import_equate_reference,
|
|
FUNCTION : self.import_function,
|
|
FUNCTION_DEF : self.import_function_def,
|
|
MANUAL_INSTRUCTION : self.import_manual_instruction,
|
|
MANUAL_OPERAND : self.import_manual_operand,
|
|
MEMORY_REFERENCE : self.import_memory_reference,
|
|
MEMORY_SECTION : self.import_memory_section,
|
|
PROGRAM_ENTRY_POINT : self.import_program_entry_point,
|
|
REGISTER_VALUE_RANGE: self.import_register_value_range,
|
|
STACK_REFERENCE : self.import_stack_reference,
|
|
STRUCTURE : self.import_structure,
|
|
SYMBOL : self.import_symbol,
|
|
TYPE_DEF : self.import_typedef,
|
|
UNION : self.import_union,
|
|
# end element for elapse time
|
|
BOOKMARKS : self.display_timer,
|
|
CODE : self.display_timer,
|
|
COMMENTS : self.display_timer,
|
|
DATA : self.display_timer,
|
|
DATATYPES : self.process_deferred,
|
|
EQUATES : self.display_timer,
|
|
FUNCTIONS : self.display_timer,
|
|
MARKUP : self.display_timer,
|
|
MEMORY_MAP : self.display_timer,
|
|
PROGRAM : self.display_total_time,
|
|
PROGRAM_ENTRY_POINTS: self.display_timer,
|
|
REGISTER_VALUES : self.display_timer,
|
|
SYMBOL_TABLE : self.display_timer }
|
|
}
|
|
|
|
|
|
def import_xml(self):
|
|
"""
|
|
Imports the XML PROGRAM file into the database.
|
|
"""
|
|
self.display_xml_importer_version()
|
|
displayMenu = self.plugin == True and self.autorun == False
|
|
#displayMenu = self.autorun == False
|
|
self.get_options(displayMenu)
|
|
if self.plugin:
|
|
self.filename=idaapi.askfile_c(0, "*.xml",
|
|
"Enter name of xml file:")
|
|
else:
|
|
self.filename = idaapi.get_input_file_path()
|
|
if (len(self.filename) == 0):
|
|
return
|
|
idaapi.msg('\nImporting from: ' + self.filename + '\n')
|
|
idc.Wait()
|
|
if self.plugin == False: idaapi.hide_wait_box()
|
|
idaapi.show_wait_box("Importing XML PROGRAM document....")
|
|
n = 0
|
|
for event,element in cElementTree.iterparse(self.filename,
|
|
events=("start","end")):
|
|
if idaapi.wasBreak() == True:
|
|
raise Cancelled
|
|
|
|
if self.debug == True and event == 'start':
|
|
print element.tag, element.attrib, element.text
|
|
|
|
if event in self.callbacks:
|
|
if element.tag in self.callbacks[event]:
|
|
if event == 'start':
|
|
self.Timers[element.tag] = time.clock()
|
|
self.callbacks[event][element.tag](element)
|
|
if event == 'end':
|
|
element.clear()
|
|
if event == 'end':
|
|
n += 1
|
|
end = time.clock()
|
|
idaapi.hide_wait_box()
|
|
self.display_summary()
|
|
idaapi.msg('\nXML Elements parsed: ' + str(n) + '\n\n')
|
|
return 1
|
|
|
|
|
|
def get_options(self, display):
|
|
"""
|
|
Displays the options menu and retrieves the option settings.
|
|
"""
|
|
fmt = "HELP\n"
|
|
fmt += "XML PROGRAM loader/importer plugin (Python)\n"
|
|
fmt += "IDA SDK: "+ str(IDA_SDK_VERSION) + "\n\n"
|
|
fmt += "The XML PROGRAM loader loads elements from a "
|
|
fmt += "XML <PROGRAM> document to create an idb database.\n\n"
|
|
fmt += "ENDHELP\n"
|
|
fmt += "Import from XML PROGRAM document...."
|
|
fmt += "\n <##Options##Code Blocks:{CodeBlocks}>"
|
|
fmt += "\n <Entry Points:{EntryPoints}>"
|
|
fmt += "\n <Segment Register Value Ranges:{RegisterValues}>"
|
|
fmt += "\n <Data Types:{DataTypes}>"
|
|
fmt += "\n <Data Definitions:{DataDefinitions}>"
|
|
fmt += "\n <Symbols:{Symbols}>"
|
|
fmt += "\n <Comments:{Comments}>"
|
|
fmt += "\n <Bookmarks:{Bookmarks}>"
|
|
fmt += "\n <Functions:{Functions}>"
|
|
fmt += "\n <Memory References:{MemoryReferences}>"
|
|
fmt += "\n <Equate/Enum References:{EquateReferences}>"
|
|
fmt += "\n <Manual Instructions/Operands:{Manual}>{cGroup1}>"
|
|
fmt += "\n\n"
|
|
|
|
Opts = { 'cGroup1': idaapi.Form.ChkGroupControl(
|
|
(
|
|
"CodeBlocks", "EntryPoints", "RegisterValues",
|
|
"DataTypes", "DataDefinitions",
|
|
"Symbols", "Comments", "Bookmarks",
|
|
"Functions", "MemoryReferences", "EquateReferences",
|
|
"Manual")) }
|
|
|
|
self.Options = idaapi.Form(fmt, Opts)
|
|
self.Options.Compile()
|
|
|
|
self.Options.CodeBlocks.checked = True
|
|
self.Options.EntryPoints.checked = True
|
|
self.Options.RegisterValues.checked = True
|
|
self.Options.DataTypes.checked = True
|
|
self.Options.DataDefinitions.checked = True
|
|
self.Options.Symbols.checked = True
|
|
self.Options.Functions.checked = True
|
|
self.Options.Comments.checked = True
|
|
self.Options.Bookmarks.checked = True
|
|
self.Options.MemoryReferences.checked = True
|
|
self.Options.EquateReferences.checked = True
|
|
self.Options.Manual.checked = True
|
|
|
|
if display == True:
|
|
ok = self.Options.Execute()
|
|
if (ok == 0):
|
|
raise Cancelled
|
|
|
|
def cleanup(self):
|
|
"""
|
|
Frees memory and closes message box at termination.
|
|
"""
|
|
if self.plugin:
|
|
self.Options.Free()
|
|
idaapi.hide_wait_box()
|
|
|
|
|
|
def display_timer(self, element):
|
|
"""
|
|
Displays the elapsed processing time for XML elements.
|
|
|
|
Args:
|
|
element: XML element object value containing the element tag.
|
|
"""
|
|
if element.tag == MEMORY_MAP and self.plugin:
|
|
return
|
|
if element.tag in self.Timers:
|
|
idaapi.msg('elapsed time: %.4f' %
|
|
(time.clock()-self.Timers[element.tag]))
|
|
|
|
|
|
def display_total_time(self, element):
|
|
"""
|
|
Displays the total processing time.
|
|
|
|
Args:
|
|
element: XML element object value (not used).
|
|
"""
|
|
TOTAL = 'Total '
|
|
idaapi.msg('\n%35selapsed time: %.4f' %
|
|
(TOTAL,time.clock()-self.Timers[PROGRAM]))
|
|
|
|
|
|
def display_summary(self):
|
|
"""
|
|
Displays summary of the XML PROGRAM import in IDA output window.
|
|
"""
|
|
summary = ''
|
|
total = 0
|
|
for tag in self.Tags:
|
|
count = self.Counters[self.Elements[tag]]
|
|
summary += "\n%s: %d" % (tag, count)
|
|
total += count
|
|
summary += '\n--------------------------------------'
|
|
header = '\n--------------------------------------'
|
|
header += ('\nTotal XML Elements Processed: %d') % total
|
|
summary = header + summary
|
|
idaapi.msg(summary)
|
|
if self.plugin and self.autorun == False:
|
|
frmt = "TITLE XML Import Successful!\n"
|
|
frmt += "ICON INFO\n"
|
|
frmt += "AUTOHIDE NONE\n"
|
|
frmt += "HIDECANCEL\n"
|
|
firstline = "\n XML IMPORT SUCCESSFUL!"
|
|
fileline = '\n\nFile: %s' % self.filename
|
|
details = '\n\nSee output window for details...'
|
|
idaapi.info("%s" % (frmt + firstline + fileline + details))
|
|
|
|
|
|
def display_xml_importer_version(self):
|
|
"""
|
|
Displays XML Importer plugin version info in IDA output window.
|
|
"""
|
|
if self.plugin:
|
|
f = idaapi.idadir(idaapi.PLG_SUBDIR) + '/xmlldr.py'
|
|
else:
|
|
f = idaapi.idadir(idaapi.LDR_SUBDIR) + '/xmlldr.py'
|
|
plugintime = time.localtime(os.path.getmtime(f))
|
|
ts = time.strftime('%b %d %Y %H:%M:%S', plugintime)
|
|
version = "\nXML Importer Version " + XML_IMPORTER_VERSION
|
|
version += " : SDK " + str(IDA_SDK_VERSION)
|
|
version += " : Python : "+ ts + '\n'
|
|
idaapi.msg(version)
|
|
|
|
|
|
def get_address(self, element, attr):
|
|
"""
|
|
Returns the address value for an element.
|
|
|
|
Args:
|
|
element: XML element object.
|
|
attr: String containing the address attribute name.
|
|
|
|
Returns:
|
|
Numeric value representing the address.
|
|
"""
|
|
addrstr = element.get(attr)
|
|
if '::' in addrstr:
|
|
# overlayed addresses not currently handled
|
|
return BADADDR
|
|
elif ':' in addrstr:
|
|
[segstr, offset_str] = string.split(addrstr,':')
|
|
offset = int(offset_str,16)
|
|
if self.is_int(segstr) == True:
|
|
sgmt = int(segstr,16)
|
|
addr = (sgmt << 4) + offset
|
|
else:
|
|
# multiple address spaces not currently implemented
|
|
addr = BADADDR
|
|
return addr
|
|
else:
|
|
return int(element.get(attr), 16)
|
|
|
|
|
|
def get_attribute(self, element, attr):
|
|
"""
|
|
Returns the attribute value string.
|
|
|
|
Args:
|
|
element: XML element object.
|
|
attr: String containing the attribute name.
|
|
|
|
Returns:
|
|
String representing the attribute value.
|
|
"""
|
|
return element.get(attr)
|
|
|
|
|
|
def get_attribute_value(self, element, attr):
|
|
"""
|
|
Returns the numeric attribute value.
|
|
|
|
Args:
|
|
element: XML element object.
|
|
attr: String containing the attribute name.
|
|
|
|
Returns:
|
|
Numeric value representing the attribute value.
|
|
"""
|
|
val = element.get(attr)
|
|
try:
|
|
if val.upper().startswith('0X') or val.upper().startswith('-0X'):
|
|
return int(val, 16)
|
|
return int(val)
|
|
except:
|
|
idaapi.msg('\nUnable to decode string as value: ' + val)
|
|
return 0
|
|
|
|
|
|
def get_cbsize(self):
|
|
"""
|
|
Returns the size of the addressable codebyte for the processor.
|
|
|
|
Returns:
|
|
Integer representing the number of 8-bit bytes in an
|
|
addressable codebyte.
|
|
"""
|
|
return (idaapi.ph_get_cnbits()+7)/8
|
|
|
|
|
|
def get_datatype_flags(self, datatype, size):
|
|
"""
|
|
Returns the flags bitmask for the datatype.
|
|
|
|
Args:
|
|
datatype: String representing the datatype.
|
|
size: Integer representing the datatype size.
|
|
|
|
Returns:
|
|
Integer representing the bitmask.
|
|
"""
|
|
if datatype.lower().startswith("byte"): return idaapi.byteflag()
|
|
if datatype.lower().startswith("word"): return idaapi.wordflag()
|
|
if datatype.lower().startswith("dword"): return idaapi.dwrdflag()
|
|
if datatype.lower().startswith("qword"): return idaapi.qwrdflag()
|
|
if datatype.lower().startswith("oword"): return idaapi.owrdflag()
|
|
if datatype.lower().startswith("tbyte"): return idaapi.tbytflag()
|
|
if datatype.lower().startswith("float"): return idaapi.floatflag()
|
|
if datatype.lower().startswith("double"): return idaapi.doubleflag()
|
|
if datatype.lower().startswith("packed"): return idaapi.packrealflag()
|
|
if self.is_string_type(datatype): return idaapi.asciflag()
|
|
if self.is_enumeration(datatype): return idaapi.enumflag()
|
|
if self.is_structure(datatype): return idaapi.struflag()
|
|
#if size == 4: return idaapi.dwrdflag()
|
|
return 0
|
|
|
|
|
|
def get_string_type(self, datatype):
|
|
if datatype.lower() == 'mbcstring':
|
|
return idaapi.ASCSTR_UNICODE
|
|
if datatype.lower().find('unicode') != -1:
|
|
if datatype.lower().find('pascal') != -1:
|
|
return idaapi.ASCSTR_ULEN2
|
|
return idaapi.ASCSTR_UNICODE
|
|
if datatype.lower().find('pascal') != -1:
|
|
return idaapi.ASCSTR_LEN2
|
|
return idaapi.ASCSTR_TERMCHR
|
|
|
|
|
|
def has_attribute(self, element, attr):
|
|
"""
|
|
Returns true if the XML element contains the named attribute.
|
|
|
|
Args:
|
|
element: XML element object
|
|
attr: String containing name of the attribute
|
|
|
|
Returns:
|
|
True if the element contains the named attribute, otherwise False.
|
|
"""
|
|
return attr in element.attrib
|
|
|
|
|
|
def is_enumeration(self, datatype):
|
|
"""
|
|
Returns true if datatype is an existing enumeration in the database.
|
|
|
|
Args:
|
|
datatype: String representing the datatype.
|
|
|
|
Returns:
|
|
True if the datatype is an enumeration in the database,
|
|
otherwise False.
|
|
"""
|
|
if idaapi.get_enum(datatype) == idaapi.BADNODE: return False
|
|
return True
|
|
|
|
|
|
def is_int(self, s):
|
|
try:
|
|
int(s, 16)
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
|
|
def is_pointer_type(self, dtype):
|
|
"""
|
|
Returns true if the datatype represents a pointer.
|
|
|
|
Args:
|
|
dtype: String representing the datatype.
|
|
|
|
Returns:
|
|
True if the datatype represents a pointer, otherwise False.
|
|
"""
|
|
if dtype.lower().startswith("pointer") or dtype.endswith('*'):
|
|
return True
|
|
return False
|
|
|
|
|
|
def is_string_type(self, datatype):
|
|
"""
|
|
Returns true if the datatype represents a string type.
|
|
|
|
Args:
|
|
datatype: String representing the datatype.
|
|
|
|
Returns:
|
|
True if the datatype represents a string, otherwise False.
|
|
"""
|
|
if datatype.lower().startswith("unicode"): return True
|
|
if datatype.lower().startswith("string"): return True
|
|
return False
|
|
|
|
|
|
def is_structure(self, datatype):
|
|
"""
|
|
Returns true if the datatype represents a structure in the database.
|
|
|
|
Args:
|
|
dtype: String representing the datatype.
|
|
|
|
Returns:
|
|
True if the datatype represents an existing structure,
|
|
otherwise False.
|
|
"""
|
|
if idaapi.get_struc_id(datatype) == idaapi.BADNODE: return False
|
|
return True
|
|
|
|
|
|
def import_address_range(self, address_range):
|
|
"""
|
|
Processes ADDRESS_RANGE element.
|
|
|
|
Args:
|
|
address_range: XML element object containing start and end address
|
|
attributes for the address range.
|
|
|
|
Returns:
|
|
Tuple containing two integers, the start and end address values.
|
|
"""
|
|
start = self.get_address(address_range,START)
|
|
end = self.get_address(address_range, END)
|
|
self.update_counter(ADDRESS_RANGE)
|
|
return (start, end)
|
|
|
|
|
|
def import_bit_mask(self, bitmask, eid):
|
|
"""
|
|
Processes a BIT_MASK element as an enum bitmask member.
|
|
|
|
Args:
|
|
bitmask: XML element object representing the IDA enum bitmask.
|
|
eid: Integer representing the IDA enum id
|
|
"""
|
|
if IDA_SDK_VERSION < 640:
|
|
return
|
|
name = self.get_attribute(bitmask,NAME)
|
|
value = self.get_attribute_value(bitmask,VALUE)
|
|
idaapi.set_bmask_name(eid, value, name)
|
|
cid = idaapi.get_const_by_name(name)
|
|
self.update_counter(BIT_MASK)
|
|
regcmt = bitmask.find(REGULAR_CMT)
|
|
if regcmt != None:
|
|
idaapi.set_const_cmt(cid, regcmt.text, False);
|
|
self.update_counter(BIT_MASK + ':' + REGULAR_CMT)
|
|
rptcmt = bitmask.find(REPEATABLE_CMT)
|
|
if rptcmt != None:
|
|
idaapi.set_const_cmt(cid, rptcmt.txt, True);
|
|
self.update_counter(BIT_MASK + ':' + REPEATABLE_CMT)
|
|
|
|
|
|
def import_bookmark(self, bookmark):
|
|
"""
|
|
Processes a BOOKMARK element.
|
|
|
|
Args:
|
|
bookmark: XML element object containing bookmark data.
|
|
"""
|
|
if self.Options.Bookmarks.checked == False:
|
|
return
|
|
try:
|
|
addr = self.get_address(bookmark, ADDRESS)
|
|
if self.has_attribute(bookmark, TYPE):
|
|
typ = self.get_attribute(bookmark, TYPE)
|
|
category = ''
|
|
if self.has_attribute(bookmark, CATEGORY):
|
|
category = self.get_attribute(bookmark, CATEGORY)
|
|
description = ''
|
|
if self.has_attribute(bookmark, DESCRIPTION):
|
|
description = self.get_attribute(bookmark, DESCRIPTION)
|
|
if idaapi.isEnabled(addr) == False:
|
|
msg = ("import_bookmark: address %X not enabled in database"
|
|
% addr)
|
|
print msg
|
|
return
|
|
self.update_counter(BOOKMARK)
|
|
for slot in range(1,1025):
|
|
if IDA_SDK_VERSION != 695:
|
|
ea = idc.GetMarkedPos(slot)
|
|
else:
|
|
import ida_moves
|
|
import ida_pro
|
|
curloc = ida_moves.curloc()
|
|
intp = ida_pro.int_pointer()
|
|
intp.assign(slot)
|
|
ea = curloc.markedpos(intp)
|
|
if ea == BADADDR:
|
|
curloc = idaapi.curloc()
|
|
curloc.ea = addr
|
|
curloc.mark(slot, category, description)
|
|
break
|
|
except:
|
|
msg = "** Exception occurred in import_bookmark **"
|
|
print "\n" + msg + "\n", sys.exc_type, sys.exc_value
|
|
|
|
|
|
def import_cmts(self, element, sid, typ):
|
|
"""
|
|
Processes REGULAR_CMT and REPEATABLE_CMT elements for structures.
|
|
|
|
Args:
|
|
element: XML element object containing a REGULAR_CMT or
|
|
REPEATABLE_CMT element
|
|
sid: Integer representing the structure id
|
|
typ: String indicating structure type (STRUCTURE or UNION)
|
|
"""
|
|
regcmt = element.find(REGULAR_CMT)
|
|
if regcmt != None:
|
|
idaapi.set_struc_cmt(sid, regcmt.text, False)
|
|
self.update_counter(typ + ':' + REGULAR_CMT)
|
|
rptcmt = element.find(REPEATABLE_CMT)
|
|
if rptcmt != None:
|
|
idaapi.set_struc_cmt(sid, rptcmt.text, True)
|
|
self.update_counter(typ + ':' + REPEATABLE_CMT)
|
|
|
|
|
|
def import_codeblock(self, code_block):
|
|
"""
|
|
Processes a CODE_BLOCK element by disassembling the address range.
|
|
|
|
Args:
|
|
code_block: XML element containing codeblock start and end
|
|
addresses.
|
|
"""
|
|
if self.Options.CodeBlocks.checked == False:
|
|
return
|
|
start = self.get_address(code_block, START)
|
|
end = self.get_address(code_block, END)
|
|
idaapi.do_unknown_range(start, end-start+1, 3)
|
|
addr = start
|
|
while (addr <= end):
|
|
length = idaapi.create_insn(addr)
|
|
addr += idaapi.get_item_size(addr) * self.get_cbsize()
|
|
self.update_counter(CODE_BLOCK)
|
|
|
|
|
|
def import_comment(self, comment):
|
|
"""
|
|
Processes a COMMENT element by creating the comment at the address.
|
|
|
|
Args:
|
|
comment: XML element containing the comment address, type,
|
|
and text.
|
|
"""
|
|
if self.Options.Comments.checked == False:
|
|
return
|
|
addr = self.get_address(comment, ADDRESS)
|
|
ctype = self.get_attribute(comment,TYPE)
|
|
text = comment.text
|
|
if ctype == 'pre':
|
|
idaapi.add_long_cmt(addr, True, text)
|
|
elif ctype == 'end-of-line':
|
|
idaapi.set_cmt(addr, text, False)
|
|
elif ctype == 'repeatable':
|
|
idaapi.set_cmt(addr, text, True)
|
|
elif ctype == 'post':
|
|
idaapi.add_long_cmt(addr, False, text)
|
|
self.update_counter(COMMENT+':' + ctype)
|
|
|
|
|
|
def import_compiler(self, compiler):
|
|
"""
|
|
Processes the COMPILER element containing the compiler name.
|
|
|
|
Args:
|
|
compiler: XML element containing the compiler name.
|
|
"""
|
|
name = self.get_attribute(compiler, NAME)
|
|
comp = idaapi.COMP_UNK
|
|
if name == "Visual C++": comp = idaapi.COMP_MS
|
|
elif name == "Borland C++": comp = idaapi.COMP_BC
|
|
elif name == "Watcom C++": comp = idaapi.COMP_WATCOM
|
|
elif name == "GNU C++": comp = idaapi.COMP_GNU
|
|
elif name == "Visual Age C++": comp = idaapi.COMP_VISAGE
|
|
elif name == "Delphi": comp = idaapi.COMP_BP
|
|
idaapi.cvar.inf.cc.id = comp
|
|
self.update_counter(COMPILER)
|
|
|
|
|
|
def import_defined_data(self, defined_data):
|
|
"""
|
|
Processes a DEFINED_DATA element by creating a data item at the
|
|
specified address.
|
|
|
|
Args:
|
|
defined_data: XML element containing the address and
|
|
datatype information for the data item
|
|
"""
|
|
if self.Options.DataDefinitions.checked == False:
|
|
return
|
|
addr = self.get_address(defined_data, ADDRESS)
|
|
datatype = self.get_attribute(defined_data, DATATYPE)
|
|
size = self.get_attribute_value(defined_data, SIZE)
|
|
self.update_counter(DEFINED_DATA)
|
|
ti = idaapi.opinfo_t()
|
|
if self.is_pointer_type(datatype):
|
|
#idaapi.set_refinfo(ti, 0, 0, 0, REF_OFF32)
|
|
flag = idaapi.dwrdflag() | idaapi.FF_0OFF
|
|
#idaapi.set_typeinfo(addr, 0, flag, ti)
|
|
else:
|
|
flag = self.get_datatype_flags(datatype, size)
|
|
if flag == idaapi.asciflag():
|
|
idaapi.make_ascii_string(addr, size,
|
|
self.get_string_type(datatype))
|
|
elif flag == idaapi.struflag():
|
|
idaapi.doStruct(addr, size, idaapi.get_struc_id(datatype))
|
|
else:
|
|
idaapi.do_data_ex(addr, flag, size, idaapi.BADNODE)
|
|
typecmt = defined_data.find(TYPEINFO_CMT)
|
|
if typecmt != None:
|
|
self.update_counter(DEFINED_DATA + ':' + TYPEINFO_CMT)
|
|
|
|
|
|
def import_enum(self, enum):
|
|
"""
|
|
Processes an ENUM element by creating the enumeration.
|
|
|
|
Args:
|
|
enum: XML element containing the enumeration name and
|
|
member data.
|
|
"""
|
|
if self.Options.DataTypes.checked == False:
|
|
return
|
|
name = self.get_attribute(enum, NAME)
|
|
if self.has_attribute(enum,NAMESPACE):
|
|
namespace = self.get_attribute(enum, NAMESPACE)
|
|
if self.has_attribute(enum,SIZE):
|
|
size = self.get_attribute_value(enum, SIZE)
|
|
eid = idaapi.add_enum(BADADDR, name,
|
|
idaapi.hexflag() | idaapi.dwrdflag())
|
|
self.update_counter(ENUM)
|
|
regcmt = enum.find(REGULAR_CMT)
|
|
if regcmt != None:
|
|
idaapi.set_enum_cmt(eid, regcmt.text, False)
|
|
self.update_counter(ENUM + ':' + REGULAR_CMT)
|
|
rptcmt = enum.find(REPEATABLE_CMT)
|
|
if rptcmt != None:
|
|
idaapi.set_enum_cmt(eid, rptcmt.text, True)
|
|
self.update_counter(ENUM + ':' + REPEATABLE_CMT)
|
|
display_settings = enum.find(DISPLAY_SETTINGS)
|
|
if display_settings != None:
|
|
self.update_counter(ENUM + ':' + DISPLAY_SETTINGS)
|
|
enum_entries = enum.findall(ENUM_ENTRY)
|
|
for enum_entry in enum_entries:
|
|
self.import_enum_entry(enum_entry, eid)
|
|
|
|
|
|
def import_enum_entry(self, enum_entry, eid):
|
|
"""
|
|
Processes an ENUM_ENTRY by creating a member in the enumeration.
|
|
|
|
Args:
|
|
enum_entry: XML element containing the member name and value.
|
|
eid: Integer representing the id of the enumeration.
|
|
"""
|
|
name = self.get_attribute(enum_entry, NAME)
|
|
value = self.get_attribute_value(enum_entry, VALUE)
|
|
if IDA_SDK_VERSION > 630:
|
|
idaapi.add_const(eid, name, value)
|
|
else:
|
|
idaapi.add_enum_member(eid, name, value)
|
|
if IDA_SDK_VERSION > 630:
|
|
cid = idaapi.get_const_by_name(name)
|
|
else:
|
|
cid = idaapi.get_enum_member_by_name(name)
|
|
self.update_counter(ENUM_ENTRY)
|
|
regcmt = enum_entry.find(REGULAR_CMT)
|
|
if regcmt != None:
|
|
if IDA_SDK_VERSION > 630:
|
|
idaapi.set_const_cmt(cid, regcmt.text, False);
|
|
else:
|
|
idaapi.set_enum_member_cmt(cid, regcmt.text, False);
|
|
self.update_counter(ENUM_ENTRY + ':' + REGULAR_CMT)
|
|
rptcmt = enum_entry.find(REPEATABLE_CMT)
|
|
if rptcmt != None:
|
|
if IDA_SDK_VERSION > 630:
|
|
idaapi.set_const_cmt(cid, rptcmt.text, True);
|
|
else:
|
|
idaapi.set_enum_member_cmt(cid, rptcmt.text, True);
|
|
self.update_counter(ENUM_ENTRY + ':' + REPEATABLE_CMT)
|
|
|
|
|
|
def import_equate(self, equate, eid):
|
|
"""
|
|
Processes EQUATE element as member of an enumeration.
|
|
|
|
Args:
|
|
enum_entry: XML element containing the equate name and value.
|
|
eid: Integer representing the id for the enumeration.
|
|
"""
|
|
name = self.get_attribute(equate,NAME)
|
|
value = self.get_attribute_value(equate,VALUE)
|
|
bm = -1
|
|
if self.has_attribute(equate, BIT_MASK):
|
|
bm = self.get_attribute_value(equate, BIT_MASK)
|
|
if IDA_SDK_VERSION > 630:
|
|
#idaapi.add_const(eid, name, value, bm)
|
|
idaapi.add_const(eid, name, value)
|
|
cid = idaapi.get_const_by_name(name)
|
|
else:
|
|
#idaapi.add_enum_member(eid, name, value, bm)
|
|
idaapi.add_enum_member(eid, name, value)
|
|
cid = idaapi.get_enum_member_by_name(name)
|
|
self.update_counter(EQUATE)
|
|
regcmt = equate.find(REGULAR_CMT)
|
|
if regcmt != None:
|
|
if IDA_SDK_VERSION > 630:
|
|
idaapi.set_const_cmt(cid, regcmt.text, False);
|
|
else:
|
|
idaapi.set_enum_member_cmt(cid, regcmt.text, False);
|
|
self.update_counter(EQUATE + ':' + REGULAR_CMT)
|
|
rptcmt = equate.find(REPEATABLE_CMT)
|
|
if rptcmt != None:
|
|
if IDA_SDK_VERSION > 630:
|
|
idaapi.set_const_cmt(cid, rptcmt.text, True);
|
|
else:
|
|
idaapi.set_enum_member_cmt(cid, rptcmt.text, True);
|
|
self.update_counter(EQUATE + ':' + REPEATABLE_CMT)
|
|
|
|
|
|
def import_equate_group(self, equate_group):
|
|
"""
|
|
Processes EQUATE_GROUP as IDA enumeration type.
|
|
|
|
Args:
|
|
equate_group: XML element containing the group name and
|
|
equate definitions.
|
|
"""
|
|
if self.Options.DataTypes.checked == False:
|
|
return
|
|
msg = EQUATE_GROUP
|
|
name = ''
|
|
if self.has_attribute(equate_group, NAME):
|
|
name = self.get_attribute(equate_group, NAME)
|
|
bf = ''
|
|
if self.has_attribute(equate_group, BIT_FIELD):
|
|
bf = self.get_attribute(equate_group, BIT_FIELD)
|
|
eid = idaapi.add_enum(BADADDR, name, idaapi.hexflag())
|
|
idaapi.set_enum_bf(eid, (bf == 'yes'))
|
|
self.update_counter(EQUATE_GROUP)
|
|
regcmt = equate_group.find(REGULAR_CMT)
|
|
if regcmt != None:
|
|
idaapi.set_enum_cmt(eid, regcmt.text, False)
|
|
self.update_counter(EQUATE_GROUP + ':' + REGULAR_CMT)
|
|
rptcmt = equate_group.find(REPEATABLE_CMT)
|
|
if rptcmt != None:
|
|
idaapi.set_enum_cmt(eid, rptcmt.text, True)
|
|
self.update_counter(EQUATE_GROUP + ':' + REPEATABLE_CMT)
|
|
equates = equate_group.findall(EQUATE)
|
|
for equate in equates:
|
|
self.import_equate(equate,eid)
|
|
bit_masks = equate_group.findall(BIT_MASK)
|
|
for bit_mask in bit_masks:
|
|
self.import_bit_mask(bit_mask, eid)
|
|
|
|
|
|
def import_equate_reference(self, equate_reference):
|
|
if (self.Options.DataTypes.checked == False or
|
|
self.Options.EquateReferences.checked == False):
|
|
return
|
|
self.update_counter(EQUATE_REFERENCE)
|
|
addr = self.get_address(equate_reference, ADDRESS)
|
|
name = ''
|
|
if self.has_attribute(equate_reference, NAME):
|
|
name = self.get_attribute(equate_reference, NAME)
|
|
if name == '':
|
|
return
|
|
opnd = 0
|
|
if self.has_attribute(equate_reference, OPERAND_INDEX):
|
|
opnd = self.get_attribute_value(equate_reference, OPERAND_INDEX)
|
|
value = None
|
|
if self.has_attribute(equate_reference, VALUE):
|
|
value = self.get_attribute_value(equate_reference, VALUE)
|
|
if IDA_SDK_VERSION < 650:
|
|
cid = idaapi.get_enum_member_by_name(name)
|
|
else:
|
|
cid = idaapi.get_const_by_name(name)
|
|
if cid == idaapi.BADNODE:
|
|
return
|
|
if IDA_SDK_VERSION < 650:
|
|
eid = idaapi.get_enum_member_enum(cid)
|
|
else:
|
|
eid = idaapi.get_const_enum(cid)
|
|
if eid == idaapi.BADNODE:
|
|
return
|
|
idaapi.op_enum(addr, opnd, eid, 0)
|
|
|
|
|
|
def import_function(self, function):
|
|
"""
|
|
Creates a function using the FUNCTION attributes.
|
|
|
|
Args:
|
|
function: XML element containing the function address and
|
|
attributes.
|
|
"""
|
|
if self.Options.Functions.checked == False:
|
|
return
|
|
try:
|
|
entry_point = self.get_address(function, ENTRY_POINT)
|
|
name = ''
|
|
if self.has_attribute(function, NAME):
|
|
name = self.get_attribute(function, NAME)
|
|
libfunc = 'n'
|
|
if self.has_attribute(function, LIBRARY_FUNCTION):
|
|
libfunc = self.get_attribute(function, LIBRARY_FUNCTION)
|
|
if idaapi.isEnabled(entry_point) == False:
|
|
msg = ("import_function: address %X not enabled in database"
|
|
% entry_point)
|
|
print msg
|
|
return
|
|
idaapi.add_func(entry_point, BADADDR)
|
|
self.update_counter(FUNCTION)
|
|
func = idaapi.get_func(entry_point)
|
|
if libfunc == 'y':
|
|
func.flags |= idaapi.FUNC_LIB
|
|
ranges = function.findall(ADDRESS_RANGE)
|
|
for addr_range in ranges:
|
|
(start, end) = self.import_address_range(addr_range)
|
|
idaapi.append_func_tail(func, start, end)
|
|
#idaapi.analyze_area(start, end+1)
|
|
idc.Wait()
|
|
regcmt = function.find(REGULAR_CMT)
|
|
if regcmt != None:
|
|
self.update_counter(FUNCTION + ':' + REGULAR_CMT)
|
|
idaapi.set_func_cmt(func, regcmt.text, False)
|
|
rptcmt = function.find(REPEATABLE_CMT)
|
|
if rptcmt != None:
|
|
self.update_counter(FUNCTION + ':' + REPEATABLE_CMT)
|
|
idaapi.set_func_cmt(func, rptcmt.text, True)
|
|
typecmt = function.find(TYPEINFO_CMT)
|
|
if typecmt != None:
|
|
self.update_counter(FUNCTION + ':' + TYPEINFO_CMT)
|
|
idc.SetType(entry_point, typecmt.text + ';')
|
|
sf = function.find(STACK_FRAME)
|
|
if sf != None:
|
|
self.import_stack_frame(sf, func)
|
|
register_vars = function.findall(REGISTER_VAR)
|
|
for register_var in register_vars:
|
|
self.import_register_var(register_var, func)
|
|
except:
|
|
msg = "** Exception occurred in import_function **"
|
|
print "\n" + msg + "\n", sys.exc_type, sys.exc_value
|
|
|
|
|
|
def import_function_def(self, function_def):
|
|
# import_function_def: NOT IMPLEMENTED
|
|
if self.Options.DataTypes.checked == False:
|
|
return
|
|
self.update_counter(FUNCTION_DEF)
|
|
|
|
|
|
def import_info_source(self, info_source):
|
|
"""
|
|
Processes INFO_SOURCE containing information about the
|
|
source of the XML PROGRAM file.
|
|
|
|
Args:
|
|
info_source: XML element containing attributes that identify
|
|
the source of the PROGRAM data.
|
|
"""
|
|
if self.has_attribute(info_source, TOOL):
|
|
tool = self.get_attribute(info_source, TOOL)
|
|
if self.has_attribute(info_source, USER):
|
|
user = self.get_attribute(info_source, USER)
|
|
if self.has_attribute(info_source, FILE):
|
|
f = self.get_attribute(info_source, FILE)
|
|
if self.has_attribute(info_source, TIMESTAMP):
|
|
ts = self.get_attribute(info_source, TIMESTAMP)
|
|
self.update_counter(INFO_SOURCE)
|
|
|
|
|
|
def import_manual_instruction(self, manual_instruction):
|
|
"""
|
|
Creates a manual instruction.
|
|
|
|
Args:
|
|
manual_instruction: XML element containing MANUAL_INSTRUCTION.
|
|
"""
|
|
if self.Options.Manual.checked == False:
|
|
return
|
|
addr = self.get_address(manual_instruction, ADDRESS)
|
|
idaapi.set_manual_insn(addr, manual_instruction.text)
|
|
self.update_counter(MANUAL_INSTRUCTION)
|
|
|
|
|
|
def import_manual_operand(self, manual_operand):
|
|
"""
|
|
Creates a manual operand at an address.
|
|
|
|
Args:
|
|
manual_operand: MANUAL_OPERAND XML element.
|
|
"""
|
|
if self.Options.Manual.checked == False:
|
|
return
|
|
addr = self.get_address(manual_operand, ADDRESS)
|
|
op = self.get_attribute_value(manual_operand, OPERAND_INDEX)
|
|
if idaapi.isEnabled(addr):
|
|
idaapi.set_forced_operand(addr, op, manual_operand.text)
|
|
self.update_counter(MANUAL_OPERAND)
|
|
|
|
|
|
def process_deferred(self, element):
|
|
"""
|
|
Processes the list of deferred structure members when the
|
|
DATATYPES end element is encountered.
|
|
|
|
Args:
|
|
element: XML end element for DATATYPES
|
|
"""
|
|
for (member, sptr) in self.deferred:
|
|
self.import_member(member, sptr, False)
|
|
self.display_timer(element)
|
|
|
|
|
|
def import_member(self, member, sptr, defer=True):
|
|
"""
|
|
Creates a member for a structure.
|
|
|
|
Args:
|
|
member: MEMBER XML element.
|
|
sptr:
|
|
defer: boolean indicating if processing a member should be
|
|
deferred when the type is unknown. A member should
|
|
only be deferred on the first pass, not when processing
|
|
the deferred list.
|
|
"""
|
|
offset = self.get_attribute_value(member, OFFSET)
|
|
datatype = self.get_attribute(member, DATATYPE)
|
|
if self.has_attribute(member, DATATYPE_NAMESPACE):
|
|
dt_namespace = self.get_attribute(member, DATATYPE_NAMESPACE)
|
|
name = ''
|
|
if self.has_attribute(member, NAME):
|
|
name = self.get_attribute(member, NAME)
|
|
size = 0
|
|
if self.has_attribute(member, SIZE):
|
|
size = self.get_attribute_value(member, SIZE)
|
|
ti = idaapi.opinfo_t()
|
|
if self.is_pointer_type(datatype):
|
|
#idaapi.set_refinfo(ti, 0, BADADDR, 0, REF_OFF32)
|
|
flag = idaapi.dwrdflag() | idaapi.FF_0OFF
|
|
else:
|
|
flag = self.get_datatype_flags(datatype, size)
|
|
if flag == 0:
|
|
if defer:
|
|
self.deferred.append([member, sptr])
|
|
return
|
|
if flag == idaapi.enumflag():
|
|
t = idaapi.get_enum(datatype)
|
|
ti.ec.tid = t
|
|
ti.ec.serial = idaapi.get_enum_idx(t)
|
|
if flag == idaapi.struflag():
|
|
t = idaapi.get_struc_id(datatype)
|
|
ti.tid = t
|
|
error = idaapi.add_struc_member(sptr, name, offset, flag, ti, size)
|
|
mbr = idaapi.get_member(sptr, offset)
|
|
self.import_member_cmts(member, mbr)
|
|
self.update_counter(MEMBER)
|
|
|
|
|
|
def import_member_cmts(self, member, mbr):
|
|
"""
|
|
Processes REGULAR_CMT and REPEATABLE_CMT elements for members.
|
|
|
|
Args:
|
|
element: XML element object containing a REGULAR_CMT or
|
|
REPEATABLE_CMT element
|
|
mbr: Integer representing the member id
|
|
"""
|
|
regcmt = member.find(REGULAR_CMT)
|
|
if regcmt != None:
|
|
idaapi.set_member_cmt(mbr, regcmt.text, False)
|
|
self.update_counter(MEMBER + ':' + REGULAR_CMT)
|
|
rptcmt = member.find(REPEATABLE_CMT)
|
|
if rptcmt != None:
|
|
idaapi.set_member_cmt(mbr, rptcmt.text, True)
|
|
self.update_counter(MEMBER + ':' + REPEATABLE_CMT)
|
|
|
|
|
|
def import_members(self, element, sptr):
|
|
"""
|
|
Add data members to a structure.
|
|
|
|
Args:
|
|
element: STRUCTURE XML element containing MEMBER sub-elements.
|
|
sptr:
|
|
"""
|
|
members = element.findall(MEMBER)
|
|
for member in members:
|
|
self.import_member(member, sptr)
|
|
|
|
|
|
def import_memory_contents(self, memory_contents, start, size):
|
|
"""
|
|
Processes MEMORY_CONTENTS to load data for a memory block.
|
|
|
|
Args:
|
|
memory_contents: MEMORY_CONTENTS XML element.
|
|
"""
|
|
if memory_contents.get(START_ADDR) == None:
|
|
saddr = start
|
|
else:
|
|
saddr = self.get_address(memory_contents, START_ADDR)
|
|
fname = self.get_attribute(memory_contents, FILE_NAME)
|
|
offset = self.get_attribute_value(memory_contents, FILE_OFFSET)
|
|
if memory_contents.get(LENGTH) == None:
|
|
length = size
|
|
else:
|
|
length = self.get_attribute_value(memory_contents, LENGTH)
|
|
#(binfilename, ext) = os.path.splitext(self.filename)
|
|
#binfilename += ".bytes"
|
|
(binfilename, fileext) = os.path.split(self.filename)
|
|
binfilename += '/' + fname
|
|
binfile = idaapi.loader_input_t()
|
|
binfile.open(binfilename)
|
|
binfile.file2base(offset,saddr,saddr+length,False)
|
|
binfile.close()
|
|
self.update_counter(MEMORY_CONTENTS)
|
|
|
|
|
|
def import_memory_map(self, memory_map):
|
|
"""
|
|
Processes the MEMORY_MAP element.
|
|
|
|
Args:
|
|
memory_map: MEMORY_MAP XML element.
|
|
|
|
MEMORY_MAP is only processed by the IDA loader. It is ignored when
|
|
run as an IDA plugin.
|
|
"""
|
|
# import memory sections only when run as loader
|
|
if self.plugin:
|
|
return
|
|
self.update_import(memory_map)
|
|
|
|
|
|
def import_memory_reference(self, memory_reference):
|
|
"""
|
|
Processes the MEMORY_REFERENCE element.
|
|
|
|
Args:
|
|
memory_reference: MEMORY_REFERENCE XML element.
|
|
"""
|
|
if self.Options.MemoryReferences.checked == False:
|
|
return
|
|
addr = self.get_address(memory_reference, ADDRESS)
|
|
if self.has_attribute(memory_reference, OPERAND_INDEX):
|
|
op = self.get_attribute_value(memory_reference, OPERAND_INDEX)
|
|
if self.has_attribute(memory_reference, USER_DEFINED):
|
|
user = self.get_attribute(memory_reference, USER_DEFINED)
|
|
to_addr = self.get_address(memory_reference, TO_ADDRESS)
|
|
if self.has_attribute(memory_reference, BASE_ADDRESS):
|
|
base_addr = self.get_address(memory_reference, BASE_ADDRESS)
|
|
if self.has_attribute(memory_reference, PRIMARY):
|
|
primary = self.get_attribute(memory_reference, PRIMARY)
|
|
self.update_counter(MEMORY_REFERENCE)
|
|
# TODO: import_memory_reference - add code to store reference
|
|
|
|
|
|
def import_memory_section(self, memory_section):
|
|
"""
|
|
Creates a memory segment in the database.
|
|
|
|
Args:
|
|
memory_section: MEMORY_SECTION XML element.
|
|
|
|
MEMORY_SECTION is only processed by the IDA loader. It is ignored
|
|
when run as an IDA plugin.
|
|
"""
|
|
# TODO: import_memory_section - handle overlays?
|
|
# import memory sections only when run as loader
|
|
if self.plugin:
|
|
return
|
|
name = self.get_attribute(memory_section, NAME)
|
|
length = self.get_attribute_value(memory_section, LENGTH)
|
|
|
|
s = idaapi.segment_t()
|
|
addrstr = self.get_attribute(memory_section, START_ADDR)
|
|
seg_str = ''
|
|
if '::' in addrstr:
|
|
# overlay - skip for now
|
|
print ' ** Overlayed memory block %s skipped ** ' % name
|
|
msg = 'Overlayed memory block %s skipped!' % name
|
|
msg += "\n\nXML Import does not currently support"
|
|
msg += "\noverlayed memory blocks."
|
|
idaapi.warning(msg)
|
|
return
|
|
elif ':' in addrstr:
|
|
[seg_str, offset_str] = string.split(addrstr,':')
|
|
offset = int(offset_str, 16)
|
|
if self.is_int(seg_str):
|
|
base = int(seg_str, 16)
|
|
sel = idaapi.setup_selector(base)
|
|
start = self.get_address(memory_section, START_ADDR)
|
|
else:
|
|
raise MultipleAddressSpacesNotSupported
|
|
return
|
|
else:
|
|
sel = idaapi.allocate_selector(0)
|
|
start = int(addrstr, 16)
|
|
|
|
s.sel = sel
|
|
s.startEA = start
|
|
s.endEA = start+length
|
|
s.bitness = self.addr_mode
|
|
|
|
perms = ''
|
|
if self.has_attribute(memory_section, PERMISSIONS):
|
|
perms = self.get_attribute(memory_section, PERMISSIONS)
|
|
s.perm = 0
|
|
if 'r' in perms: s.perm |= idaapi.SEGPERM_READ
|
|
if 'w' in perms: s.perm |= idaapi.SEGPERM_WRITE
|
|
if 'x' in perms: s.perm |= idaapi.SEGPERM_EXEC
|
|
idaapi.add_segm_ex(s, name, "", idaapi.ADDSEG_OR_DIE |
|
|
idaapi.ADDSEG_QUIET)
|
|
self.update_counter(MEMORY_SECTION)
|
|
for memory_contents in memory_section.findall(MEMORY_CONTENTS):
|
|
self.import_memory_contents(memory_contents, start, length)
|
|
|
|
|
|
def import_processor(self, processor):
|
|
"""
|
|
Processes the PROCESSOR element.
|
|
|
|
Args:
|
|
processor: PROCESSOR XML element.
|
|
"""
|
|
name = self.get_attribute(processor, NAME)
|
|
self.update_counter(PROCESSOR)
|
|
if self.plugin:
|
|
return
|
|
address_model = self.get_attribute(processor, ADDRESS_MODEL)
|
|
if address_model != None:
|
|
flag = idaapi.ph_get_flag()
|
|
if str.lower(address_model) == '16-bit':
|
|
self.addr_mode = 0
|
|
elif str.lower(address_model) == '32-bit':
|
|
self.addr_mode = 1
|
|
elif str.lower(address_model) == '64-bit':
|
|
self.addr_mode = 2
|
|
|
|
|
|
def import_program(self, program):
|
|
"""
|
|
Processes the PROGRAM element.
|
|
|
|
Args:
|
|
program: PROGRAM XML element.
|
|
"""
|
|
self.update_status(PROGRAM)
|
|
name = self.get_attribute(program, NAME)
|
|
if self.has_attribute(program, EXE_PATH):
|
|
epath = self.get_attribute(program, EXE_PATH)
|
|
idaapi.set_root_filename(epath)
|
|
else:
|
|
idaapi.set_root_filename(name)
|
|
if self.has_attribute(program, EXE_FORMAT):
|
|
eformat = self.get_attribute(program, EXE_FORMAT)
|
|
RootNode = idaapi.netnode('Root Node')
|
|
if IDA_SDK_VERSION < 650:
|
|
RootNode.supset(1, eformat)
|
|
else:
|
|
RootNode.supset(idaapi.RIDX_FILE_FORMAT_NAME, eformat)
|
|
if self.has_attribute(program, IMAGE_BASE):
|
|
base = self.get_attribute_value(program, IMAGE_BASE)
|
|
idaapi.set_imagebase(base)
|
|
if self.has_attribute(program, INPUT_MD5):
|
|
input_md5 = self.get_attribute(program, INPUT_MD5)
|
|
# store original md5 in a special netnode
|
|
md5 = idaapi.netnode(INPUT_MD5, len(INPUT_MD5), True)
|
|
if (IDA_SDK_VERSION < 650):
|
|
md5.supset(1302, input_md5)
|
|
else:
|
|
md5.supset(idaapi.RIDX_MD5, input_md5)
|
|
self.update_counter(PROGRAM)
|
|
"""
|
|
# TODO: this needs to be on "end" event for PROGRAM
|
|
description = program.find(DESCRIPTION)
|
|
if description != None:
|
|
pass # figure out what to do with it
|
|
"""
|
|
|
|
|
|
def import_program_entry_point(self, program_entry_point):
|
|
"""
|
|
Defines a program entry point.
|
|
|
|
Args:
|
|
program_entry_point: PROGRAM_ENTRY_POINT XML element.
|
|
Contains the entry point address.
|
|
"""
|
|
if self.Options.EntryPoints.checked == False:
|
|
return
|
|
addr = self.get_address(program_entry_point, ADDRESS)
|
|
idaapi.add_entry(addr, addr, "", True)
|
|
self.update_counter(PROGRAM_ENTRY_POINT)
|
|
|
|
|
|
def import_register_value_range(self, register_value_range):
|
|
"""
|
|
Defines the address range for a register value.
|
|
|
|
Args:
|
|
register_value_range: REGISTER_VALUE_RANGE XML element.
|
|
Contains the register, value, start address and range length.
|
|
"""
|
|
if self.Options.RegisterValues.checked == False:
|
|
return
|
|
self.update_counter(REGISTER_VALUE_RANGE)
|
|
reg = self.get_attribute(register_value_range, REGISTER)
|
|
if reg == 'cs': return
|
|
value = self.get_attribute_value(register_value_range, VALUE)
|
|
addr = self.get_address(register_value_range, START_ADDRESS)
|
|
length = self.get_attribute_value(register_value_range, LENGTH)
|
|
r = idaapi.str2reg(reg)
|
|
if r >= idaapi.ph.regFirstSreg and r <= idaapi.ph.regLastSreg:
|
|
if IDA_SDK_VERSION < 670:
|
|
idaapi.splitSRarea1(addr, r, value, 2)
|
|
else:
|
|
idaapi.splitSRarea1(addr, r, value, idaapi.SR_user)
|
|
|
|
|
|
def import_register_var(self, register_var, func):
|
|
"""
|
|
Defines a register variable for a function.
|
|
|
|
Args:
|
|
register_var: REGISTER_VAR XML element.
|
|
Contains register, variable name, and datatype.
|
|
func: IDA function object
|
|
"""
|
|
name = self.get_attribute(register_var, NAME)
|
|
reg = self.get_attribute(register_var, REGISTER)
|
|
if self.has_attribute(register_var, DATATYPE):
|
|
datatype = self.get_attribute(register_var, DATATYPE)
|
|
if self.has_attribute(register_var, DATATYPE_NAMESPACE):
|
|
namespace = self.get_attribute(register_var, DATATYPE_NAMESPACE)
|
|
idc.MakeLocal(func.startEA, func.endEA, reg, name)
|
|
self.update_counter(REGISTER_VAR)
|
|
|
|
|
|
def import_stack_frame(self, stack_frame, func):
|
|
"""
|
|
Defines a stack frame for a function.
|
|
|
|
Args:
|
|
stack_frame: STACK_FRAME element with STACK_VAR child elements.
|
|
"""
|
|
if self.has_attribute(stack_frame, LOCAL_VAR_SIZE):
|
|
lvsize = self.get_attribute_value(stack_frame, LOCAL_VAR_SIZE)
|
|
if self.has_attribute(stack_frame, PARAM_OFFSET):
|
|
param_offset = self.get_attribute_value(stack_frame, PARAM_OFFSET)
|
|
if self.has_attribute(stack_frame, REGISTER_SAVE_SIZE):
|
|
reg_save_size = self.get_attribute_value(stack_frame,
|
|
REGISTER_SAVE_SIZE)
|
|
if self.has_attribute(stack_frame, RETURN_ADDR_SIZE):
|
|
retaddr_size = self.get_attribute_value(stack_frame,
|
|
RETURN_ADDR_SIZE)
|
|
if self.has_attribute(stack_frame, BYTES_PURGED):
|
|
bytes_purged = self.get_attribute_value(stack_frame, BYTES_PURGED)
|
|
self.update_counter(STACK_FRAME)
|
|
for stack_var in stack_frame.findall(STACK_VAR):
|
|
self.import_stack_var(stack_var, func)
|
|
|
|
|
|
def import_stack_reference(self, stack_reference):
|
|
# import_stack_reference: NOT IMPLEMENTED
|
|
#self.update_counter(STACK_REFERENCE)
|
|
pass
|
|
|
|
|
|
def import_stack_var(self, stack_var, func):
|
|
"""
|
|
Processes STACK_VAR element.
|
|
|
|
Args:
|
|
stack_var: STACK_VAR XML element.
|
|
|
|
Stack variables are created by IDA's function analysis.
|
|
Only the STACK_VAR NAME attribute is used to set the name for
|
|
a stack variable at the specified stack/frame offset.
|
|
"""
|
|
spoffset = self.get_attribute_value(stack_var, STACK_PTR_OFFSET)
|
|
datatype = self.get_attribute(stack_var, DATATYPE)
|
|
offset = spoffset + func.frsize + func.frregs
|
|
if self.has_attribute(stack_var, FRAME_PTR_OFFSET):
|
|
fpoffset = self.get_attribute_value(stack_var, FRAME_PTR_OFFSET)
|
|
offset = fpoffset + func.frsize
|
|
name = ''
|
|
if self.has_attribute(stack_var, NAME):
|
|
name = self.get_attribute(stack_var, NAME)
|
|
if self.has_attribute(stack_var, DATATYPE_NAMESPACE):
|
|
namespace = self.get_attribute(stack_var, DATATYPE_NAMESPACE)
|
|
if self.has_attribute(stack_var, SIZE):
|
|
size = self.get_attribute_value(stack_var, SIZE)
|
|
self.update_counter(STACK_VAR)
|
|
sf = idaapi.get_frame(func)
|
|
if name != '':
|
|
idaapi.set_member_name(sf, offset, name)
|
|
|
|
|
|
def import_structure(self, structure):
|
|
"""
|
|
Adds a structure.
|
|
|
|
Args:
|
|
structure: STRUCTURE XML element.
|
|
Contains the STRUCTURE attributes and child elements.
|
|
"""
|
|
if self.Options.DataTypes.checked == False:
|
|
return
|
|
name = self.get_attribute(structure, NAME)
|
|
dtyp = idaapi.get_struc_id(name)
|
|
if dtyp != idaapi.BADNODE:
|
|
# duplicate name, try adding name space
|
|
if self.has_attribute(structure, NAMESPACE) == False:
|
|
return
|
|
namespace = self.get_attribute(structure, NAMESPACE)
|
|
name = namespace + '__' + name
|
|
name.replace('/','_')
|
|
name.replace('.','_')
|
|
dtyp = idaapi.get_struc_id(name)
|
|
# skip if still duplicate (could add sequence #)
|
|
if dtyp != idaapi.BADNODE:
|
|
return
|
|
size = 0
|
|
if self.has_attribute(structure, SIZE):
|
|
size = self.get_attribute_value(structure, SIZE)
|
|
if self.has_attribute(structure, VARIABLE_LENGTH):
|
|
vl = self.get_attribute_value(structure, VARIABLE_LENGTH)
|
|
isVariableLength = vl == 'y'
|
|
sid = idaapi.add_struc(BADADDR, name, False)
|
|
sptr = idaapi.get_struc(sid)
|
|
self.update_counter(STRUCTURE)
|
|
self.import_cmts(structure, sid, STRUCTURE)
|
|
self.import_members(structure, sptr)
|
|
t = idaapi.opinfo_t()
|
|
if idaapi.get_struc_size(sptr) < size:
|
|
idaapi.add_struc_member(sptr,"",size-1,idaapi.byteflag(),t,1)
|
|
|
|
|
|
def import_symbol(self, symbol):
|
|
"""
|
|
Adds a symbol name at the specified address.
|
|
|
|
Args:
|
|
symbol: SYMBOL XML element.
|
|
Contains symbol name and address. Optionally includes
|
|
type and mangled symbol.
|
|
"""
|
|
if self.Options.Symbols.checked == False:
|
|
return
|
|
addr = self.get_address(symbol, ADDRESS)
|
|
name = self.get_attribute(symbol, NAME)
|
|
if self.has_attribute(symbol, MANGLED):
|
|
name = self.get_attribute(symbol, MANGLED)
|
|
flag = idaapi.SN_NOWARN
|
|
if self.has_attribute(symbol, TYPE):
|
|
typ = self.get_attribute(symbol, TYPE)
|
|
if typ == 'local': flag |= idaapi.SN_LOCAL
|
|
idaapi.set_name(addr, name, flag)
|
|
self.update_counter(SYMBOL)
|
|
|
|
|
|
def import_typedef(self, type_def):
|
|
# import_typedef: NOT IMPLEMENTED
|
|
if self.Options.DataTypes.checked == False:
|
|
return
|
|
self.update_counter(TYPE_DEF)
|
|
|
|
|
|
def import_union(self, union):
|
|
"""
|
|
Adds a union datatype.
|
|
|
|
Args:
|
|
union: UNION XML element.
|
|
Contains UNION attributes and child elements.
|
|
"""
|
|
if self.Options.DataTypes.checked == False:
|
|
return
|
|
name = self.get_attribute(union, NAME)
|
|
dtyp = idaapi.get_struc_id(name)
|
|
if dtyp != idaapi.BADNODE:
|
|
# duplicate name, try adding name space
|
|
if self.has_attribute(union, NAMESPACE) == False:
|
|
return
|
|
namespace = self.get_attribute(union, NAMESPACE)
|
|
name = namespace + '__' + name
|
|
name.replace('/','_')
|
|
name.replace('.','_')
|
|
dtyp = idaapi.get_struc_id(name)
|
|
# skip if still duplicate (could add sequence #)
|
|
if dtyp != idaapi.BADNODE:
|
|
return
|
|
size = 0
|
|
if self.has_attribute(union, SIZE):
|
|
size = self.get_attribute_value(union, SIZE)
|
|
sid = idaapi.add_struc(BADADDR, name, True)
|
|
sptr = idaapi.get_struc(sid)
|
|
self.update_counter(UNION)
|
|
self.import_cmts(union, sid, UNION)
|
|
self.import_members(union, sptr)
|
|
t = idaapi.opinfo_t()
|
|
if idaapi.get_struc_size(sptr) < size:
|
|
idaapi.add_struc_member(sptr,"", size-1, idaapi.byteflag(), None, 1)
|
|
|
|
|
|
def open_file(self, filename, mode):
|
|
"""
|
|
Opens filename to specified mode.
|
|
|
|
Args:
|
|
filename: String representing absolute filepath.
|
|
mode: String representing mode for open.
|
|
|
|
Returns
|
|
File handle.
|
|
|
|
Exceptions:
|
|
Displays a warning and raises FileError exception
|
|
if open fails.
|
|
"""
|
|
try:
|
|
f = open(filename, mode)
|
|
return f
|
|
except:
|
|
fmt = "TITLE ERROR!\n"
|
|
fmt += "ICON ERROR\n"
|
|
fmt += "AUTOHIDE NONE\n"
|
|
fmt += "HIDECANCEL\n"
|
|
fmt += "Error opening file" + filename + "!\n"
|
|
idaapi.warning(fmt)
|
|
raise FileError
|
|
|
|
|
|
def update_counter(self, tag):
|
|
"""
|
|
Updates the counter for the element tag.
|
|
|
|
Args:
|
|
tag: String representing element tag.
|
|
"""
|
|
if tag in self.Elements:
|
|
self.Counters[self.Elements[tag]] += 1
|
|
else:
|
|
self.Elements[tag] = len(self.Elements)
|
|
self.Counters.append(1)
|
|
self.Tags.append(tag)
|
|
|
|
|
|
def update_import(self, element):
|
|
"""
|
|
Update the element counter and processing status.
|
|
|
|
Args:
|
|
element: XML element
|
|
|
|
This function is used to process certain high-level elements
|
|
(such as COMMENTS, CODE_BLOCKS, SYMBOL_TABLE, FUNCTIONS, etc.)
|
|
that are used to group sub-elements.
|
|
"""
|
|
self.update_counter(element.tag)
|
|
self.update_status(element.tag)
|
|
|
|
|
|
def update_status(self, tag):
|
|
"""
|
|
Displays the processing status in the IDA window.
|
|
|
|
Args:
|
|
tag: String representing XML element tag
|
|
"""
|
|
status = 'Importing ' + tag
|
|
idaapi.msg('\n%-35s' % status)
|
|
idaapi.hide_wait_box()
|
|
idaapi.show_wait_box(status)
|
|
|
|
|
|
# Global XML string constants for elements and attributes
|
|
ADDRESS = 'ADDRESS'
|
|
ADDRESS_MODEL = 'ADDRESS_MODEL'
|
|
ADDRESS_RANGE = 'ADDRESS_RANGE'
|
|
BASE_ADDRESS = 'BASE_ADDRESS'
|
|
BIT_FIELD = 'BIT_FIELD'
|
|
BIT_MAPPED = 'BIT_MAPPED'
|
|
BIT_MASK = 'BIT_MASK'
|
|
BOOKMARK = 'BOOKMARK'
|
|
BOOKMARKS = 'BOOKMARKS'
|
|
BYTES = 'BYTES'
|
|
BYTES_PURGED = 'BYTES_PURGED'
|
|
CATEGORY = 'CATEGORY'
|
|
CODE = 'CODE'
|
|
CODE_BLOCK = 'CODE_BLOCK'
|
|
COMMENT = 'COMMENT'
|
|
COMMENTS = 'COMMENTS'
|
|
COMPILER = 'COMPILER'
|
|
DATA = 'DATA'
|
|
DATATYPE = 'DATATYPE'
|
|
DATATYPES = 'DATATYPES'
|
|
DATATYPE_NAMESPACE = 'DATATYPE_NAMESPACE'
|
|
DEFINED_DATA = 'DEFINED_DATA'
|
|
DESCRIPTION = 'DESCRIPTION'
|
|
DISPLAY_SETTINGS = 'DISPLAY_SETTINGS'
|
|
END = 'END'
|
|
ENDIAN = 'ENDIAN'
|
|
ENTRY_POINT = 'ENTRY_POINT'
|
|
ENUM = 'ENUM'
|
|
ENUM_ENTRY = 'ENUM_ENTRY'
|
|
EQUATE = 'EQUATE'
|
|
EQUATES = 'EQUATES'
|
|
EQUATE_GROUP = 'EQUATE_GROUP'
|
|
EQUATE_REFERENCE = 'EQUATE_REFERENCE'
|
|
EXE_FORMAT = 'EXE_FORMAT'
|
|
EXE_PATH = 'EXE_PATH'
|
|
EXT_LIBRARY = 'EXT_LIBRARY'
|
|
EXT_LIBRARY_REFERENCE = 'EXT_LIBRARY_REFERENCE'
|
|
EXT_LIBRARY_TABLE = 'EXT_LIBRARY_TABLE'
|
|
FAMILY = 'FAMILY'
|
|
FILE = 'FILE'
|
|
FILE_NAME = 'FILE_NAME'
|
|
FILE_OFFSET = 'FILE_OFFSET'
|
|
FOLDER = 'FOLDER'
|
|
FORMAT = 'FORMAT'
|
|
FRAGMENT = 'FRAGMENT'
|
|
FRAME_PTR_OFFSET = 'FRAME_PTR_OFFSET'
|
|
FUNCTION = 'FUNCTION'
|
|
FUNCTIONS = 'FUNCTIONS'
|
|
FUNCTION_DEF = 'FUNCTION_DEF'
|
|
IMAGE_BASE = 'IMAGE_BASE'
|
|
INPUT_MD5 = 'INPUT_MD5'
|
|
INFO_SOURCE = 'INFO_SOURCE'
|
|
LANGUAGE_PROVIDER = 'LANGUAGE_PROVIDER'
|
|
LENGTH = 'LENGTH'
|
|
LIB_ADDR = 'LIB_ADDR'
|
|
LIB_LABEL = 'LIB_LABEL'
|
|
LIB_ORDINAL = 'LIB_ORDINAL'
|
|
LIB_PROG_NAME = 'LIB_PROG_NAME'
|
|
LIBRARY_FUNCTION = 'LIBRARY_FUNCTION'
|
|
LOCAL_VAR_SIZE = 'LOCAL_VAR_SIZE'
|
|
MANGLED = 'MANGLED'
|
|
MANUAL_INSTRUCTION = 'MANUAL_INSTRUCTION'
|
|
MANUAL_OPERAND = 'MANUAL_OPERAND'
|
|
MARKUP = 'MARKUP'
|
|
MEMBER = 'MEMBER'
|
|
MEMORY_CONTENTS = 'MEMORY_CONTENTS'
|
|
MEMORY_MAP = 'MEMORY_MAP'
|
|
MEMORY_REFERENCE = 'MEMORY_REFERENCE'
|
|
MEMORY_SECTION = 'MEMORY_SECTION'
|
|
NAME = 'NAME'
|
|
NAMESPACE = 'NAMESPACE'
|
|
OFFSET = 'OFFSET'
|
|
OPERAND_INDEX = 'OPERAND_INDEX'
|
|
PARAM_OFFSET = 'PARAM_OFFSET'
|
|
PATH = 'PATH'
|
|
PERMISSIONS = 'PERMISSIONS'
|
|
PRIMARY = 'PRIMARY'
|
|
PROCESSOR = 'PROCESSOR'
|
|
PROGRAM = 'PROGRAM'
|
|
PROGRAM_ENTRY_POINT = 'PROGRAM_ENTRY_POINT'
|
|
PROGRAM_ENTRY_POINTS = 'PROGRAM_ENTRY_POINTS'
|
|
PROGRAM_TREES = 'PROGRAM_TREES'
|
|
PROPERTIES = 'PROPERTIES'
|
|
PROPERTY = 'PROPERTY'
|
|
REGISTER = 'REGISTER'
|
|
REGISTER_SAVE_SIZE = 'REGISTER_SAVE_SIZE'
|
|
REGISTER_VALUES = 'REGISTER_VALUES'
|
|
REGISTER_VALUE_RANGE = 'REGISTER_VALUE_RANGE'
|
|
REGISTER_VAR = 'REGISTER_VAR'
|
|
REGULAR_CMT = 'REGULAR_CMT'
|
|
RELOCATION = 'RELOCATION'
|
|
RELOCATION_TABLE = 'RELOCATION_TABLE'
|
|
REPEATABLE_CMT = 'REPEATABLE_CMT'
|
|
RETURN_ADDR_SIZE = 'RETURN_ADDR_SIZE'
|
|
RETURN_TYPE = 'RETURN_TYPE'
|
|
SHOW_TERMINATOR = 'SHOW_TERMINATOR'
|
|
SIGNED = 'SIGNED'
|
|
SIZE = 'SIZE'
|
|
SOURCE_ADDRESS = 'SOURCE_ADDRESS'
|
|
SOURCE_TYPE = 'SOURCE_TYPE'
|
|
STACK_FRAME = 'STACK_FRAME'
|
|
STACK_PTR_OFFSET = 'STACK_PTR_OFFSET'
|
|
STACK_REFERENCE = 'STACK_REFERENCE'
|
|
STACK_VAR = 'STACK_VAR'
|
|
START = 'START'
|
|
START_ADDR = 'START_ADDR'
|
|
START_ADDRESS = 'START_ADDRESS'
|
|
STRUCTURE = 'STRUCTURE'
|
|
SYMBOL = 'SYMBOL'
|
|
SYMBOL_TABLE = 'SYMBOL_TABLE'
|
|
TIMESTAMP = 'TIMESTAMP'
|
|
TOOL = 'TOOL'
|
|
TO_ADDRESS = 'TO_ADDRESS'
|
|
TREE = 'TREE'
|
|
TYPE = 'TYPE'
|
|
TYPEINFO_CMT = 'TYPEINFO_CMT'
|
|
TYPE_DEF = 'TYPE_DEF'
|
|
UNION = 'UNION'
|
|
USER = 'USER'
|
|
USER_DEFINED = 'USER_DEFINED'
|
|
VALUE = 'VALUE'
|
|
VARIABLE_LENGTH = 'VARIABLE_LENGTH'
|
|
ZERO_PAD = 'ZERO_PAD'
|
|
|