Created
November 18, 2019 21:11
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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