Skip to content

Instantly share code, notes, and snippets.

@ab9rf
Created November 18, 2019 21:11
Show Gist options
  • Save ab9rf/f3909401671e679cd03f059d93a26e8a to your computer and use it in GitHub Desktop.
Save ab9rf/f3909401671e679cd03f059d93a26e8a to your computer and use it in GitHub Desktop.
A script to use with ghidra for importing DF structures into ghidra. Does not completely work yet; only imports global symbols at the moment.
#TODO write a description for this script
#@author
#@category DwarfFortress
#@keybinding
#@menupath
#@toolbar
#import xml.etree.ElementTree as ET
from ghidra.program.model.data import CategoryPath
from ghidra.program.model.data import StructureDataType
from ghidra.program.model.data import DataTypeConflictHandler
from ghidra.program.model.symbol import SourceType
from ghidra.util.xml import XmlUtilities
from java.io import File
from org.jdom.filter import ElementFilter
import re
importver = 'v0.44.12 SDL win64'
translate = {
'padding': 'undefined',
'bool': 'byte',
's-float': 'float',
'ptr-string': 'char*',
'uint32_t': 'uint',
'stl-fstream': 'stl::fstream',
'int8_t': 'byte',
'long': 'longlong',
'uint16_t': 'ushort',
'int16_t': 'short',
'uint8_t': 'ubyte',
'int64_t': 'longlong',
'int32_t': 'int',
'stl-string': 'std::string'
}
class DFField:
def __init__(self, type, name, comment=None):
self.name = name
self.type = type
self.comment = comment
class DFStruct:
def __init__(self, type, name, comment=None):
self.name = name
self.type = type
self.comment = comment
self.fields = {}
def addField(self, type, name, comment=None):
self.fields[name] = DFField(type, name, comment)
def elementFilter(str):
return ElementFilter(str)
def vec (c,typ):
return c + '<' + typ + '>'
def ptr (typ):
return typ + '*'
def arr (cnt,typ):
return typ + '[' + cnt + ']'
def process(fld, typ, nam):
ftype = typ
fname = nam
fcomm = fld.getAttributeValue('comment')
if (ftype == 'bitfield' or ftype == 'compound'):
ftype = fld.getAttributeValue('type-name')
elif (ftype == 'stl-vector' or ftype == 'stl-deque' or
ftype == 'stl-set' or ftype == 'stl-bit-vector' or
ftype == 'df-flagarray' or ftype == 'df-static-flagarray' or
ftype == 'df-array' or ftype == 'df-linked-list'):
vtype = fld.getAttributeValue('type-name')
if (not vtype):
ptype = fld.getAttributeValue('pointer-type')
if (ptype):
vtype = ptr(ptype)
elif fld.getChild('pointer'):
aname = 'T_' + fname
tt = DFStruct(None, aname, fld.getAttributeValue('comment'))
vtype = make_type(tt, fld.getChild('pointer'))
else:
vtype = vec(ftype,'undefined')
ftype = vec(ftype,vtype)
elif (ftype == 'static-array'):
ptype = fld.getAttributeValue('type-name')
count = fld.getAttributeValue('count')
aname = 'T_' + fname
if (not ptype):
tt = DFStruct(None, aname, fld.getAttributeValue('comment'))
ptype = make_type(tt, fld)
ftype = arr(count,ptype)
elif (ftype == 'pointer'):
ptype = fld.getAttributeValue('type-name')
aname = 'T_' + fname
if (not ptype):
tt = DFStruct(None, aname, fld.getAttributeValue('comment'))
ptype = make_type(tt, fld)
ftype = ptr(ptype)
elif (ftype == 'compound'):
ctype = fld.getAttributeValue('type-name')
aname = 'T_' + fname
if (not ctype):
tt = DFStruct(None, aname, fld.getAttributeValue('comment'))
ctype = make_type(tt, fld)
ftype = ctype
elif (ftype == 'enum'):
aname = 'T_' + fname
btype = fld.getAttributeValue('base-type') or 'int32_t'
etype = DFStruct(btype, aname, fld.getAttributeValue('comment'))
ftype = etype.name
elif (ftype == 'static-string'):
cnt = fld.getAttributeValue('size')
ftype = arr(cnt, 'char')
elif (ftype in translate):
ftype = translate[ftype]
return ftype
def make_type(typ, spec):
anon = 0
for fld in spec.getChildren():
ftype = fld.getName()
if (ftype == 'virtual-methods' or ftype == 'custom-methods'):
continue
if (ftype == 'code-helper' or ftype == 'extra-include' or ftype == 'comment'):
continue
fname = fld.getAttributeValue('name')
if not fname:
anon = anon + 1
fname = 'anon_' + str(anon)
ftype = process(fld, ftype, fname)
fcomm = fld.getAttributeValue('comment')
typ.addField(ftype, fname, fcomm)
return typ.name
pgm = getCurrentProgram()
st = pgm.getSymbolTable()
ns = pgm.getGlobalNamespace()
af = pgm.getAddressFactory()
def addtype():
pgm = getCurrentProgram()
dtm = pgm.getDataTypeManager()
cpr = dtm.getRootCategory().getCategoryPath()
dfh_cp = CategoryPath(cpr,"dfhack")
dfh_cat = dtm.createCategory(dfh_cp)
newtype = StructureDataType(dfh_cp, "newtype", 0)
fieldtype = dtm.getDataType(cpr, "word")
newtype.add(fieldtype, 2, "field1", "")
dtm.addDataType(newtype,DataTypeConflictHandler.REPLACE_HANDLER)
def main():
dir = askDirectory("Directory", "Path to df-structures repo:")
print dir
getXML = lambda(f): XmlUtilities.readDocFromFile(File(dir, f))
tree = getXML('symbols.xml')
target = None
ent = tree.getDescendants(elementFilter('symbol-table'))
for e in ent:
name = e.getAttributeValue('name')
print name
if name == importver:
target = e
break
for ga in target.getDescendants(elementFilter('global-address')):
sym = ga.getAttributeValue('name')
val = ga.getAttributeValue('value')
addr = af.getAddress(val)
l = st.createLabel(addr, sym, SourceType.IMPORTED)
files = dir.listFiles()
fmatcher = re.compile ( r'df\.(.*)\.xml' )
types = {}
for f in files:
mat = fmatcher.match(f.getName())
if mat:
print 'Reading ' + f.getName()
data = XmlUtilities.readDocFromFile(f).getRootElement()
for e in data.getChildren():
tag = e.getName()
# print '>' + tag
n = e.getAttributeValue('type-name')
on = e.getAttributeValue('original-name')
t = e.getAttributeValue('base-type') or 'int32_t'
c = e.getAttributeValue('comment')
typ = DFStruct(t,on or n,c)
if tag == 'bitfield-type' or tag == 'enum-type':
if t: typedef[n] = typ
elif tag == 'class-type' or tag == 'struct-type':
sup = e.getAttributeValue('inherits-from')
if (sup):
typ.super = sup
types[n] = make_type(typ, e)
elif tag == 'global-object':
gln = e.getAttributeValue('name')
if n:
ftype = process(e, n, gln)
else:
tt = DFStruct(None, 'T_' + gln)
ftype = make_type(tt, e)
print 'global ' + gln + ' is type ' + ftype
for t in types:
print t, types[t]
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment