Skip to content

Instantly share code, notes, and snippets.

@edmcman
Created July 26, 2019 15:59
Show Gist options
  • Save edmcman/cfa46c393ac22c19ef288cfbdbdc6006 to your computer and use it in GitHub Desktop.
Save edmcman/cfa46c393ac22c19ef288cfbdbdc6006 to your computer and use it in GitHub Desktop.
Dump Ghidra PCode
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//Decompile the function at the cursor and its callees, then output facts files corresponding to the pcodes
//@category PCode
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import ghidra.app.decompiler.DecompInterface;
import ghidra.app.decompiler.DecompileException;
import ghidra.app.decompiler.DecompileOptions;
import ghidra.app.decompiler.DecompileResults;
import ghidra.app.script.GhidraScript;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.AbstractFloatDataType;
import ghidra.program.model.data.AbstractIntegerDataType;
import ghidra.program.model.data.Array;
import ghidra.program.model.data.BooleanDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.Enum;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.GenericCallingConvention;
import ghidra.program.model.data.ParameterDefinition;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.Union;
import ghidra.program.model.listing.Function;
import ghidra.program.model.pcode.FunctionPrototype;
import ghidra.program.model.pcode.HighConstant;
import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.pcode.HighGlobal;
import ghidra.program.model.pcode.HighLocal;
import ghidra.program.model.pcode.HighOther;
import ghidra.program.model.pcode.HighParam;
import ghidra.program.model.pcode.HighSymbol;
import ghidra.program.model.pcode.HighVariable;
import ghidra.program.model.pcode.PcodeBlock;
import ghidra.program.model.pcode.PcodeBlockBasic;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.PcodeOpAST;
import ghidra.program.model.pcode.SequenceNumber;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.pcode.VarnodeAST;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.program.model.symbol.SymbolTable;
public class PCodeDumpSF extends GhidraScript {
String SEP = ":";
String TAB = "\t";
String QUOTE = "\"";
Set<Function> toProcess = new HashSet<Function>();
Set<Function> isEP = new HashSet<Function>();
File outputDirectory;
PrintWriter ia;
//HashMap<String, PrintWriter> pws = new HashMap<String, PrintWriter>();
HashSet<String> decls = new HashSet<String>();
HashMap<String, String> pairs;
HashSet<String> types = new HashSet<String>();
HashMap<HighVariable,VarnodeAST> extraGlobals = new HashMap<HighVariable,VarnodeAST>();
@Override
protected void run() throws Exception {
PluginTool tool = state.getTool();
if (tool == null) {
println("Script is not running in GUI");
}
outputDirectory = askDirectory("Select Directory for Results", "OK");
try {
File f = new File(outputDirectory,currentProgram.getName()+".facts");
ia = new PrintWriter(f);
//pws.put("input_assist.dl", ia);
//ia.println("table S2N[string, int]");
//File f2 = new File(outputDirectory, "S2N.facts");
//PrintWriter pw = new PrintWriter(f2);
//pws.put("S2N", pw);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
DecompileOptions options = new DecompileOptions();
DecompInterface ifc = new DecompInterface();
ifc.setOptions(options);
ifc.setSimplificationStyle("decompile");
if (!ifc.openProgram(this.currentProgram)) {
throw new DecompileException("Decompiler", "Unable to initialize: "+ifc.getLastMessage());
}
toProcess = new HashSet<Function>();
Function func = null; //this.getFunctionContaining(this.currentAddress);
if (func != null) {
collectFunctions(func);
isEP.add(func);
} else {
for (Function f : this.currentProgram.getFunctionManager().getFunctions(true)) {
collectFunctions(f);
isEP.add(f);
}
for (Function f : this.currentProgram.getFunctionManager().getExternalFunctions()) {
collectFunctions(f);
}
}
for (Function f : toProcess) {
processFunction(ifc, f);
if (monitor.isCancelled()) break;
}
closeFiles();
}
private void collectFunctions(Function f) {
if (toProcess.contains(f)) return;
toProcess.add(f);
Set<Function> calledFunctions = f.getCalledFunctions(monitor);
for (Function function : calledFunctions) {
collectFunctions(function);
}
}
protected void processFunction(DecompInterface ifc, Function f) {
pairs = new HashMap<String, String>();
System.out.println("processing "+f.getName()+SEP+f.getEntryPoint());
SymbolIterator externalSymbols = f.getProgram().getSymbolTable().getSymbols(f.getName());
while (externalSymbols.hasNext()) {
Symbol next = externalSymbols.next();
if (!next.isExternal()) {
Address address = next.getAddress();
export("HFUNC_LOCAL_EP", f.getEntryPoint().toString(), address.toString());
}
}
HighFunction high = getHighFunction(ifc, f);
if (high == null) {
String id = funcID(f);
export("HFUNC_FUNC", id, id);
export("HFUNC_TOSTR", id, id);
export("HFUNC_PROTO", id, id);
export("HFUNC_EP", id, f.getEntryPoint().toString());
export("HFUNC_ISEXT", id, "true");
return;
}
HashSet<PcodeOp> set = new HashSet<PcodeOp>();
Iterator<PcodeOpAST> opiter = high.getPcodeOps();
while (opiter.hasNext()) {
PcodeOpAST op = opiter.next();
if (op != null) {
set.add(op);
exportPcode(high, op);
}
}
exportPcodeOpSequence(high, set);
exportHighFunction(high);
}
private void closeFiles() {
//for (PrintWriter pw : pws.values()) {
// pw.flush();
// pw.close();
//}
ia.close();
}
private HighFunction getHighFunction(DecompInterface ifc, Function func) {
DecompileResults res = ifc.decompileFunction(func, 300, null);
HighFunction high = res.getHighFunction();
if (high == null) {
System.err.println(func+" returned null HighFunction");
}
return high;
}
private void export(String label, String key, String value) {
key = key.replaceAll(QUOTE, "'");
//value = value.replaceAll(QUOTE, "'");
if (!decls.contains(label)) {
ia.println("table "+label+"[string, string]");
decls.add(label);
}
if (!pairs.containsKey(label+key)) {
ia.println(label+"["+QUOTE+key+QUOTE+","+QUOTE+value+QUOTE+"]");
pairs.put(label+key, value);
}
}
private void exportL(String label, String key, long value) {
key = key.replaceAll(QUOTE, "'");
if (!decls.contains(label)) {
ia.println("table " + label + "[string, int]");
decls.add(label);
}
if (!pairs.containsKey(label + key)) {
ia.println(label + "[" + QUOTE + key + QUOTE + "," + value + "]");
pairs.put(label + key, Long.toString(value));
}
}
private void exportN(String label, String key, int index, String value) {
key = key.replaceAll(QUOTE, "'");
value = value.replaceAll(QUOTE, "'");
if (!decls.contains(label)) {
if (value.equals("")) {
ia.println("table "+label+"[string, int]");
} else {
ia.println("table "+label+"[string, int, string]");
}
decls.add(label);
}
if (!pairs.containsKey(label+key+index)) {
if (value.equals("")) {
ia.println(label+"["+QUOTE+key+QUOTE+","+index+"]");
} else {
ia.println(label+"["+QUOTE+key+QUOTE+","+index+","+QUOTE+value+QUOTE+"]");
}
pairs.put(label+key+index, value);
}
}
private void exportNL(String label, String key, int index, long value) {
key = key.replaceAll(QUOTE, "'");
if (!decls.contains(label)) {
ia.println("table " + label + "[string, int, int]");
decls.add(label);
}
if (!pairs.containsKey(label + key + index)) {
ia.println(label + "[" + QUOTE + key + QUOTE + "," + index + "," + value + "]");
pairs.put(label + key + index, Long.toString(value));
}
}
private void exportPcode(HighFunction hfn, PcodeOpAST op) {
SequenceNumber sn = op.getSeqnum();
String outstr = op.toString();
//if (sn != null) {
// outstr = sn.getTarget()+SEP+sn.getTime();
//}
String id = pcodeID(hfn,op);
export("PCODE_TOSTR", id, funcID(hfn.getFunction())+SEP+outstr);
export("PCODE_MNEMONIC", id, op.getMnemonic());
export("PCODE_OPCODE", id, Integer.toString(op.getOpcode()));
export("PCODE_PARENT", id, bbID(hfn,op.getParent()));
export("PCODE_TARGET", id, op.getSeqnum().getTarget().toString());
exportN("PCODE_INPUT_COUNT", id, op.getNumInputs(), "");
for (int i = 0; i < op.getNumInputs(); ++i) {
VarnodeAST vni = (VarnodeAST) op.getInput(i);
if (vni != null) {
// OK, this is a little weird, but PTRSUBs with first arg == 0
// are (usually) global variables at address == second arg
if (op.getMnemonic().equals("PTRSUB") && (i == 0)) {
if (vni.getAddress().getOffset() == 0) {
VarnodeAST next = (VarnodeAST) op.getInput(1);
HighVariable high = next.getHigh();
if (high != null) {
extraGlobals.put(high, next);
}
}
}
exportN("PCODE_INPUT", id, i, vnodeID(hfn,vni));
exportVarnode(hfn,vni);
}
}
VarnodeAST vno = (VarnodeAST) op.getOutput();
if (vno != null) {
export("PCODE_OUTPUT", id, vnodeID(hfn,vno));
exportVarnode(hfn, vno);
}
}
private void exportVarnode(HighFunction hfn, VarnodeAST vn) {
String id = vnodeID(hfn,vn);
export("VNODE_ADDRESS", id, vn.getAddress().toString());
if (vn.isAddress()) {
export("VNODE_IS_ADDRESS", id, "true");
}
if (vn.isAddrTied()) {
export("VNODE_IS_ADDRTIED", id, "true");
}
export("VNODE_PC_ADDRESS", id, vn.getPCAddress().toString());
export("VNODE_DESC", id, vn.toString());
long offset = vn.getOffset();
exportL("VNODE_OFFSET", id, offset);
if (offset < Integer.MAX_VALUE && offset > Integer.MIN_VALUE) {
exportL("VNODE_OFFSET_N", id, offset);
}
export("VNODE_SIZE", id, Integer.toString(vn.getSize()));
export("VNODE_SPACE", id, vn.getAddress().getAddressSpace().getName());
HighVariable hv = vn.getHigh();
if (hv == null) {
//export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.toString());
export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.getPCAddress().toString()+SEP+vn.toString());
} else {
if (hv instanceof HighConstant && hv.getDataType() instanceof Pointer) {
if (offset != 0) {
extraGlobals.put(hv, vn);
}
}
//export("VNODE_TOSTR", id, funcID(hfn.getFunction())+hvarName(hfn,hv));
export("VNODE_TOSTR", id, funcID(hfn.getFunction())+SEP+vn.getPCAddress().toString()+SEP+hvarName(hfn,hv));
export("VNODE_HVAR", id, hvarID(hfn,hv));
exportHighVariable(hfn, hv, true);
}
if (vn.getDef() != null) {
export("VNODE_DEF", id, pcodeID(hfn, vn.getDef()));
}
}
private void exportHighVariable(HighFunction hfn, HighVariable hv, boolean dontDescend) {
String id = hvarID(hfn,hv);
export("HVAR_NAME", id, hvarName(hfn,hv));
export("HVAR_SIZE", id, Integer.toString(hv.getSize()));
if (hv instanceof HighGlobal) {
export("HVAR_CLASS", id, "global");
}
if (hv instanceof HighLocal) {
export("HVAR_CLASS", id, "local");
Address pcAddress = ((HighLocal)hv).getPCAddress();
if (pcAddress != null) {
export("HVAR_SCOPE", id, pcAddress.toString());
}
}
if (hv instanceof HighConstant) {
export("HVAR_CLASS", id, "constant");
}
if (hv instanceof HighOther) {
export("HVAR_CLASS", id, "other");
}
DataType dataType = hv.getDataType();
if (dataType != null) {
export("HVAR_TYPE", id, dtID(dataType));
exportType(dataType);
}
if (!dontDescend) {
VarnodeAST representative = (VarnodeAST) hv.getRepresentative();
if (representative != null) {
export("HVAR_REPRESENTATIVE", id, vnodeID(hfn,representative));
exportVarnode(hfn, representative);
}
Varnode[] instances = hv.getInstances();
for (Varnode varnode : instances) {
exportVarnode(hfn, (VarnodeAST)varnode);
}
}
}
private void exportType(DataType dataType) {
String id = dtID(dataType);
if (types.contains(id)) return;
types.add(id);
export("TYPE_NAME", id, id);
exportN("TYPE_LENGTH", id, dataType.getLength(), "");
while (dataType instanceof TypeDef) {
TypeDef typedef = (TypeDef) dataType;
dataType = typedef.getBaseDataType();
}
if (dataType instanceof Pointer) {
export("TYPE_POINTER", id, "true");
DataType baseType = ((Pointer) dataType).getDataType();
if (baseType != null) {
export("TYPE_POINTER_BASE", id, dtID(baseType));
exportType(baseType);
} else {
System.err.println("TEST");
}
}
if (dataType instanceof Array) {
export("TYPE_ARRAY", id, "true");
Array arr = (Array) dataType;
export("TYPE_ARRAY_BASE", id, dtID(arr.getDataType()));
exportN("TYPE_ARRAY_N", id, arr.getNumElements(), "");
exportN("TYPE_ARRAY_ELEMENT_LENGTH", id, arr.getElementLength(), "");
exportType(arr.getDataType());
}
if (dataType instanceof Structure) {
export("TYPE_STRUCT", id, "true");
Structure struct = (Structure) dataType;
exportN("TYPE_STRUCT_FIELD_COUNT", id, struct.getNumComponents(), "");
for (int i = 0; i < struct.getNumComponents(); i++) {
DataTypeComponent dtc = struct.getComponent(i);
exportComponent("TYPE_STRUCT", id, i, dtc);
}
}
if (dataType instanceof Union) {
export("TYPE_UNION", id, "true");
Union union = (Union) dataType;
exportN("TYPE_UNION_FIELD_COUNT", id, union.getNumComponents(), "");
for (int i = 0; i < union.getNumComponents(); i++) {
DataTypeComponent dtc = union.getComponent(i);
exportComponent("TYPE_UNION", id, i, dtc);
}
}
if (dataType instanceof FunctionDefinition) {
export("TYPE_FUNC", id, "true");
FunctionDefinition fd = (FunctionDefinition) dataType;
export("TYPE_FUNC_RET", id, fd.getReturnType().toString());
exportType(fd.getReturnType());
export("TYPE_FUNC_VARARGS", id, Boolean.toString(fd.hasVarArgs()));
ParameterDefinition[] arguments = fd.getArguments();
exportN("TYPE_FUNC_PARAM_COUNT", id, arguments.length, "");
for (int i = 0; i < arguments.length; i++) {
exportN("TYPE_FUNC_PARAM", id, i, arguments[i].toString());
exportType(arguments[i].getDataType());
}
}
if (dataType instanceof BooleanDataType) {
export("TYPE_BOOLEAN", id, "true");
}
if (dataType instanceof AbstractIntegerDataType) {
export("TYPE_INTEGER", id, "true");
}
if (dataType instanceof AbstractFloatDataType) {
export("TYPE_FLOAT", id, "true");
}
if (dataType instanceof Enum) {
export("TYPE_ENUM", id, "true");
}
}
private void exportComponent(String label, String id, int i, DataTypeComponent dtc) {
String dtcid = dtID(dtc.getDataType());
exportN(label+"_FIELD", id, i, dtcid);
exportNL(label+"_OFFSET", id, i, dtc.getOffset());
exportNL(label+"_OFFSET_N", id, i, dtc.getOffset());
if (dtc.getFieldName() != null) {
exportN(label+"_FIELD_NAME", id, i, dtc.getFieldName());
exportN(label+"_FIELD_NAME_BY_OFFSET", id, dtc.getOffset(), dtc.getFieldName());
}
exportType(dtc.getDataType());
}
private void exportHighFunction(HighFunction hfn) {
for (PcodeBlockBasic bb : hfn.getBasicBlocks()) {
String bbid = bbID(hfn,bb);
export("BB_HFUNC", bbid, hfuncID(hfn));
if (bb.getStart() != null) {
export("BB_START", bbid, bb.getStart().toString());
}
for (int i = 0; i < bb.getInSize(); i++) {
export("BB_IN", bbid, bbID(hfn,bb.getIn(i)));
}
for (int i = 0; i < bb.getOutSize(); i++) {
export("BB_OUT", bbid, bbID(hfn,bb.getOut(i)));
}
if (bb.getOutSize() > 1) {
export("BB_TOUT", bbid, bbID(hfn,bb.getTrueOut()));
export("BB_FOUT", bbid, bbID(hfn,bb.getFalseOut()));
}
}
String id = hfuncID(hfn);
export("HFUNC_FUNC", id, funcID(hfn.getFunction()));
export("HFUNC_TOSTR", id, funcID(hfn.getFunction()));
export("HFUNC_CSPEC", id, hfn.getCompilerSpec().toString());
export("HFUNC_LANG", id, hfn.getLanguage().toString());
export("HFUNC_EP", id, hfn.getFunction().getEntryPoint().toString());
FunctionPrototype proto = hfn.getFunctionPrototype();
if (proto != null) {
export("HFUNC_PROTO", id, funcID(hfn.getFunction()));
exportPrototype(hfn, proto, funcID(hfn.getFunction()));
}
Function f = hfn.getFunction();
Function thunk = f.getThunkedFunction(false);
if (thunk != null && thunk.isExternal()) {
export("HFUNC_ISEXT", id, "true");
}
if (isEP.contains(f)) {
export("HFUNC_ISEP", id, "true");
}
Iterator<HighSymbol> symbols = hfn.getLocalSymbolMap().getSymbols();
while (symbols.hasNext()) {
HighSymbol hs = symbols.next();
String hsid = hsID(hfn,hs);
export("SYMBOL_HFUNC", hsid, id);
HighVariable hv = hs.getHighVariable();
if (hv != null) {
export("SYMBOL_HVAR", hsid, hvarID(hfn,hv));
exportHighVariable(hfn, hv, false);
}
}
}
private void exportPrototype(HighFunction hfn, FunctionPrototype proto, String id) {
exportN("PROTO_PARAMETER_COUNT", id, proto.getNumParams(), "");
for (int i = 0; i < proto.getNumParams(); i++) {
HighParam param = proto.getParam(i);
exportN("PROTO_PARAMETER", id, i, hvarID(hfn,param));
exportN("PROTO_PARAMETER_S", id, i, hvarID(hfn,param));
export("PROTO_PARAMETER_DATATYPE", hvarID(hfn,param), dtID(param.getDataType()));
exportType(param.getDataType());
VarnodeAST rep = (VarnodeAST) param.getRepresentative();
export("PROTO_REPRESENTATIVE", hvarID(hfn,param), vnodeID(hfn, rep));
exportVarnode(hfn, rep);
}
/*
ParameterDefinition[] parameterDefinitions = proto.getParameterDefinitions();
if (parameterDefinitions != null) {
for (ParameterDefinition def : parameterDefinitions) {
exportN("PROTO_PARAMETER_DEFINITION", id, def.getOrdinal(), def.getName());
export("PROTO_PARAMETER_DATATYPE", def.getName(), dtID(def.getDataType()));
exportType(def.getDataType());
}
}
*/
DataType returnType = proto.getReturnType();
export("PROTO_RETTYPE", id, dtID(returnType));
exportType(returnType);
GenericCallingConvention cc = proto.getGenericCallingConvention();
if (cc != null) {
export("PROTO_CALLING_CONVENTION", id, cc.toString());
}
export("PROTO_IS_VOID", id, Boolean.toString(proto.hasNoReturn()));
export("PROTO_HAS_THIS", id, Boolean.toString(proto.hasThisPointer()));
export("PROTO_IS_VARARG", id, Boolean.toString(proto.isVarArg()));
export("PROTO_IS_INLINE", id, Boolean.toString(proto.isInline()));
export("PROTO_IS_CONSTRUCTOR", id, Boolean.toString(proto.isConstructor()));
export("PROTO_IS_DESTRUCTOR", id, Boolean.toString(proto.isDestructor()));
}
private void exportPcodeOpSequence(HighFunction hfn, HashSet<PcodeOp> set) {
Iterator<PcodeOpAST> opiter = hfn.getPcodeOps();
HashSet<PcodeBlockBasic> seenParents = new HashSet<PcodeBlockBasic>();
HashMap<PcodeBlock, PcodeOp> first = new HashMap<PcodeBlock, PcodeOp>();
HashMap<PcodeBlock, PcodeOp> last = new HashMap<PcodeBlock, PcodeOp>();
while (opiter.hasNext()) {
PcodeOpAST op = opiter.next();
PcodeBlockBasic parent = op.getParent();
if (seenParents.contains(parent)) {
continue;
}
Iterator<PcodeOp> iterator = parent.getIterator();
PcodeOp prev = null;
PcodeOp next = null;
while (iterator.hasNext()) {
next = iterator.next();
if (prev == null && set.contains(next)) {
first.put(parent, next);
}
if (prev != null && set.contains(prev) && set.contains(next)) {
export("PCODE_NEXT", pcodeID(hfn, prev), pcodeID(hfn, next));
}
prev = next;
}
if (next != null && set.contains(next)) {
last.put(parent, next);
}
seenParents.add(parent);
}
for (PcodeBlock block : first.keySet()) {
PcodeOpAST ast = (PcodeOpAST) first.get((block));
export("BB_FIRST", bbID(hfn, block), pcodeID(hfn, ast));
}
for (PcodeBlock block : last.keySet()) {
export("BB_LAST", bbID(hfn, block), pcodeID(hfn, last.get(block)));
}
}
private String pcodeID(HighFunction hfn, PcodeOp op) {
SequenceNumber sn = op.getSeqnum();
if (sn != null) {
return hfuncID(hfn)+SEP+sn.getTarget()+SEP+sn.getTime();
}
return hfuncID(hfn)+SEP+"NO_SEQNUM"+SEP+op.toString();
}
private String vnodeID(HighFunction hfn, VarnodeAST vn) {
return hfuncID(hfn)+SEP+Integer.toString(vn.getUniqueId());
}
private String hvarID(HighFunction hfn, HighVariable hv) {
return hfuncID(hfn)+SEP+hvarName(hfn, hv);
}
private String hvarName(HighFunction hfn, HighVariable hv) {
if (hv.getName() == null) {
SymbolTable symbolTable = hfn.getFunction().getProgram().getSymbolTable();
Varnode rep = hv.getRepresentative();
Address addr = rep.getAddress();
if (extraGlobals.containsKey(hv)) {
VarnodeAST vn = extraGlobals.get(hv);
addr = currentAddress.getNewAddress(vn.getOffset());
}
Symbol symbol = symbolTable.getPrimarySymbol(addr);
if (symbol == null) {
return Integer.toString(hv.hashCode());
}
export("HVAR_CLASS", hfuncID(hfn)+SEP+symbol.getName(), "global");
return symbol.getName();
}
return hv.getName();
}
private String hsID(HighFunction hfn, HighSymbol hs) {
return hfuncID(hfn)+SEP+hs.getName();
}
private String funcID(Function fn) {
return fn.getName(true)+"@"+fn.getEntryPoint();
}
private String hfuncID(HighFunction fn) {
return fn.toString();
}
private String bbID(HighFunction hfn, PcodeBlock bb) {
if (bb.getStart() != null) {
return hfuncID(hfn)+SEP+bb.hashCode();
}
return hfuncID(hfn)+SEP+"unknown block";
}
private String dtID(DataType dt) {
if (dt.getName() != null) {
return dt.getName().replaceAll(" ", "");
}
return dt.toString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment