string debugging tags

This commit is contained in:
caheckman 2020-04-23 12:43:21 -04:00
parent 547a4f2ab5
commit 9ea9790e88
5 changed files with 263 additions and 155 deletions

View file

@ -232,7 +232,7 @@ Datatype *CastStrategyC::castStandard(Datatype *reqtype,Datatype *curtype,
isptr = true; isptr = true;
} }
if (curtype == reqtype) return (Datatype *)0; // Different typedefs could point to the same type if (curtype == reqtype) return (Datatype *)0; // Different typedefs could point to the same type
if ((reqbase->getMetatype()==TYPE_VOID)||(reqbase->getMetatype()==TYPE_VOID)) if ((reqbase->getMetatype()==TYPE_VOID)||(curtype->getMetatype()==TYPE_VOID))
return (Datatype *)0; // Don't cast from or to VOID return (Datatype *)0; // Don't cast from or to VOID
if (reqbase->getSize() != curbase->getSize()) { if (reqbase->getSize() != curbase->getSize()) {
if (reqbase->isVariableLength() && isptr && reqbase->hasSameVariableBase(curbase)) { if (reqbase->isVariableLength() && isptr && reqbase->hasSameVariableBase(curbase)) {
@ -375,7 +375,7 @@ Datatype *CastStrategyJava::castStandard(Datatype *reqtype,Datatype *curtype,
if ((reqbase->getMetatype()==TYPE_PTR)||(curbase->getMetatype()==TYPE_PTR)) if ((reqbase->getMetatype()==TYPE_PTR)||(curbase->getMetatype()==TYPE_PTR))
return (Datatype *)0; // There must be explicit cast op between objects, so assume no cast necessary return (Datatype *)0; // There must be explicit cast op between objects, so assume no cast necessary
if ((reqbase->getMetatype()==TYPE_VOID)||(reqbase->getMetatype()==TYPE_VOID)) if ((reqbase->getMetatype()==TYPE_VOID)||(curtype->getMetatype()==TYPE_VOID))
return (Datatype *)0; // Don't cast from or to VOID return (Datatype *)0; // Don't cast from or to VOID
if (reqbase->getSize() != curbase->getSize()) return reqtype; // Always cast change in size if (reqbase->getSize() != curbase->getSize()) return reqtype; // Always cast change in size
switch(reqbase->getMetatype()) { switch(reqbase->getMetatype()) {

View file

@ -170,12 +170,13 @@ int main(int argc,char **argv)
{ {
const char *initscript = (const char *)0; const char *initscript = (const char *)0;
{
vector<string> extrapaths; vector<string> extrapaths;
int4 i=1; int4 i = 1;
while((i<argc)&&(argv[i][0]=='-')) { while ((i < argc) && (argv[i][0] == '-')) {
if (argv[i][1]=='i') if (argv[i][1] == 'i')
initscript = argv[++i]; initscript = argv[++i];
else if (argv[i][1]=='s') else if (argv[i][1] == 's')
extrapaths.push_back(argv[++i]); extrapaths.push_back(argv[++i]);
i += 1; i += 1;
} }
@ -183,7 +184,7 @@ int main(int argc,char **argv)
string ghidraroot = FileManage::discoverGhidraRoot(argv[0]); string ghidraroot = FileManage::discoverGhidraRoot(argv[0]);
if (ghidraroot.size() == 0) { if (ghidraroot.size() == 0) {
const char *sleighhomepath = getenv("SLEIGHHOME"); const char *sleighhomepath = getenv("SLEIGHHOME");
if (sleighhomepath == (const char *)0) { if (sleighhomepath == (const char*) 0) {
if (extrapaths.empty()) { if (extrapaths.empty()) {
cerr << "Could not discover root of Ghidra installation" << endl; cerr << "Could not discover root of Ghidra installation" << endl;
exit(1); exit(1);
@ -192,7 +193,8 @@ int main(int argc,char **argv)
else else
ghidraroot = sleighhomepath; ghidraroot = sleighhomepath;
} }
startDecompilerLibrary(ghidraroot.c_str(),extrapaths); startDecompilerLibrary(ghidraroot.c_str(), extrapaths);
}
IfaceStatus *status; IfaceStatus *status;
try { try {

View file

@ -111,17 +111,18 @@ void StringManager::saveXml(ostream &s) const
/// Read \<stringmanage> tag, with \<string> sub-tags. /// Read \<stringmanage> tag, with \<string> sub-tags.
/// \param el is the root tag element /// \param el is the root tag element
/// \param m is the manager for looking up AddressSpaces /// \param m is the manager for looking up AddressSpaces
void StringManager::restoreXml(const Element *el,const AddrSpaceManager *m) void StringManager::restoreXml(const Element *el, const AddrSpaceManager *m)
{ {
const List &list(el->getChildren()); const List &list(el->getChildren());
List::const_iterator iter; List::const_iterator iter1;
iter = list.begin(); for (iter1 = list.begin(); iter1 != list.end(); ++iter1) {
Address addr = Address::restoreXml(*iter, m); List::const_iterator iter2 = (*iter1)->getChildren().begin();
++iter; Address addr = Address::restoreXml(*iter2, m);
++iter2;
StringData &stringData(stringMap[addr]); StringData &stringData(stringMap[addr]);
stringData.isTruncated = xml_readbool((*iter)->getAttributeValue("trunc")); stringData.isTruncated = xml_readbool((*iter2)->getAttributeValue("trunc"));
istringstream is((*iter)->getContent()); istringstream is((*iter2)->getContent());
int4 val; int4 val;
char c1, c2; char c1, c2;
is >> ws; is >> ws;
@ -146,6 +147,7 @@ void StringManager::restoreXml(const Element *el,const AddrSpaceManager *m)
c1 = is.get(); c1 = is.get();
c2 = is.get(); c2 = is.get();
} }
}
} }
/// \param buffer is the byte buffer /// \param buffer is the byte buffer
@ -285,6 +287,9 @@ const vector<uint1> &StringManagerUnicode::getStringData(const Address &addr,Dat
stringData.isTruncated = false; stringData.isTruncated = false;
isTrunc = false; isTrunc = false;
if (charType->isOpaqueString()) // Cannot currently test for an opaque encoding
return stringData.byteData; // Return the empty buffer
int4 curBufferSize = 0; int4 curBufferSize = 0;
int4 charsize = charType->getSize(); int4 charsize = charType->getSize();
bool foundTerminator = false; bool foundTerminator = false;

View file

@ -61,6 +61,7 @@ public class DecompileCallback {
boolean isTruncated; // Did we truncate the string boolean isTruncated; // Did we truncate the string
public byte[] byteData; // The UTF8 encoding of the string public byte[] byteData; // The UTF8 encoding of the string
} }
private DecompileDebug debug; private DecompileDebug debug;
private Program program; private Program program;
private Listing listing; private Listing listing;
@ -725,7 +726,6 @@ public class DecompileCallback {
resBuf.append("\n"); // Make into official XML document resBuf.append("\n"); // Make into official XML document
String res = resBuf.toString(); String res = resBuf.toString();
if (debug != null) { if (debug != null) {
debug.getType(name, res);
debug.getType(type); debug.getType(type);
} }
return res; return res;
@ -1305,6 +1305,9 @@ public class DecompileCallback {
stringVal = stringVal.substring(0, maxChars); stringVal = stringVal.substring(0, maxChars);
} }
stringData.byteData = stringVal.getBytes(utf8Charset); stringData.byteData = stringVal.getBytes(utf8Charset);
if (debug != null) {
debug.getStringData(addr, stringData);
}
return stringData; return stringData;
} }

View file

@ -18,6 +18,7 @@ package ghidra.app.decompiler;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import ghidra.app.decompiler.DecompileCallback.StringData;
import ghidra.app.plugin.processors.sleigh.ContextCache; import ghidra.app.plugin.processors.sleigh.ContextCache;
import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.plugin.processors.sleigh.symbol.ContextSymbol; import ghidra.app.plugin.processors.sleigh.symbol.ContextSymbol;
@ -35,28 +36,34 @@ import ghidra.program.model.symbol.Namespace;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.xml.SpecXmlUtils; import ghidra.util.xml.SpecXmlUtils;
/**
* A container for collecting communication between the decompiler and the Ghidra database,
* as serviced through DecompileCallback during decompilation of a function.
* The query results can then be dumped as an XML document.
* The container is populated through methods that mirror the various methods in DecompileCallback.
*/
public class DecompileDebug { public class DecompileDebug {
private Function func; private Function func; // The function being decompiled
private Program program; private Program program; // The program
private File debugFile; private File debugFile; // The file to dump the XML document to
private ArrayList<Namespace> dbscope; private ArrayList<Namespace> dbscope; // Symbol query: scope
private ArrayList<String> database; private ArrayList<String> database; // description of the symbol
private ArrayList<String> type; private ArrayList<DataType> dtypes; // Data-types queried
private ArrayList<DataType> dtypes; private ArrayList<String> symbol; // Names of code labels
private ArrayList<String> symbol; private ArrayList<String> context; // Tracked register values associated with an address
private ArrayList<String> context; private ArrayList<String> cpool; // Constant pool results
private ArrayList<String> cpool; private ArrayList<String> flowoverride; // Flow overrides associated with an address
private ArrayList<String> flowoverride; private ArrayList<String> inject; // Injection payloads
private ArrayList<String> inject; private TreeSet<ByteChunk> byteset; // Load image bytes
private TreeSet<ByteChunk> byteset; private TreeSet<Address> contextchange; // Addresses at which there is a context change
private TreeSet<Address> contextchange; private TreeMap<Address, StringData> stringmap; // Strings queried with their associated start address
private Register contextRegister; private Register contextRegister; // The global context register
private ProgramContext progctx; private ProgramContext progctx; // Program context
private String comments; private String comments; // All comments associated with the function (in XML form)
private Namespace globalnamespace; private Namespace globalnamespace; // The global namespace
private AddressRange readonlycache; private AddressRange readonlycache; // Current range of addresses with same readonly value (for internal use)
private boolean readonlycacheval; private boolean readonlycacheval; // Current readonly value (for internal use)
private PcodeDataTypeManager dtmanage; private PcodeDataTypeManager dtmanage; // Decompiler's data-type manager
class ByteChunk implements Comparable<ByteChunk> { class ByteChunk implements Comparable<ByteChunk> {
public Address addr; public Address addr;
@ -68,23 +75,29 @@ public class DecompileDebug {
val = new byte[16]; val = new byte[16];
min = (int) ad.getOffset() & 15; min = (int) ad.getOffset() & 15;
int len = v.length - off; int len = v.length - off;
if (min + len >= 16) if (min + len >= 16) {
len = 16 - min; len = 16 - min;
}
max = min + len; max = min + len;
for (int i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i) {
val[i] = 0; val[i] = 0;
for (int i = 0; i < len; ++i) }
for (int i = 0; i < len; ++i) {
val[min + i] = v[off + i]; val[min + i] = v[off + i];
} }
}
public void merge(ByteChunk op2) { public void merge(ByteChunk op2) {
for (int i = op2.min; i < op2.max; ++i) for (int i = op2.min; i < op2.max; ++i) {
val[i] = op2.val[i]; val[i] = op2.val[i];
if (op2.min < min) }
if (op2.min < min) {
min = op2.min; min = op2.min;
if (op2.max > max) }
if (op2.max > max) {
max = op2.max; max = op2.max;
} }
}
@Override @Override
public int compareTo(ByteChunk op2) { public int compareTo(ByteChunk op2) {
@ -97,13 +110,13 @@ public class DecompileDebug {
debugFile = debugf; debugFile = debugf;
dbscope = new ArrayList<Namespace>(); dbscope = new ArrayList<Namespace>();
database = new ArrayList<String>(); database = new ArrayList<String>();
type = new ArrayList<String>();
dtypes = new ArrayList<DataType>(); dtypes = new ArrayList<DataType>();
symbol = new ArrayList<String>(); symbol = new ArrayList<String>();
context = new ArrayList<String>(); context = new ArrayList<String>();
cpool = new ArrayList<String>(); cpool = new ArrayList<String>();
byteset = new TreeSet<ByteChunk>(); byteset = new TreeSet<ByteChunk>();
contextchange = new TreeSet<Address>(); contextchange = new TreeSet<Address>();
stringmap = new TreeMap<Address, StringData>();
flowoverride = new ArrayList<String>(); flowoverride = new ArrayList<String>();
inject = new ArrayList<String>(); inject = new ArrayList<String>();
contextRegister = null; contextRegister = null;
@ -127,8 +140,9 @@ public class DecompileDebug {
public void shutdown(Language pcodelanguage, String xmlOptions) { public void shutdown(Language pcodelanguage, String xmlOptions) {
OutputStream debugStream; OutputStream debugStream;
if (debugFile.exists()) if (debugFile.exists()) {
debugFile.delete(); debugFile.delete();
}
try { try {
debugStream = new BufferedOutputStream(new FileOutputStream(debugFile)); debugStream = new BufferedOutputStream(new FileOutputStream(debugFile));
} }
@ -155,6 +169,7 @@ public class DecompileDebug {
dumpTrackedContext(debugStream); dumpTrackedContext(debugStream);
debugStream.write("</context_points>\n".getBytes()); debugStream.write("</context_points>\n".getBytes());
dumpComments(debugStream); dumpComments(debugStream);
dumpStringData(debugStream);
dumpCPool(debugStream); dumpCPool(debugStream);
dumpConfiguration(debugStream, xmlOptions); dumpConfiguration(debugStream, xmlOptions);
dumpFlowOverride(debugStream); dumpFlowOverride(debugStream);
@ -177,14 +192,16 @@ public class DecompileDebug {
binimage += "\">\n"; binimage += "\">\n";
debugStream.write(binimage.getBytes()); debugStream.write(binimage.getBytes());
dumpBytes(debugStream); dumpBytes(debugStream);
for (int i = 0; i < symbol.size(); ++i) for (String element : symbol) {
debugStream.write((symbol.get(i)).getBytes()); debugStream.write((element).getBytes());
}
debugStream.write("</binaryimage>\n".getBytes()); debugStream.write("</binaryimage>\n".getBytes());
} }
private boolean isReadOnly(Address addr) { private boolean isReadOnly(Address addr) {
if ((readonlycache != null) && (readonlycache.contains(addr))) if ((readonlycache != null) && (readonlycache.contains(addr))) {
return readonlycacheval; return readonlycacheval;
}
MemoryBlock block = program.getMemory().getBlock(addr); MemoryBlock block = program.getMemory().getBlock(addr);
readonlycache = null; readonlycache = null;
readonlycacheval = false; readonlycacheval = false;
@ -221,24 +238,31 @@ public class DecompileDebug {
SpecXmlUtils.encodeStringAttribute(buf, "space", space.getPhysicalSpace().getName()); SpecXmlUtils.encodeStringAttribute(buf, "space", space.getPhysicalSpace().getName());
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "offset", chunk.addr.getOffset() + SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "offset", chunk.addr.getOffset() +
chunk.min); chunk.min);
if (lastreadonly) if (lastreadonly) {
SpecXmlUtils.encodeBooleanAttribute(buf, "readonly", lastreadonly); SpecXmlUtils.encodeBooleanAttribute(buf, "readonly", lastreadonly);
}
buf.append(">\n"); buf.append(">\n");
tagstarted = true; tagstarted = true;
} }
for (int i = 0; i < chunk.min; ++i) for (int i = 0; i < chunk.min; ++i)
{
buf.append(" "); // pad the hex display to 16 bytes buf.append(" "); // pad the hex display to 16 bytes
}
for (int i = chunk.min; i < chunk.max; ++i) { for (int i = chunk.min; i < chunk.max; ++i) {
int hi = (chunk.val[i] >> 4) & 0xf; int hi = (chunk.val[i] >> 4) & 0xf;
int lo = chunk.val[i] & 0xf; int lo = chunk.val[i] & 0xf;
if (hi > 9) if (hi > 9) {
hi += 'a' - 10; hi += 'a' - 10;
else }
else {
hi += '0'; hi += '0';
if (lo > 9) }
if (lo > 9) {
lo += 'a' - 10; lo += 'a' - 10;
else }
else {
lo += '0'; lo += '0';
}
buf.append((char) hi); buf.append((char) hi);
buf.append((char) lo); buf.append((char) lo);
} }
@ -252,24 +276,57 @@ public class DecompileDebug {
lastspace = space; lastspace = space;
} }
} }
if (tagstarted) if (tagstarted) {
buf.append("</bytechunk>\n"); buf.append("</bytechunk>\n");
}
debugStream.write(buf.toString().getBytes()); debugStream.write(buf.toString().getBytes());
} }
// private void dumpTypes(OutputStream debugStream) throws IOException { /**
// StringBuilder buf = new StringBuilder(); * Dump information on strings that were queried by the decompiler.
// buf.append("<typegrp"); * @param debugStream is the stream to write to
// SpecXmlUtils.encodeSignedIntegerAttribute(buf, "structalign", 4); * @throws IOException if any i/o error occurs
// SpecXmlUtils.encodeSignedIntegerAttribute(buf, "enumsize", 4); */
// SpecXmlUtils.encodeBooleanAttribute(buf, "enumsigned", false); private void dumpStringData(OutputStream debugStream) throws IOException {
// buf.append(">\n"); if (stringmap.isEmpty()) {
// // structalign should come out of pcodelanguage.getCompilerSpec() return;
// debugStream.write(buf.toString().getBytes()); }
// for (int i = type.size() - 1; i >= 0; --i) StringBuilder buf = new StringBuilder();
// debugStream.write((type.get(i)).getBytes()); buf.append("<stringmanage>\n");
// debugStream.write("</typegrp>\n".getBytes()); for (Map.Entry<Address, StringData> entry : stringmap.entrySet()) {
// } buf.append("<string>\n<addr");
Varnode.appendSpaceOffset(buf, entry.getKey());
buf.append("/>\n<bytes");
SpecXmlUtils.encodeBooleanAttribute(buf, "trunc", entry.getValue().isTruncated);
buf.append(">\n ");
int count = 0;
for (byte element : entry.getValue().byteData) {
int hi = (element >> 4) & 0xf;
int lo = element & 0xf;
if (hi > 9) {
hi += 'a' - 10;
}
else {
hi += '0';
}
if (lo > 9) {
lo += 'a' - 10;
}
else {
lo += '0';
}
buf.append((char) hi);
buf.append((char) lo);
if (count % 20 == 19) {
buf.append("\n ");
}
}
buf.append("00\n</bytes>\n");
buf.append("</string>\n");
}
buf.append("</stringmanage>\n");
debugStream.write(buf.toString().getBytes());
}
private void dumpDataTypes(OutputStream debugStream) throws IOException { private void dumpDataTypes(OutputStream debugStream) throws IOException {
int intSize = program.getCompilerSpec().getDataOrganization().getIntegerSize(); int intSize = program.getCompilerSpec().getDataOrganization().getIntegerSize();
@ -285,12 +342,15 @@ public class DecompileDebug {
DataTypeDependencyOrderer TypeOrderer = DataTypeDependencyOrderer TypeOrderer =
new DataTypeDependencyOrderer(program.getDataTypeManager(), dtypes); new DataTypeDependencyOrderer(program.getDataTypeManager(), dtypes);
//First output all structures as zero size so to avoid any cyclic dependencies. //First output all structures as zero size so to avoid any cyclic dependencies.
for (DataType dataType : TypeOrderer.getStructList()) for (DataType dataType : TypeOrderer.getStructList()) {
debugStream.write((dtmanage.buildStructTypeZeroSizeOveride(dataType) + "\n").toString().getBytes()); debugStream.write((dtmanage.buildStructTypeZeroSizeOveride(dataType) + "\n").toString().getBytes());
}
//Next, use the dependency stack to output types. //Next, use the dependency stack to output types.
for (DataType dataType : TypeOrderer.getDependencyList()) for (DataType dataType : TypeOrderer.getDependencyList()) {
if (!(dataType instanceof BuiltIn)) //If we don't do this, we have a problem with DataType "string" (array of size=-1) if (!(dataType instanceof BuiltIn)) {
debugStream.write((dtmanage.buildType(dataType, dataType.getLength()) + "\n").toString().getBytes()); debugStream.write((dtmanage.buildType(dataType, dataType.getLength()) + "\n").toString().getBytes());
}
}
debugStream.write("</typegrp>\n".getBytes()); debugStream.write("</typegrp>\n".getBytes());
} }
@ -299,20 +359,24 @@ public class DecompileDebug {
// set associated with the function start // set associated with the function start
// and it is written in xml as if it were // and it is written in xml as if it were
// the default tracking set // the default tracking set
for (int i = 0; i < context.size(); ++i) for (String element : context) {
debugStream.write((context.get(i)).getBytes()); debugStream.write((element).getBytes());
}
} }
private ArrayList<ContextSymbol> getContextSymbols() { private ArrayList<ContextSymbol> getContextSymbols() {
Language lang = program.getLanguage(); Language lang = program.getLanguage();
if (!(lang instanceof SleighLanguage)) if (!(lang instanceof SleighLanguage)) {
return null; return null;
}
ArrayList<ContextSymbol> res = new ArrayList<ContextSymbol>(); ArrayList<ContextSymbol> res = new ArrayList<ContextSymbol>();
ghidra.app.plugin.processors.sleigh.symbol.Symbol[] list = ghidra.app.plugin.processors.sleigh.symbol.Symbol[] list =
((SleighLanguage) lang).getSymbolTable().getSymbolList(); ((SleighLanguage) lang).getSymbolTable().getSymbolList();
for (Symbol element : list) for (Symbol element : list) {
if (element instanceof ContextSymbol) if (element instanceof ContextSymbol) {
res.add((ContextSymbol) element); res.add((ContextSymbol) element);
}
}
return res; return res;
} }
@ -323,8 +387,9 @@ public class DecompileDebug {
*/ */
private void getContextChangePoints(Address addr) { private void getContextChangePoints(Address addr) {
AddressRange addrrange = progctx.getRegisterValueRangeContaining(contextRegister, addr); AddressRange addrrange = progctx.getRegisterValueRangeContaining(contextRegister, addr);
if (addrrange == null) if (addrrange == null) {
return; return;
}
contextchange.add(addrrange.getMinAddress()); contextchange.add(addrrange.getMinAddress());
try { try {
Address nextaddr = addrrange.getMaxAddress().add(1); Address nextaddr = addrrange.getMaxAddress().add(1);
@ -339,13 +404,14 @@ public class DecompileDebug {
* body of the function. Right now we only get the context at the * body of the function. Right now we only get the context at the
* beginning of the function because its difficult to tell where the * beginning of the function because its difficult to tell where the
* context changes. * context changes.
* @param debugStream * @param debugStream is the stream being written to
* @throws IOException * @throws IOException for any i/o error
*/ */
private void dumpPointsetContext(OutputStream debugStream) throws IOException { private void dumpPointsetContext(OutputStream debugStream) throws IOException {
ArrayList<ContextSymbol> ctxsymbols = getContextSymbols(); ArrayList<ContextSymbol> ctxsymbols = getContextSymbols();
if (ctxsymbols == null) if (ctxsymbols == null) {
return; return;
}
ContextCache ctxcache = new ContextCache(); ContextCache ctxcache = new ContextCache();
ctxcache.registerVariable(contextRegister); ctxcache.registerVariable(contextRegister);
int[] buf = new int[ctxcache.getContextSize()]; int[] buf = new int[ctxcache.getContextSize()];
@ -359,22 +425,27 @@ public class DecompileDebug {
StringBuilder stringBuf = new StringBuilder(); StringBuilder stringBuf = new StringBuilder();
if (lastbuf != null) { // Check to make sure we don't have identical context data if (lastbuf != null) { // Check to make sure we don't have identical context data
int i; int i;
for (i = 0; i < buf.length; ++i) for (i = 0; i < buf.length; ++i) {
if (buf[i] != lastbuf[i]) if (buf[i] != lastbuf[i]) {
break; break;
}
}
if (i == buf.length) if (i == buf.length)
{
continue; // If all data is identical, then changepoint is not necessary continue; // If all data is identical, then changepoint is not necessary
} }
else }
else {
lastbuf = new int[buf.length]; lastbuf = new int[buf.length];
for (int i = 0; i < buf.length; ++i) }
for (int i = 0; i < buf.length; ++i) {
lastbuf[i] = buf[i]; lastbuf[i] = buf[i];
}
stringBuf.append("<context_pointset"); stringBuf.append("<context_pointset");
Varnode.appendSpaceOffset(stringBuf, addr); Varnode.appendSpaceOffset(stringBuf, addr);
stringBuf.append(">\n"); stringBuf.append(">\n");
for (int i = 0; i < ctxsymbols.size(); ++i) { for (ContextSymbol sym : ctxsymbols) {
ContextSymbol sym = ctxsymbols.get(i);
int sbit = sym.getLow(); int sbit = sym.getLow();
int ebit = sym.getHigh(); int ebit = sym.getHigh();
int word = sbit / (8 * 4); int word = sbit / (8 * 4);
@ -395,37 +466,48 @@ public class DecompileDebug {
} }
private void dumpCPool(OutputStream debugStream) throws IOException { private void dumpCPool(OutputStream debugStream) throws IOException {
if (cpool.size() == 0) return; if (cpool.size() == 0) {
return;
}
debugStream.write("<constantpool>\n".getBytes()); debugStream.write("<constantpool>\n".getBytes());
for(String rec : cpool) for(String rec : cpool) {
debugStream.write(rec.getBytes()); debugStream.write(rec.getBytes());
}
debugStream.write("</constantpool>\n".getBytes()); debugStream.write("</constantpool>\n".getBytes());
} }
private void dumpComments(OutputStream debugStream) throws IOException { private void dumpComments(OutputStream debugStream) throws IOException {
if (comments != null) if (comments != null) {
debugStream.write(comments.getBytes()); debugStream.write(comments.getBytes());
} }
}
private void dumpConfiguration(OutputStream debugStream, String xmlOptions) throws IOException { private void dumpConfiguration(OutputStream debugStream, String xmlOptions) throws IOException {
if ((xmlOptions != null) && (xmlOptions.length() != 0)) if ((xmlOptions != null) && (xmlOptions.length() != 0)) {
debugStream.write(xmlOptions.getBytes()); debugStream.write(xmlOptions.getBytes());
} }
}
private void dumpFlowOverride(OutputStream debugStream) throws IOException { private void dumpFlowOverride(OutputStream debugStream) throws IOException {
if (flowoverride.size() == 0) return; if (flowoverride.size() == 0) {
return;
}
debugStream.write("<flowoverridelist>\n".getBytes()); debugStream.write("<flowoverridelist>\n".getBytes());
for(int i=0;i<flowoverride.size();++i) for (String element : flowoverride) {
debugStream.write(flowoverride.get(i).getBytes()); debugStream.write(element.getBytes());
}
debugStream.write("</flowoverridelist>\n".getBytes()); debugStream.write("</flowoverridelist>\n".getBytes());
} }
private void dumpInject(OutputStream debugStream) throws IOException { private void dumpInject(OutputStream debugStream) throws IOException {
if (inject.size() == 0) return; if (inject.size() == 0) {
return;
}
debugStream.write("<injectdebug>\n".getBytes()); debugStream.write("<injectdebug>\n".getBytes());
for(int i=0;i<inject.size();++i) for (String element : inject) {
debugStream.write(inject.get(i).getBytes()); debugStream.write(element.getBytes());
}
debugStream.write("</injectdebug>\n".getBytes()); debugStream.write("</injectdebug>\n".getBytes());
} }
@ -434,23 +516,27 @@ public class DecompileDebug {
debugStream.write("<db>\n".getBytes()); debugStream.write("<db>\n".getBytes());
for (int i = 0; i < database.size(); ++i) { for (int i = 0; i < database.size(); ++i) {
scopename = dbscope.get(i); scopename = dbscope.get(i);
if (scopename != null) if (scopename != null) {
break; break;
} }
}
while (scopename != null) { while (scopename != null) {
StringBuilder datahead = new StringBuilder(); StringBuilder datahead = new StringBuilder();
datahead.append("<scope"); datahead.append("<scope");
// Force globalnamespace to have blank name // Force globalnamespace to have blank name
if (scopename != globalnamespace) if (scopename != globalnamespace) {
SpecXmlUtils.xmlEscapeAttribute(datahead, "name", scopename.getName()); SpecXmlUtils.xmlEscapeAttribute(datahead, "name", scopename.getName());
else }
else {
SpecXmlUtils.encodeStringAttribute(datahead, "name", ""); SpecXmlUtils.encodeStringAttribute(datahead, "name", "");
}
datahead.append(">\n"); datahead.append(">\n");
datahead.append("<parent>\n"); datahead.append("<parent>\n");
HighFunction.createNamespaceTag(datahead, scopename.getParentNamespace()); HighFunction.createNamespaceTag(datahead, scopename.getParentNamespace());
datahead.append("</parent>\n"); datahead.append("</parent>\n");
if (scopename != globalnamespace) if (scopename != globalnamespace) {
datahead.append("<rangeequalssymbols/>\n"); datahead.append("<rangeequalssymbols/>\n");
}
datahead.append("<symbollist>\n"); datahead.append("<symbollist>\n");
debugStream.write(datahead.toString().getBytes()); debugStream.write(datahead.toString().getBytes());
for (int i = 0; i < database.size(); ++i) { for (int i = 0; i < database.size(); ++i) {
@ -462,12 +548,13 @@ public class DecompileDebug {
} }
debugStream.write("</symbollist>\n</scope>\n".getBytes()); debugStream.write("</symbollist>\n</scope>\n".getBytes());
scopename = null; scopename = null;
for (int i = 0; i < dbscope.size(); ++i) { for (Namespace element : dbscope) {
scopename = dbscope.get(i); scopename = element;
if (scopename != null) if (scopename != null) {
break; break;
} }
} }
}
debugStream.write("</db>\n".getBytes()); debugStream.write("</db>\n".getBytes());
} }
@ -476,7 +563,7 @@ public class DecompileDebug {
} }
public void getPcode(Address addr, Instruction instr) { public void getPcode(Address addr, Instruction instr) {
if (instr != null) if (instr != null) {
try { try {
byte[] bytes; byte[] bytes;
int delaySlotsCnt = instr.getDelaySlotDepth(); int delaySlotsCnt = instr.getDelaySlotDepth();
@ -511,6 +598,7 @@ public class DecompileDebug {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e); Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
} }
} }
}
public void getBytes(Address addr, byte[] res) { public void getBytes(Address addr, byte[] res) {
int off = 0; int off = 0;
@ -521,14 +609,19 @@ public class DecompileDebug {
ByteChunk match = byteset.tailSet(chunk).first(); ByteChunk match = byteset.tailSet(chunk).first();
match.merge(chunk); match.merge(chunk);
} }
else else {
byteset.add(chunk); byteset.add(chunk);
}
Address newaddr = chunk.addr.add(chunk.max); Address newaddr = chunk.addr.add(chunk.max);
off += newaddr.getOffset() - addr.getOffset(); off += newaddr.getOffset() - addr.getOffset();
addr = newaddr; addr = newaddr;
} }
} }
public void getStringData(Address addr, StringData stringData) {
stringmap.put(addr, stringData);
}
public void getComments(String comm) { public void getComments(String comm) {
comments = comm; // Already in XML form comments = comm; // Already in XML form
} }
@ -545,15 +638,13 @@ public class DecompileDebug {
} }
public void getMapped(Namespace namespc, String res) { public void getMapped(Namespace namespc, String res) {
if (namespc == null) if (namespc == null) {
dbscope.add(globalnamespace); dbscope.add(globalnamespace);
else
dbscope.add(namespc);
database.add(res);
} }
else {
public void getType(String name, String res) { dbscope.add(namespc);
type.add(res); }
database.add(res);
} }
public void getType(DataType dt) { public void getType(DataType dt) {
@ -562,9 +653,10 @@ public class DecompileDebug {
public void getFNTypes(HighFunction hfunc) { public void getFNTypes(HighFunction hfunc) {
getType(hfunc.getFunctionPrototype().getReturnType()); getType(hfunc.getFunctionPrototype().getReturnType());
for (int i = 0; i < hfunc.getFunctionPrototype().getNumParams(); i++) for (int i = 0; i < hfunc.getFunctionPrototype().getNumParams(); i++) {
getType(hfunc.getFunctionPrototype().getParam(i).getDataType()); getType(hfunc.getFunctionPrototype().getParam(i).getDataType());
} }
}
public void getTrackedRegisters(String doc) { public void getTrackedRegisters(String doc) {
context.add(doc); context.add(doc);
@ -575,8 +667,9 @@ public class DecompileDebug {
buf.append("<ref"); buf.append("<ref");
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "a", refs[0]); SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "a", refs[0]);
long val = 0; long val = 0;
if (refs.length > 1) if (refs.length > 1) {
val = refs[1]; val = refs[1];
}
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "b", val); SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "b", val);
buf.append("/>\n"); buf.append("/>\n");
buf.append(rec); buf.append(rec);
@ -586,16 +679,21 @@ public class DecompileDebug {
public void addFlowOverride(Address addr,FlowOverride fo) { public void addFlowOverride(Address addr,FlowOverride fo) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append("<flow type=\""); buf.append("<flow type=\"");
if (fo == FlowOverride.BRANCH) if (fo == FlowOverride.BRANCH) {
buf.append("branch"); buf.append("branch");
else if (fo == FlowOverride.CALL) }
else if (fo == FlowOverride.CALL) {
buf.append("call"); buf.append("call");
else if (fo == FlowOverride.CALL_RETURN) }
else if (fo == FlowOverride.CALL_RETURN) {
buf.append("callreturn"); buf.append("callreturn");
else if (fo == FlowOverride.RETURN) }
else if (fo == FlowOverride.RETURN) {
buf.append("return"); buf.append("return");
else }
else {
buf.append("none"); buf.append("none");
}
buf.append("\"><addr"); buf.append("\"><addr");
Varnode.appendSpaceOffset(buf,func.getEntryPoint()); Varnode.appendSpaceOffset(buf,func.getEntryPoint());
buf.append("/><addr"); buf.append("/><addr");
@ -604,12 +702,12 @@ public class DecompileDebug {
flowoverride.add(buf.toString()); flowoverride.add(buf.toString());
} }
public void addInject(Address addr,String name,int type,String payload) { public void addInject(Address addr,String name,int injectType,String payload) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append("<inject name=\""); buf.append("<inject name=\"");
buf.append(name); buf.append(name);
buf.append('"'); buf.append('"');
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "type", type); SpecXmlUtils.encodeSignedIntegerAttribute(buf, "type", injectType);
buf.append(">\n <addr"); buf.append(">\n <addr");
Varnode.appendSpaceOffset(buf, addr); Varnode.appendSpaceOffset(buf, addr);
buf.append("/>\n <payload><![CDATA[\n"); buf.append("/>\n <payload><![CDATA[\n");