mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
string debugging tags
This commit is contained in:
parent
547a4f2ab5
commit
9ea9790e88
5 changed files with 263 additions and 155 deletions
|
@ -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()) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue