GP-2358 Packed protocol for decompiler marshaling

This commit is contained in:
caheckman 2022-07-26 15:36:05 -04:00
parent 6a1a649213
commit 79c3508f54
119 changed files with 4238 additions and 2207 deletions

View File

@ -15,6 +15,7 @@
*/ */
package ghidra.pcode.exec; package ghidra.pcode.exec;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -81,9 +82,10 @@ public class SleighProgramCompiler {
* @return the list of p-code ops * @return the list of p-code ops
* @throws UnknownInstructionException in case of crossbuilds, the target instruction is unknown * @throws UnknownInstructionException in case of crossbuilds, the target instruction is unknown
* @throws MemoryAccessException in case of crossbuilds, the target address cannot be accessed * @throws MemoryAccessException in case of crossbuilds, the target address cannot be accessed
* @throws IOException for errors in during emitting
*/ */
public static List<PcodeOp> buildOps(Language language, ConstructTpl template) public static List<PcodeOp> buildOps(Language language, ConstructTpl template)
throws UnknownInstructionException, MemoryAccessException { throws UnknownInstructionException, MemoryAccessException, IOException {
Address zero = language.getDefaultSpace().getAddress(0); Address zero = language.getDefaultSpace().getAddress(0);
SleighParserContext c = new SleighParserContext(zero, zero, zero, zero); SleighParserContext c = new SleighParserContext(zero, zero, zero, zero);
ParserWalker walk = new ParserWalker(c); ParserWalker walk = new ParserWalker(c);
@ -116,6 +118,7 @@ public class SleighProgramCompiler {
* This is basically a hack to avoid NPEs when no output varnode is given. * This is basically a hack to avoid NPEs when no output varnode is given.
* *
* @param parser the parser to add the symbol to * @param parser the parser to add the symbol to
* @return the nil symbol
*/ */
protected static VarnodeSymbol addNilSymbol(PcodeParser parser) { protected static VarnodeSymbol addNilSymbol(PcodeParser parser) {
SleighSymbol exists = parser.findSymbol(NIL_SYMBOL_NAME); SleighSymbol exists = parser.findSymbol(NIL_SYMBOL_NAME);
@ -124,9 +127,8 @@ public class SleighProgramCompiler {
return (VarnodeSymbol) exists; return (VarnodeSymbol) exists;
} }
long offset = parser.allocateTemp(); long offset = parser.allocateTemp();
VarnodeSymbol nil = VarnodeSymbol nil = new VarnodeSymbol(new Location("<util>", 0), NIL_SYMBOL_NAME,
new VarnodeSymbol(new Location("<util>", 0), NIL_SYMBOL_NAME, parser.getUniqueSpace(), parser.getUniqueSpace(), offset, 1);
offset, 1);
parser.addSymbol(nil); parser.addSymbol(nil);
return nil; return nil;
} }
@ -156,7 +158,7 @@ public class SleighProgramCompiler {
return ctor.construct(language, SleighProgramCompiler.buildOps(language, template), return ctor.construct(language, SleighProgramCompiler.buildOps(language, template),
libSyms); libSyms);
} }
catch (UnknownInstructionException | MemoryAccessException e) { catch (UnknownInstructionException | MemoryAccessException | IOException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
@ -278,9 +280,8 @@ public class SleighProgramCompiler {
String p = params.get(i); String p = params.get(i);
Varnode a = args.get(i); Varnode a = args.get(i);
if (a == null && i == 0) { // Only allow output to be omitted if (a == null && i == 0) { // Only allow output to be omitted
parser.addSymbol( parser.addSymbol(new VarnodeSymbol(nil.getLocation(), p, nilVnData.space,
new VarnodeSymbol(nil.getLocation(), p, nilVnData.space, nilVnData.offset, nilVnData.offset, nilVnData.size));
nilVnData.size));
} }
else { else {
parser.addSymbol(paramSym(language, sleigh, opName, p, a)); parser.addSymbol(paramSym(language, sleigh, opName, p, a));

View File

@ -304,7 +304,7 @@ void Range::decode(Decoder &decoder)
{ {
uint4 elemId = decoder.openElement(); uint4 elemId = decoder.openElement();
if (elemId != ELEM_RANGE && elemId != ELEM_REGISTER) if (elemId != ELEM_RANGE && elemId != ELEM_REGISTER)
throw XmlError("Expecting <range> or <register> element"); throw DecoderError("Expecting <range> or <register> element");
decodeFromAttributes(decoder); decodeFromAttributes(decoder);
decoder.closeElement(elemId); decoder.closeElement(elemId);
} }
@ -354,7 +354,7 @@ void RangeProperties::decode(Decoder &decoder)
{ {
uint4 elemId = decoder.openElement(); uint4 elemId = decoder.openElement();
if (elemId != ELEM_RANGE && elemId != ELEM_REGISTER) if (elemId != ELEM_RANGE && elemId != ELEM_REGISTER)
throw XmlError("Expecting <range> or <register> element"); throw DecoderError("Expecting <range> or <register> element");
for(;;) { for(;;) {
uint4 attribId = decoder.getNextAttributeId(); uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break; if (attribId == 0) break;

View File

@ -534,22 +534,25 @@ void Architecture::nameFunction(const Address &addr,string &name) const
name = defname.str(); name = defname.str();
} }
/// This process sets up a "register relative" space for this architecture /// \brief Create a new address space associated with a pointer register
/// If the name is "stack", this space takes on the role of an "official" stack space ///
/// Should only be called once during initialization /// This process sets up a \e register \e relative"space for this architecture.
/// If indicated, this space takes on the role of the \e formal stack space.
/// Should only be called once during initialization.
/// \param basespace is the address space underlying the stack /// \param basespace is the address space underlying the stack
/// \param nm is the name of the new space /// \param nm is the name of the new space
/// \param ptrdata is the register location acting as a pointer into the new space /// \param ptrdata is the register location acting as a pointer into the new space
/// \param truncSize is the (possibly truncated) size of the register that fits the space /// \param truncSize is the (possibly truncated) size of the register that fits the space
/// \param isreversejustified is \b true if small variables are justified opposite of endianness /// \param isreversejustified is \b true if small variables are justified opposite of endianness
/// \param stackGrowth is \b true if a stack implemented in this space grows in the negative direction /// \param stackGrowth is \b true if a stack implemented in this space grows in the negative direction
/// \param isFormal is the indicator for the \b formal stack space
void Architecture::addSpacebase(AddrSpace *basespace,const string &nm,const VarnodeData &ptrdata, void Architecture::addSpacebase(AddrSpace *basespace,const string &nm,const VarnodeData &ptrdata,
int4 truncSize,bool isreversejustified,bool stackGrowth) int4 truncSize,bool isreversejustified,bool stackGrowth,bool isFormal)
{ {
int4 ind = numSpaces(); int4 ind = numSpaces();
SpacebaseSpace *spc = new SpacebaseSpace(this,translate,nm,ind,truncSize,basespace,ptrdata.space->getDelay()+1); SpacebaseSpace *spc = new SpacebaseSpace(this,translate,nm,ind,truncSize,basespace,ptrdata.space->getDelay()+1,isFormal);
if (isreversejustified) if (isreversejustified)
setReverseJustified(spc); setReverseJustified(spc);
insertSpace(spc); insertSpace(spc);
@ -1047,7 +1050,7 @@ void Architecture::decodeStackPointer(Decoder &decoder)
truncSize = basespace->getAddrSize(); truncSize = basespace->getAddrSize();
} }
addSpacebase(basespace,"stack",point,truncSize,isreversejustify,stackGrowth); // Create the "official" stackpointer addSpacebase(basespace,"stack",point,truncSize,isreversejustify,stackGrowth,true); // Create the "official" stackpointer
} }
/// Manually alter the dead-code delay for a specific address space, /// Manually alter the dead-code delay for a specific address space,
@ -1114,7 +1117,7 @@ void Architecture::decodeSpacebase(Decoder &decoder)
AddrSpace *basespace = decoder.readSpace(ATTRIB_SPACE); AddrSpace *basespace = decoder.readSpace(ATTRIB_SPACE);
decoder.closeElement(elemId); decoder.closeElement(elemId);
const VarnodeData &point(translate->getRegister(registerName)); const VarnodeData &point(translate->getRegister(registerName));
addSpacebase(basespace,nameString,point,point.size,false,false); addSpacebase(basespace,nameString,point,point.size,false,false,false);
} }
/// Configure memory based on a \<nohighptr> element. Mark specific address ranges /// Configure memory based on a \<nohighptr> element. Mark specific address ranges

View File

@ -247,7 +247,7 @@ public:
#endif #endif
protected: protected:
void addSpacebase(AddrSpace *basespace,const string &nm,const VarnodeData &ptrdata, void addSpacebase(AddrSpace *basespace,const string &nm,const VarnodeData &ptrdata,
int4 truncSize,bool isreversejustified,bool stackGrowth); ///< Create a new space and associated pointer int4 truncSize,bool isreversejustified,bool stackGrowth,bool isFormal);
void addNoHighPtr(const Range &rng); ///< Add a new region where pointers do not exist void addNoHighPtr(const Range &rng); ///< Add a new region where pointers do not exist
// Factory routines for building this architecture // Factory routines for building this architecture

View File

@ -40,7 +40,7 @@ void CommentDatabaseGhidra::fillCache(const Address &fad) const
iter = cache.beginComment(fad); iter = cache.beginComment(fad);
iterend = cache.endComment(fad); iterend = cache.endComment(fad);
XmlDecode decoder(ghidra); PackedDecode decoder(ghidra);
if (ghidra->getComments(fad,commentfilter,decoder)) { if (ghidra->getComments(fad,commentfilter,decoder)) {
cache.decode(decoder); cache.decode(decoder);
} }

View File

@ -71,7 +71,7 @@ void IfcLoadFile::execute(istream &s)
else else
*status->optr << "Wrong tag type for experimental rules: "+root->getName() << endl; *status->optr << "Wrong tag type for experimental rules: "+root->getName() << endl;
} }
catch(XmlError &err) { catch(DecoderError &err) {
*status->optr << err.explain << endl; *status->optr << err.explain << endl;
*status->optr << "Skipping experimental rules" << endl; *status->optr << "Skipping experimental rules" << endl;
} }
@ -81,7 +81,7 @@ void IfcLoadFile::execute(istream &s)
bool iserror = false; bool iserror = false;
try { try {
dcp->conf->init(store); dcp->conf->init(store);
} catch(XmlError &err) { } catch(DecoderError &err) {
errmsg = err.explain; errmsg = err.explain;
iserror = true; iserror = true;
} catch(LowlevelError &err) { } catch(LowlevelError &err) {
@ -156,7 +156,7 @@ void IfcRestore::execute(istream &s)
dcp->conf->restoreXml(store); dcp->conf->restoreXml(store);
} catch(LowlevelError &err) { } catch(LowlevelError &err) {
throw IfaceExecutionError(err.explain); throw IfaceExecutionError(err.explain);
} catch(XmlError &err) { } catch(DecoderError &err) {
throw IfaceExecutionError(err.explain); throw IfaceExecutionError(err.explain);
} }

View File

@ -32,16 +32,16 @@ const CPoolRecord *ConstantPoolGhidra::getRecord(const vector<uintb> &refs) cons
{ {
const CPoolRecord *rec = cache.getRecord(refs); const CPoolRecord *rec = cache.getRecord(refs);
if (rec == (const CPoolRecord *)0) { if (rec == (const CPoolRecord *)0) {
XmlDecode decoder(ghidra);
bool success; bool success;
PackedDecode decoder(ghidra);
try { try {
success = ghidra->getCPoolRef(refs,decoder); success = ghidra->getCPoolRef(refs,decoder);
} }
catch(JavaError &err) { catch(JavaError &err) {
throw LowlevelError("Error fetching constant pool record: " + err.explain); throw LowlevelError("Error fetching constant pool record: " + err.explain);
} }
catch(XmlError &err) { catch(DecoderError &err) {
throw LowlevelError("Error in constant pool record xml: "+err.explain); throw LowlevelError("Error in constant pool record encoding: "+err.explain);
} }
if (!success) { if (!success) {
ostringstream s; ostringstream s;

View File

@ -52,7 +52,7 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const
if (cacheScope != (Scope *)0) if (cacheScope != (Scope *)0)
return cacheScope; // Scope was previously cached return cacheScope; // Scope was previously cached
XmlDecode decoder(ghidra); PackedDecode decoder(ghidra);
if (!ghidra->getNamespacePath(id,decoder)) if (!ghidra->getNamespacePath(id,decoder))
throw LowlevelError("Could not get namespace info"); throw LowlevelError("Could not get namespace info");
@ -212,7 +212,7 @@ Symbol *ScopeGhidra::removeQuery(const Address &addr) const
// Have we queried this address before // Have we queried this address before
if (holes.inRange(addr,1)) return (Symbol *)0; if (holes.inRange(addr,1)) return (Symbol *)0;
XmlDecode decoder(ghidra); PackedDecode decoder(ghidra);
if (ghidra->getMappedSymbolsXML(addr,decoder)) { // Query GHIDRA about this address if (ghidra->getMappedSymbolsXML(addr,decoder)) { // Query GHIDRA about this address
sym = dump2Cache(decoder); // Add it to the cache sym = dump2Cache(decoder); // Add it to the cache
} }
@ -349,9 +349,9 @@ Funcdata *ScopeGhidra::resolveExternalRefFunction(ExternRefSymbol *sym) const
if (resFd == (Funcdata *)0) { if (resFd == (Funcdata *)0) {
// If the function isn't in cache, we use the special // If the function isn't in cache, we use the special
// getExternalRefXML interface to recover the external function // getExternalRefXML interface to recover the external function
PackedDecode decoder(ghidra);
SymbolEntry *entry = sym->getFirstWholeMap(); SymbolEntry *entry = sym->getFirstWholeMap();
XmlDecode decoder(ghidra); if (ghidra->getExternalRef(entry->getAddr(),decoder)) {
if (ghidra->getExternalRefXML(entry->getAddr(),decoder)) {
FunctionSymbol *funcSym; FunctionSymbol *funcSym;
// Make sure referenced function is cached // Make sure referenced function is cached
funcSym = dynamic_cast<FunctionSymbol *>(dump2Cache(decoder)); funcSym = dynamic_cast<FunctionSymbol *>(dump2Cache(decoder));

View File

@ -4395,13 +4395,10 @@ void FuncProto::decode(Decoder &decoder,Architecture *glb)
} }
else if (attribId == ATTRIB_EXTRAPOP) { else if (attribId == ATTRIB_EXTRAPOP) {
seenextrapop = true; seenextrapop = true;
string expopval = decoder.readString(); try {
if (expopval == "unknown") readextrapop = decoder.readSignedInteger();
} catch(DecoderError &err) {
readextrapop = ProtoModel::extrapop_unknown; readextrapop = ProtoModel::extrapop_unknown;
else {
istringstream i1(expopval);
i1.unsetf(ios::dec | ios::hex | ios::oct);
i1 >> readextrapop;
} }
} }
else if (attribId == ATTRIB_MODELLOCK) { else if (attribId == ATTRIB_MODELLOCK) {

View File

@ -23,6 +23,28 @@
#include "cpool_ghidra.hh" #include "cpool_ghidra.hh"
#include "inject_ghidra.hh" #include "inject_ghidra.hh"
//AttributeId ATTRIB_BADDATA = AttributeId("baddata",145);
ElementId ELEM_COMMAND_ISNAMEUSED = ElementId("command_isnameused",239);
ElementId ELEM_COMMAND_GETBYTES = ElementId("command_getbytes",240);
ElementId ELEM_COMMAND_GETCALLFIXUP = ElementId("command_getcallfixup",241);
ElementId ELEM_COMMAND_GETCALLMECH = ElementId("command_getcallmech",242);
ElementId ELEM_COMMAND_GETCALLOTHERFIXUP = ElementId("command_getcallotherfixup",243);
ElementId ELEM_COMMAND_GETCODELABEL = ElementId("command_getcodelabel",244);
ElementId ELEM_COMMAND_GETCOMMENTS = ElementId("command_getcomments",245);
ElementId ELEM_COMMAND_GETCPOOLREF = ElementId("command_getcpoolref",246);
ElementId ELEM_COMMAND_GETDATATYPE = ElementId("command_getdatatype",247);
ElementId ELEM_COMMAND_GETEXTERNALREF = ElementId("command_getexternalref",248);
ElementId ELEM_COMMAND_GETMAPPEDSYMBOLS = ElementId("command_getmappedsymbols",249);
ElementId ELEM_COMMAND_GETNAMESPACEPATH = ElementId("command_getnamespacepath",250);
ElementId ELEM_COMMAND_GETPCODE = ElementId("command_getpcode",251);
ElementId ELEM_COMMAND_GETPCODEEXECUTABLE = ElementId("command_getpcodeexecutable",252);
ElementId ELEM_COMMAND_GETREGISTER = ElementId("command_getregister",253);
ElementId ELEM_COMMAND_GETREGISTERNAME = ElementId("command_getregistername",254);
ElementId ELEM_COMMAND_GETSTRINGDATA = ElementId("command_getstringdata",255);
ElementId ELEM_COMMAND_GETTRACKEDREGISTERS = ElementId("command_gettrackedregisters",256);
ElementId ELEM_COMMAND_GETUSEROPNAME = ElementId("command_getuseropname",257);
/// Catch the signal so the OS doesn't pop up a dialog /// Catch the signal so the OS doesn't pop up a dialog
/// \param sig is the OS signal (should always be SIGSEGV) /// \param sig is the OS signal (should always be SIGSEGV)
void ArchitectureGhidra::segvHandler(int4 sig) void ArchitectureGhidra::segvHandler(int4 sig)
@ -143,7 +165,7 @@ void ArchitectureGhidra::readStringStream(istream &s,string &res)
/// \param s is the input stream from the client. /// \param s is the input stream from the client.
/// \param decoder is the given stream decoder that will hold the result /// \param decoder is the given stream decoder that will hold the result
/// \return \b true if a response was received /// \return \b true if a response was received
bool ArchitectureGhidra::readStream(istream &s,Decoder &decoder) bool ArchitectureGhidra::readStringStream(istream &s,Decoder &decoder)
{ {
int4 type = readToAnyBurst(s); int4 type = readToAnyBurst(s);
@ -159,38 +181,6 @@ bool ArchitectureGhidra::readStream(istream &s,Decoder &decoder)
throw JavaError("alignment","Expecting string or end of query response"); throw JavaError("alignment","Expecting string or end of query response");
} }
/// The method expects to see protocol markers indicating a string from the client,
/// otherwise it throws and exception. An array size is encoded in the first 4 characters
/// of the string. An array of this size is allocated and filled with the
/// rest of the string.
/// \param s is the input stream from the client
/// \return the array of packed p-code data
uint1 *ArchitectureGhidra::readPackedStream(istream &s)
{
int4 type = readToAnyBurst(s);
if (type == 14) {
uint4 size = 0;
int4 c = s.get();
size ^= (c-0x20);
c = s.get();
size ^= ((c-0x20)<<6);
c = s.get();
size ^= ((c-0x20)<<12);
c = s.get();
size ^= ((c-0x20)<<18);
uint1 *res = new uint1[ size ];
s.read((char *)res,size);
type = readToAnyBurst(s);
if (type != 15)
throw JavaError("alignment","Expecting packed string end");
return res;
}
if ((type&1)==1)
return (uint1 *)0;
throw JavaError("alignment","Expecting string or end of query response");
}
/// Write out a string with correct protocol markers /// Write out a string with correct protocol markers
/// \param s is the output stream to the client /// \param s is the output stream to the client
/// \param msg is the string to send /// \param msg is the string to send
@ -240,27 +230,13 @@ bool ArchitectureGhidra::readAll(istream &s,Decoder &decoder)
{ {
readToResponse(s); readToResponse(s);
if (readStream(s,decoder)) { if (readStringStream(s,decoder)) {
readResponseEnd(s); readResponseEnd(s);
return true; return true;
} }
return false; return false;
} }
/// Read up to the beginning of a query response, check for an
/// exception record, otherwise read in packed p-code op data.
/// \param s is the input stream from the client
/// \return the array of packed p-coded data
uint1 *ArchitectureGhidra::readPackedAll(istream &s)
{
readToResponse(s);
uint1 *doc = readPackedStream(s);
if (doc != (uint1 *)0)
readResponseEnd(s);
return doc;
}
/// \brief Send an exception message to the Ghidra client /// \brief Send an exception message to the Ghidra client
/// ///
/// This generally called because of some sort of alignment issue in the /// This generally called because of some sort of alignment issue in the
@ -412,8 +388,12 @@ bool ArchitectureGhidra::getRegister(const string &regname,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getRegister"); sout.write("\000\000\001\016",4); // Beginning of string header
writeStringStream(sout,regname); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETREGISTER);
encoder.writeString(ATTRIB_NAME, regname);
encoder.closeElement(ELEM_COMMAND_GETREGISTER);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -429,11 +409,12 @@ string ArchitectureGhidra::getRegisterName(const VarnodeData &vndata)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getRegisterName");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
Address addr(vndata.space,vndata.offset); Address addr(vndata.space,vndata.offset);
encoder.clear(); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETREGISTERNAME);
addr.encode(encoder,vndata.size); addr.encode(encoder,vndata.size);
encoder.closeElement(ELEM_COMMAND_GETREGISTERNAME);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -456,10 +437,11 @@ bool ArchitectureGhidra::getTrackedRegisters(const Address &addr,Decoder &decode
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getTrackedRegisters");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear(); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETTRACKEDREGISTERS);
addr.encode(encoder); addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETTRACKEDREGISTERS);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -475,9 +457,11 @@ string ArchitectureGhidra::getUserOpName(int4 index)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getUserOpName");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
sout << dec << index; PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETUSEROPNAME);
encoder.writeSignedInteger(ATTRIB_INDEX, index);
encoder.closeElement(ELEM_COMMAND_GETUSEROPNAME);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -489,24 +473,24 @@ string ArchitectureGhidra::getUserOpName(int4 index)
return res; return res;
} }
/// Get a description of all the p-code ops for the instruction /// Get a description of all the p-code ops for the instruction at the given address.
/// at the given address. The information is stored in a special
/// compressed format. (See PcodeEmit::restorePackedOp)
/// \param addr is the address of the instruction /// \param addr is the address of the instruction
/// \return an array of the packed data /// \param decoder is the stream decoder for holding the result
uint1 *ArchitectureGhidra::getPcodePacked(const Address &addr) /// \return true if the request is successful and ops are ready to be decoded
bool ArchitectureGhidra::getPcode(const Address &addr,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getPacked");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear(); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETPCODE);
addr.encode(encoder); addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETPCODE);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readPackedAll(sin); return readAll(sin,decoder);
} }
/// The Ghidra client will pass back a \<symbol> element, \<function> element, or some /// The Ghidra client will pass back a \<symbol> element, \<function> element, or some
@ -520,10 +504,11 @@ bool ArchitectureGhidra::getMappedSymbolsXML(const Address &addr,Decoder &decode
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getMappedSymbolsXML");
sout.write("\000\000\001\016",4); // Beginning of string sout.write("\000\000\001\016",4); // Beginning of string
encoder.clear(); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETMAPPEDSYMBOLS);
addr.encode(encoder); addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETMAPPEDSYMBOLS);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -540,14 +525,15 @@ bool ArchitectureGhidra::getMappedSymbolsXML(const Address &addr,Decoder &decode
/// \param addr is the given address /// \param addr is the given address
/// \param decoder is the stream decoder that will hold the result /// \param decoder is the stream decoder that will hold the result
/// \return \b true if the query completes successfully /// \return \b true if the query completes successfully
bool ArchitectureGhidra::getExternalRefXML(const Address &addr,Decoder &decoder) bool ArchitectureGhidra::getExternalRef(const Address &addr,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getExternalRefXML");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear(); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETEXTERNALREF);
addr.encode(encoder); addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETEXTERNALREF);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -565,9 +551,11 @@ bool ArchitectureGhidra::getNamespacePath(uint8 id,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getNamespacePath");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
sout << hex << id; PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETNAMESPACEPATH);
encoder.writeUnsignedInteger(ATTRIB_ID, id);
encoder.closeElement(ELEM_COMMAND_GETNAMESPACEPATH);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -579,15 +567,13 @@ bool ArchitectureGhidra::isNameUsed(const string &nm,uint8 startId,uint8 stopId)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"isNameUsed");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
sout << nm; PackedEncode encoder(sout);
sout.write("\000\000\001\017",4); encoder.openElement(ELEM_COMMAND_ISNAMEUSED);
sout.write("\000\000\001\016",4); // Beginning of string header encoder.writeString(ATTRIB_NAME, nm);
sout << hex << startId; encoder.writeUnsignedInteger(ATTRIB_FIRST, startId);
sout.write("\000\000\001\017",4); encoder.writeUnsignedInteger(ATTRIB_LAST, stopId);
sout.write("\000\000\001\016",4); // Beginning of string header encoder.closeElement(ELEM_COMMAND_ISNAMEUSED);
sout << hex << stopId;
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -606,10 +592,11 @@ string ArchitectureGhidra::getCodeLabel(const Address &addr)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getSymbol");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear(); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETCODELABEL);
addr.encode(encoder); addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETCODELABEL);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -627,14 +614,16 @@ string ArchitectureGhidra::getCodeLabel(const Address &addr)
/// \param id is a unique id associated with the data-type, pass 0 if unknown /// \param id is a unique id associated with the data-type, pass 0 if unknown
/// \param decoder is the stream decoder that will hold the result /// \param decoder is the stream decoder that will hold the result
/// \return \b true if the query completed successfully /// \return \b true if the query completed successfully
bool ArchitectureGhidra::getType(const string &name,uint8 id,Decoder &decoder) bool ArchitectureGhidra::getDataType(const string &name,uint8 id,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getType");
writeStringStream(sout,name);
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
sout << dec << (int8)id; // Pass as a signed integer PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETDATATYPE);
encoder.writeString(ATTRIB_NAME, name);
encoder.writeSignedInteger(ATTRIB_ID, id);
encoder.closeElement(ELEM_COMMAND_GETDATATYPE);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -654,13 +643,12 @@ bool ArchitectureGhidra::getComments(const Address &fad,uint4 flags,Decoder &dec
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getComments");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear(); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETCOMMENTS);
encoder.writeUnsignedInteger(ATTRIB_TYPE, flags);
fad.encode(encoder); fad.encode(encoder);
sout.write("\000\000\001\017",4); encoder.closeElement(ELEM_COMMAND_GETCOMMENTS);
sout.write("\000\000\001\016",4); // Beginning of string header
sout << dec << flags;
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -678,10 +666,11 @@ void ArchitectureGhidra::getBytes(uint1 *buf,int4 size,const Address &inaddr)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getBytes");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear(); PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETBYTES);
inaddr.encode(encoder,size); inaddr.encode(encoder,size);
encoder.closeElement(ELEM_COMMAND_GETBYTES);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -726,14 +715,14 @@ void ArchitectureGhidra::getStringData(vector<uint1> &buffer,const Address &addr
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getString");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear(); PackedEncode encoder(sout);
addr.encode(encoder,maxBytes); encoder.openElement(ELEM_COMMAND_GETSTRINGDATA);
sout.write("\000\000\001\017",4); encoder.writeSignedInteger(ATTRIB_MAXSIZE, maxBytes);
writeStringStream(sout,ct->getName()); encoder.writeString(ATTRIB_TYPE,ct->getName());
sout.write("\000\000\001\016",4); // Beginning of string header encoder.writeUnsignedInteger(ATTRIB_ID, ct->getId());
sout << dec << (int8)ct->getId(); // Pass as a signed integer addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETSTRINGDATA);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
@ -785,18 +774,33 @@ bool ArchitectureGhidra::getPcodeInject(const string &name,int4 type,const Injec
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
if (type == InjectPayload::CALLFIXUP_TYPE)
writeStringStream(sout,"getCallFixup");
else if (type == InjectPayload::CALLOTHERFIXUP_TYPE)
writeStringStream(sout,"getCallotherFixup");
else if (type == InjectPayload::CALLMECHANISM_TYPE)
writeStringStream(sout,"getCallMech");
else
writeStringStream(sout,"getXPcode");
writeStringStream(sout,name);
sout.write("\000\000\001\016",4); sout.write("\000\000\001\016",4);
encoder.clear(); PackedEncode encoder(sout);
con.encode(encoder); if (type == InjectPayload::CALLFIXUP_TYPE) {
encoder.openElement(ELEM_COMMAND_GETCALLFIXUP);
encoder.writeString(ATTRIB_NAME, name);
con.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETCALLFIXUP);
}
else if (type == InjectPayload::CALLOTHERFIXUP_TYPE) {
encoder.openElement(ELEM_COMMAND_GETCALLOTHERFIXUP);
encoder.writeString(ATTRIB_NAME, name);
con.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETCALLOTHERFIXUP);
}
else if (type == InjectPayload::CALLMECHANISM_TYPE) {
encoder.openElement(ELEM_COMMAND_GETCALLMECH);
encoder.writeString(ATTRIB_NAME, name);
con.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETCALLMECH);
}
else {
encoder.openElement(ELEM_COMMAND_GETPCODEEXECUTABLE);
encoder.writeString(ATTRIB_NAME, name);
con.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETPCODEEXECUTABLE);
}
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -814,12 +818,16 @@ bool ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getCPoolRef");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
sout << hex << refs[0]; PackedEncode encoder(sout);
for(int4 i=1;i<refs.size();++i) { encoder.openElement(ELEM_COMMAND_GETCPOOLREF);
sout << ',' << hex << refs[i]; encoder.writeSignedInteger(ATTRIB_SIZE, refs.size());
for(int4 i=0;i<refs.size();++i) {
encoder.openElement(ELEM_VALUE);
encoder.writeUnsignedInteger(ATTRIB_CONTENT, refs[i]);
encoder.closeElement(ELEM_VALUE);
} }
encoder.closeElement(ELEM_COMMAND_GETCPOOLREF);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -827,24 +835,6 @@ bool ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs,Decoder &decoder)
return readAll(sin,decoder); return readAll(sin,decoder);
} }
// Document *ArchitectureGhidra::getScopeProperties(Scope *newscope)
// { // Query ghidra about the properties of a namespace scope
// vector<string> namepath;
// newscope->getNameSegments(namepath);
// sout.write("\000\000\001\004",4);
// writeStringStream(sout,"getScope");
// sout.write("\000\000\001\016",4); // Beginning of string header
// sout << "<name>\n";
// for(int4 i=0;i<namepath.size();++i)
// sout << "<val>" << namepath[i] << "</val>\n";
// sout << "</name>\n";
// sout.write("\000\000\001\017",4);
// sout.write("\000\000\001\005",4);
// sout.flush();
// return readXMLAll(sin);
// }
void ArchitectureGhidra::printMessage(const string &message) const void ArchitectureGhidra::printMessage(const string &message) const
{ {
@ -861,7 +851,7 @@ void ArchitectureGhidra::printMessage(const string &message) const
/// \param o is the output stream to the Ghidra client /// \param o is the output stream to the Ghidra client
ArchitectureGhidra::ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec, ArchitectureGhidra::ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,
const string &corespec,istream &i,ostream &o) const string &corespec,istream &i,ostream &o)
: Architecture(), sin(i), sout(o), encoder(sout) : Architecture(), sin(i), sout(o)
{ {
print->setMarkup(true); print->setMarkup(true);

View File

@ -21,6 +21,26 @@
#include "architecture.hh" #include "architecture.hh"
extern ElementId ELEM_COMMAND_ISNAMEUSED; ///< Marshaling element \<command_isnameused>
extern ElementId ELEM_COMMAND_GETBYTES; ///< Marshaling element \<command_getbytes>
extern ElementId ELEM_COMMAND_GETCALLFIXUP; ///< Marshaling element \<command_getcallfixup>
extern ElementId ELEM_COMMAND_GETCALLMECH; ///< Marshaling element \<command_getcallmech>
extern ElementId ELEM_COMMAND_GETCALLOTHERFIXUP; ///< Marshaling element \<command_getcallotherfixup>
extern ElementId ELEM_COMMAND_GETCODELABEL; ///< Marshaling element \<command_getcodelabel>
extern ElementId ELEM_COMMAND_GETCOMMENTS; ///< Marshaling element \<command_getcomments>
extern ElementId ELEM_COMMAND_GETCPOOLREF; ///< Marshaling element \<command_getcpoolref>
extern ElementId ELEM_COMMAND_GETDATATYPE; ///< Marshaling element \<command_datatype>
extern ElementId ELEM_COMMAND_GETEXTERNALREF; ///< Marshaling element \<command_getexternalref>
extern ElementId ELEM_COMMAND_GETMAPPEDSYMBOLS; ///< Marshaling element \<command_getmappedsymbols>
extern ElementId ELEM_COMMAND_GETNAMESPACEPATH; ///< Marshaling element \<command_getnamespacepath>
extern ElementId ELEM_COMMAND_GETPCODE; ///< Marshaling element \<command_getpcode>
extern ElementId ELEM_COMMAND_GETPCODEEXECUTABLE; ///< Marshaling element \<command_getpcodeexecutable>
extern ElementId ELEM_COMMAND_GETREGISTER; ///< Marshaling element \<command_getregister>
extern ElementId ELEM_COMMAND_GETREGISTERNAME; ///< Marshaling element \<command_getregistername>
extern ElementId ELEM_COMMAND_GETSTRINGDATA; ///< Marshaling element \<command_getstringdata>
extern ElementId ELEM_COMMAND_GETTRACKEDREGISTERS; ///< Marshaling element \<command_gettrackedregisters>
extern ElementId ELEM_COMMAND_GETUSEROPNAME; ///< Marshaling element \<command_getuseropname>
/// \brief Exception that mirrors exceptions thrown by the Ghidra client /// \brief Exception that mirrors exceptions thrown by the Ghidra client
/// ///
/// If the Ghidra client throws an exception while trying to answer a query, /// If the Ghidra client throws an exception while trying to answer a query,
@ -60,7 +80,6 @@ struct JavaError : public LowlevelError {
class ArchitectureGhidra : public Architecture { class ArchitectureGhidra : public Architecture {
istream &sin; ///< Input stream for interfacing with Ghidra istream &sin; ///< Input stream for interfacing with Ghidra
ostream &sout; ///< Output stream for interfacing with Ghidra ostream &sout; ///< Output stream for interfacing with Ghidra
XmlEncode encoder; ///< Encoder used to write to Ghidra
mutable string warnings; ///< Warnings accumulated by the decompiler mutable string warnings; ///< Warnings accumulated by the decompiler
string pspecxml; ///< XML pspec passed from Ghidra string pspecxml; ///< XML pspec passed from Ghidra
string cspecxml; ///< XML cspec passed from Ghidra string cspecxml; ///< XML cspec passed from Ghidra
@ -91,13 +110,13 @@ public:
string getRegisterName(const VarnodeData &vndata); ///< Retrieve a register name given its storage location string getRegisterName(const VarnodeData &vndata); ///< Retrieve a register name given its storage location
bool getTrackedRegisters(const Address &addr,Decoder &decoder); ///< Retrieve \e tracked register values at the given address bool getTrackedRegisters(const Address &addr,Decoder &decoder); ///< Retrieve \e tracked register values at the given address
string getUserOpName(int4 index); ///< Get the name of a user-defined p-code op string getUserOpName(int4 index); ///< Get the name of a user-defined p-code op
uint1 *getPcodePacked(const Address &addr); ///< Get p-code for a single instruction bool getPcode(const Address &addr,Decoder &decoder); ///< Get p-code for a single instruction
bool getMappedSymbolsXML(const Address &addr,Decoder &decoder); ///< Get symbols associated with the given address bool getMappedSymbolsXML(const Address &addr,Decoder &decoder); ///< Get symbols associated with the given address
bool getExternalRefXML(const Address &addr,Decoder &decoder); ///< Retrieve a description of an external function bool getExternalRef(const Address &addr,Decoder &decoder); ///< Retrieve a description of an external function
bool getNamespacePath(uint8 id,Decoder &decoder); ///< Get a description of a namespace path bool getNamespacePath(uint8 id,Decoder &decoder); ///< Get a description of a namespace path
bool isNameUsed(const string &nm,uint8 startId,uint8 stopId); ///< Is given name used along namespace path bool isNameUsed(const string &nm,uint8 startId,uint8 stopId); ///< Is given name used along namespace path
string getCodeLabel(const Address &addr); ///< Retrieve a label at the given address string getCodeLabel(const Address &addr); ///< Retrieve a label at the given address
bool getType(const string &name,uint8 id,Decoder &decoder); ///< Retrieve a data-type description for the given name and id bool getDataType(const string &name,uint8 id,Decoder &decoder); ///< Retrieve a data-type description for the given name and id
bool getComments(const Address &fad,uint4 flags,Decoder &decoder); ///< Retrieve comments for a particular function bool getComments(const Address &fad,uint4 flags,Decoder &decoder); ///< Retrieve comments for a particular function
void getBytes(uint1 *buf,int4 size,const Address &inaddr); ///< Retrieve bytes in the LoadImage at the given address void getBytes(uint1 *buf,int4 size,const Address &inaddr); ///< Retrieve bytes in the LoadImage at the given address
bool getPcodeInject(const string &name,int4 type,const InjectContext &con,Decoder &decoder); bool getPcodeInject(const string &name,int4 type,const InjectContext &con,Decoder &decoder);
@ -136,13 +155,11 @@ public:
static int4 readToAnyBurst(istream &s); ///< Read the next message protocol marker static int4 readToAnyBurst(istream &s); ///< Read the next message protocol marker
static bool readBoolStream(istream &s); ///< Read a boolean value from the client static bool readBoolStream(istream &s); ///< Read a boolean value from the client
static void readStringStream(istream &s,string &res); ///< Receive a string from the client static void readStringStream(istream &s,string &res); ///< Receive a string from the client
static bool readStringStream(istream &s,Decoder &decoder); ///< Receive an encoded string from the client
static void writeStringStream(ostream &s,const string &msg); ///< Send a string to the client static void writeStringStream(ostream &s,const string &msg); ///< Send a string to the client
static void readToResponse(istream &s); ///< Read the query response protocol marker static void readToResponse(istream &s); ///< Read the query response protocol marker
static void readResponseEnd(istream &s); ///< Read the ending query response protocol marker static void readResponseEnd(istream &s); ///< Read the ending query response protocol marker
static bool readAll(istream &s,Decoder &decoder); ///< Read a whole response as an XML document static bool readAll(istream &s,Decoder &decoder); ///< Read a whole response as an XML document
static bool readStream(istream &s,Decoder &decoder); ///< Receive an XML document from the client
static uint1 *readPackedStream(istream &s); ///< Read packed p-code op information
static uint1 *readPackedAll(istream &s); ///< Read a whole response as packed p-code op information
static void passJavaException(ostream &s,const string &tp,const string &msg); static void passJavaException(ostream &s,const string &tp,const string &msg);
static bool isDynamicSymbolName(const string &nm); ///< Check if name is of form FUN_.. or DAT_.. static bool isDynamicSymbolName(const string &nm); ///< Check if name is of form FUN_.. or DAT_..

View File

@ -19,7 +19,7 @@ const TrackedSet &ContextGhidra::getTrackedSet(const Address &addr) const
{ {
cache.clear(); cache.clear();
XmlDecode decoder(glb); PackedDecode decoder(glb);
glb->getTrackedRegisters(addr,decoder); glb->getTrackedRegisters(addr,decoder);
uint4 elemId = decoder.openElement(ELEM_TRACKED_POINTSET); uint4 elemId = decoder.openElement(ELEM_TRACKED_POINTSET);

View File

@ -126,9 +126,9 @@ int4 GhidraCommand::doit(void)
throw JavaError("alignment","Missing end of command"); throw JavaError("alignment","Missing end of command");
rawAction(); rawAction();
} }
catch(XmlError &err) { catch(DecoderError &err) {
string errmsg; string errmsg;
errmsg = "XML processing error: " + err.explain; errmsg = "Marshaling error: " + err.explain;
ghidra->printMessage( errmsg ); ghidra->printMessage( errmsg );
} }
catch(JavaError &err) { catch(JavaError &err) {
@ -277,8 +277,8 @@ void DecompileAt::loadParameters(void)
{ {
GhidraCommand::loadParameters(); GhidraCommand::loadParameters();
XmlDecode decoder(ghidra); PackedDecode decoder(ghidra);
ArchitectureGhidra::readStream(sin,decoder); // Read encoded address directly from in stream ArchitectureGhidra::readStringStream(sin,decoder); // Read encoded address directly from in stream
addr = Address::decode(decoder); // Decode for functions address addr = Address::decode(decoder); // Decode for functions address
} }
@ -305,7 +305,7 @@ void DecompileAt::rawAction(void)
sout.write("\000\000\001\016",4); sout.write("\000\000\001\016",4);
if (fd->isProcComplete()) { if (fd->isProcComplete()) {
XmlEncode encoder(sout); PackedEncode encoder(sout);
encoder.openElement(ELEM_DOC); encoder.openElement(ELEM_DOC);
if (ghidra->getSendParamMeasures() && (ghidra->allacts.getCurrentName() == "paramid")) { if (ghidra->getSendParamMeasures() && (ghidra->allacts.getCurrentName() == "paramid")) {
ParamIDAnalysis pidanalysis( fd, true ); // Only send back final prototype ParamIDAnalysis pidanalysis( fd, true ); // Only send back final prototype
@ -331,8 +331,8 @@ void StructureGraph::loadParameters(void)
{ {
GhidraCommand::loadParameters(); GhidraCommand::loadParameters();
XmlDecode decoder(ghidra); PackedDecode decoder(ghidra);
ArchitectureGhidra::readStream(sin,decoder); ArchitectureGhidra::readStringStream(sin,decoder);
ingraph.decode(decoder); ingraph.decode(decoder);
} }
@ -351,7 +351,7 @@ void StructureGraph::rawAction(void)
resultgraph.orderBlocks(); resultgraph.orderBlocks();
sout.write("\000\000\001\016",4); sout.write("\000\000\001\016",4);
XmlEncode encoder(sout); PackedEncode encoder(sout);
resultgraph.encode(encoder); resultgraph.encode(encoder);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
ingraph.clear(); ingraph.clear();
@ -411,8 +411,17 @@ void SetOptions::loadParameters(void)
{ {
GhidraCommand::loadParameters(); GhidraCommand::loadParameters();
optionsListTag.clear(); if (decoder != (Decoder *)0)
ArchitectureGhidra::readStringStream(sin, optionsListTag); delete decoder;
decoder = new PackedDecode(ghidra);
ArchitectureGhidra::readStringStream(sin, *decoder);
}
SetOptions::~SetOptions(void)
{
if (decoder != (Decoder *)0)
delete decoder;
} }
void SetOptions::rawAction(void) void SetOptions::rawAction(void)
@ -421,12 +430,9 @@ void SetOptions::rawAction(void)
res = false; res = false;
ghidra->resetDefaults(); ghidra->resetDefaults();
DocumentStorage storage; ghidra->options->decode(*decoder);
istringstream s(optionsListTag); delete decoder;
Document *doc = storage.parseDocument(s); decoder = (Decoder *)0;
XmlDecode decoder(ghidra,doc->getRoot());
ghidra->options->decode(decoder);
optionsListTag.clear();
res = true; res = true;
} }

View File

@ -217,16 +217,18 @@ public:
/// The decompiler supports configuration of a variety of named options that affect /// The decompiler supports configuration of a variety of named options that affect
/// everything from how code is transformed to how it is displayed (See ArchOption). /// everything from how code is transformed to how it is displayed (See ArchOption).
/// The command expects 2 string parameters: the encoded integer id of the program, /// The command expects 2 string parameters: the encoded integer id of the program,
/// and an XML document containing an \<optionslist> tag. The \<optionslist> tag /// and an encoded document containing an \<optionslist> element. The \<optionslist> element
/// contains one child tag for each option to be configured. /// contains one child element for each option to be configured.
/// The command returns a single character message, 't' or 'f', indicating whether the /// The command returns a single character message, 't' or 'f', indicating whether the
/// configuration succeeded. /// configuration succeeded.
class SetOptions : public GhidraCommand { class SetOptions : public GhidraCommand {
string optionsListTag; ///< The <optionslist> XML tag Decoder *decoder; ///< The \<optionslist> decoder
virtual void loadParameters(void); virtual void loadParameters(void);
virtual void sendResult(void); virtual void sendResult(void);
public: public:
bool res; ///< Set to \b true if the option change succeeded bool res; ///< Set to \b true if the option change succeeded
SetOptions(void) { decoder = (Decoder *)0; res = false; } ///< Constructor
virtual ~SetOptions(void);
virtual void rawAction(void); virtual void rawAction(void);
}; };

View File

@ -46,14 +46,14 @@ const VarnodeData &GhidraTranslate::getRegister(const string &nm) const
map<string,VarnodeData>::const_iterator iter = nm2addr.find(nm); map<string,VarnodeData>::const_iterator iter = nm2addr.find(nm);
if (iter != nm2addr.end()) if (iter != nm2addr.end())
return (*iter).second; return (*iter).second;
XmlDecode decoder(glb); PackedDecode decoder(glb);
try { try {
if (!glb->getRegister(nm,decoder)) // Ask Ghidra client about the register if (!glb->getRegister(nm,decoder)) // Ask Ghidra client about the register
throw LowlevelError("No register named "+nm); throw LowlevelError("No register named "+nm);
} }
catch(XmlError &err) { catch(DecoderError &err) {
ostringstream errmsg; ostringstream errmsg;
errmsg << "Error parsing XML response for query of register: " << nm; errmsg << "Error decoding response for query of register: " << nm;
errmsg << " -- " << err.explain; errmsg << " -- " << err.explain;
throw LowlevelError(errmsg.str()); throw LowlevelError(errmsg.str());
} }
@ -100,9 +100,10 @@ int4 GhidraTranslate::oneInstruction(PcodeEmit &emit,const Address &baseaddr) co
{ {
int4 offset; int4 offset;
uint1 *doc; PackedDecode decoder(glb);
bool success;
try { try {
doc = glb->getPcodePacked(baseaddr); // Request p-code for one instruction success = glb->getPcode(baseaddr,decoder); // Request p-code for one instruction
} }
catch(JavaError &err) { catch(JavaError &err) {
ostringstream s; ostringstream s;
@ -110,34 +111,26 @@ int4 GhidraTranslate::oneInstruction(PcodeEmit &emit,const Address &baseaddr) co
baseaddr.printRaw(s); baseaddr.printRaw(s);
throw LowlevelError(s.str()); throw LowlevelError(s.str());
} }
if (doc == (uint1 *)0) { if (!success) {
ostringstream s; ostringstream s;
s << "No pcode could be generated at address: " << baseaddr.getShortcut(); s << "No pcode could be generated at address: " << baseaddr.getShortcut();
baseaddr.printRaw(s); baseaddr.printRaw(s);
throw BadDataError(s.str()); throw BadDataError(s.str());
} }
uintb val; int4 el = decoder.openElement();
const uint1 *ptr = PcodeEmit::unpackOffset(doc+1,val); offset = decoder.readSignedInteger(ATTRIB_OFFSET);
offset = (int4)val; if (el == ELEM_UNIMPL) {
if (*doc == PcodeEmit::unimpl_tag) {
ostringstream s; ostringstream s;
s << "Instruction not implemented in pcode:\n "; s << "Instruction not implemented in pcode:\n ";
baseaddr.printRaw(s); baseaddr.printRaw(s);
delete [] doc;
throw UnimplError(s.str(),offset); throw UnimplError(s.str(),offset);
} }
int4 spcindex = (int4)(*ptr++ - 0x20); Address pc = Address::decode(decoder);
AddrSpace *spc = getSpace(spcindex);
uintb instoffset;
ptr = PcodeEmit::unpackOffset(ptr,instoffset);
Address pc(spc,instoffset);
while(*ptr == PcodeEmit::op_tag) while(decoder.peekElement() != 0)
ptr = emit.restorePackedOp(pc,ptr,this); emit.decodeOp(pc,decoder);
delete [] doc;
return offset; return offset;
} }

View File

@ -1872,7 +1872,7 @@ void Heritage::splitJoinLevel(vector<Varnode *> &lastcombo,vector<Varnode *> &ne
int4 sizeaccum = 0; int4 sizeaccum = 0;
int4 j; int4 j;
for(j=recnum;j<numpieces;++j) { for(j=recnum;j<numpieces;++j) {
sizeaccum += joinrec->getPiece(recnum).size; sizeaccum += joinrec->getPiece(j).size;
if (sizeaccum == curvn->getSize()) { if (sizeaccum == curvn->getSize()) {
j += 1; j += 1;
break; break;

View File

@ -3472,8 +3472,8 @@ void execute(IfaceStatus *status,IfaceDecompData *dcp)
*status->optr << "Low-level ERROR: " << err.explain << endl; *status->optr << "Low-level ERROR: " << err.explain << endl;
dcp->abortFunction(*status->optr); dcp->abortFunction(*status->optr);
} }
catch(XmlError &err) { catch(DecoderError &err) {
*status->optr << "XML ERROR: " << err.explain << endl; *status->optr << "Decoding ERROR: " << err.explain << endl;
dcp->abortFunction(*status->optr); dcp->abortFunction(*status->optr);
} }
status->evaluateError(); status->evaluateError();

View File

@ -48,7 +48,7 @@ void InjectPayloadGhidra::inject(InjectContext &con,PcodeEmit &emit) const
{ {
ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb; ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb;
XmlDecode decoder(ghidra); PackedDecode decoder(ghidra);
try { try {
if (!ghidra->getPcodeInject(name,type,con,decoder)) if (!ghidra->getPcodeInject(name,type,con,decoder))
throw LowlevelError("Could not retrieve pcode snippet: "+name); throw LowlevelError("Could not retrieve pcode snippet: "+name);
@ -56,12 +56,13 @@ void InjectPayloadGhidra::inject(InjectContext &con,PcodeEmit &emit) const
catch(JavaError &err) { catch(JavaError &err) {
throw LowlevelError("Error getting pcode snippet: " + err.explain); throw LowlevelError("Error getting pcode snippet: " + err.explain);
} }
catch(XmlError &err) { catch(DecoderError &err) {
throw LowlevelError("Error in pcode snippet xml: "+err.explain); throw LowlevelError("Error in pcode snippet xml: "+err.explain);
} }
uint4 elemId = decoder.openElement(); uint4 elemId = decoder.openElement();
Address addr = Address::decode(decoder);
while(decoder.peekElement() != 0) while(decoder.peekElement() != 0)
emit.decodeOp(decoder); emit.decodeOp(addr,decoder);
decoder.closeElement(elemId); decoder.closeElement(elemId);
} }
@ -121,7 +122,7 @@ void ExecutablePcodeGhidra::inject(InjectContext &con,PcodeEmit &emit) const
{ {
ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb; ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb;
XmlDecode decoder(ghidra); PackedDecode decoder(ghidra);
try { try {
if (!ghidra->getPcodeInject(name,type,con,decoder)) if (!ghidra->getPcodeInject(name,type,con,decoder))
throw LowlevelError("Could not retrieve pcode snippet: "+name); throw LowlevelError("Could not retrieve pcode snippet: "+name);
@ -129,12 +130,13 @@ void ExecutablePcodeGhidra::inject(InjectContext &con,PcodeEmit &emit) const
catch(JavaError &err) { catch(JavaError &err) {
throw LowlevelError("Error getting pcode snippet: " + err.explain); throw LowlevelError("Error getting pcode snippet: " + err.explain);
} }
catch(XmlError &err) { catch(DecoderError &err) {
throw LowlevelError("Error in pcode snippet xml: "+err.explain); throw LowlevelError("Error in pcode snippet xml: "+err.explain);
} }
uint4 elemId = decoder.openElement(); uint4 elemId = decoder.openElement();
Address addr = Address::decode(decoder);
while(decoder.peekElement() != 0) while(decoder.peekElement() != 0)
emit.decodeOp(decoder); emit.decodeOp(addr,decoder);
decoder.closeElement(elemId); decoder.closeElement(elemId);
} }
@ -144,7 +146,7 @@ void ExecutablePcodeGhidra::decode(Decoder &decoder)
uint4 elemId = decoder.openElement(); uint4 elemId = decoder.openElement();
if (elemId != ELEM_PCODE && elemId != ELEM_CASE_PCODE && elemId != ELEM_ADDR_PCODE && if (elemId != ELEM_PCODE && elemId != ELEM_CASE_PCODE && elemId != ELEM_ADDR_PCODE &&
elemId != ELEM_DEFAULT_PCODE && elemId != ELEM_SIZE_PCODE) elemId != ELEM_DEFAULT_PCODE && elemId != ELEM_SIZE_PCODE)
throw XmlError("Expecting <pcode>, <case_pcode>, <addr_pcode>, <default_pcode>, or <size_pcode>"); throw DecoderError("Expecting <pcode>, <case_pcode>, <addr_pcode>, <default_pcode>, or <size_pcode>");
decodePayloadAttributes(decoder); decodePayloadAttributes(decoder);
decodePayloadParams(decoder); // Parse the parameters decodePayloadParams(decoder); // Parse the parameters
decoder.closeElementSkipping(elemId); // But skip rest of body decoder.closeElementSkipping(elemId); // But skip rest of body

View File

@ -233,7 +233,7 @@ void ExecutablePcodeSleigh::decode(Decoder &decoder)
uint4 elemId = decoder.openElement(); uint4 elemId = decoder.openElement();
if (elemId != ELEM_PCODE && elemId != ELEM_CASE_PCODE && if (elemId != ELEM_PCODE && elemId != ELEM_CASE_PCODE &&
elemId != ELEM_ADDR_PCODE && elemId != ELEM_DEFAULT_PCODE && elemId != ELEM_SIZE_PCODE) elemId != ELEM_ADDR_PCODE && elemId != ELEM_DEFAULT_PCODE && elemId != ELEM_SIZE_PCODE)
throw XmlError("Expecting <pcode>, <case_pcode>, <addr_pcode>, <default_pcode>, or <size_pcode>"); throw DecoderError("Expecting <pcode>, <case_pcode>, <addr_pcode>, <default_pcode>, or <size_pcode>");
decodePayloadAttributes(decoder); decodePayloadAttributes(decoder);
decodePayloadParams(decoder); decodePayloadParams(decoder);
uint4 subId = decoder.openElement(ELEM_BODY); uint4 subId = decoder.openElement(ELEM_BODY);
@ -269,8 +269,8 @@ void InjectPayloadDynamic::decodeEntry(Decoder &decoder)
delete (*iter).second; // Delete any preexisting document delete (*iter).second; // Delete any preexisting document
addrMap[addr] = doc; addrMap[addr] = doc;
} }
catch(XmlError &err) { catch(DecoderError &err) {
throw LowlevelError("Error in dynamic payload XML"); throw LowlevelError("Error decoding dynamic payload");
} }
decoder.closeElement(subId); decoder.closeElement(subId);
} }
@ -284,8 +284,9 @@ void InjectPayloadDynamic::inject(InjectContext &context,PcodeEmit &emit) const
const Element *el = (*eiter).second->getRoot(); const Element *el = (*eiter).second->getRoot();
XmlDecode decoder(glb->translate,el); XmlDecode decoder(glb->translate,el);
uint4 rootId = decoder.openElement(ELEM_INST); uint4 rootId = decoder.openElement(ELEM_INST);
Address addr = Address::decode(decoder);
while(decoder.peekElement() != 0) while(decoder.peekElement() != 0)
emit.decodeOp(decoder); emit.decodeOp(addr,decoder);
decoder.closeElement(rootId); decoder.closeElement(rootId);
} }

View File

@ -16,8 +16,12 @@
#include "marshal.hh" #include "marshal.hh"
#include "translate.hh" #include "translate.hh"
using namespace PackedFormat;
unordered_map<string,uint4> AttributeId::lookupAttributeId; unordered_map<string,uint4> AttributeId::lookupAttributeId;
const int4 PackedDecode::BUFFER_SIZE = 1024;
/// Access static vector of AttributeId objects that are registered during static initialization /// Access static vector of AttributeId objects that are registered during static initialization
/// The list itself is created once on the first call to this method. /// The list itself is created once on the first call to this method.
/// \return a reference to the vector /// \return a reference to the vector
@ -48,7 +52,7 @@ void AttributeId::initialize(void)
AttributeId *attrib = thelist[i]; AttributeId *attrib = thelist[i];
#ifdef CPUI_DEBUG #ifdef CPUI_DEBUG
if (lookupAttributeId.find(attrib->name) != lookupAttributeId.end()) if (lookupAttributeId.find(attrib->name) != lookupAttributeId.end())
throw XmlError(attrib->name + " attribute registered more than once"); throw DecoderError(attrib->name + " attribute registered more than once");
#endif #endif
lookupAttributeId[attrib->name] = attrib->id; lookupAttributeId[attrib->name] = attrib->id;
} }
@ -88,7 +92,7 @@ void ElementId::initialize(void)
ElementId *elem = thelist[i]; ElementId *elem = thelist[i];
#ifdef CPUI_DEBUG #ifdef CPUI_DEBUG
if (lookupElementId.find(elem->name) != lookupElementId.end()) if (lookupElementId.find(elem->name) != lookupElementId.end())
throw XmlError(elem->name + " element registered more than once"); throw DecoderError(elem->name + " element registered more than once");
#endif #endif
lookupElementId[elem->name] = elem->id; lookupElementId[elem->name] = elem->id;
} }
@ -103,16 +107,6 @@ XmlDecode::~XmlDecode(void)
delete document; delete document;
} }
void XmlDecode::clear(void)
{
if (document != (Document *)0)
delete document;
document = (Document *)0;
rootElement = (const Element *)0;
attributeIndex = -1;
}
void XmlDecode::ingestStream(istream &s) void XmlDecode::ingestStream(istream &s)
{ {
@ -169,7 +163,7 @@ uint4 XmlDecode::openElement(const ElementId &elemId)
const Element *el; const Element *el;
if (elStack.empty()) { if (elStack.empty()) {
if (rootElement == (const Element *)0) if (rootElement == (const Element *)0)
throw XmlError("Expecting <" + elemId.getName() + "> but reached end of document"); throw DecoderError("Expecting <" + elemId.getName() + "> but reached end of document");
el = rootElement; el = rootElement;
rootElement = (const Element *)0; // Only open document once rootElement = (const Element *)0; // Only open document once
} }
@ -181,10 +175,10 @@ uint4 XmlDecode::openElement(const ElementId &elemId)
iterStack.back() = ++iter; iterStack.back() = ++iter;
} }
else else
throw XmlError("Expecting <" + elemId.getName() + "> but no remaining children in current element"); throw DecoderError("Expecting <" + elemId.getName() + "> but no remaining children in current element");
} }
if (el->getName() != elemId.getName()) if (el->getName() != elemId.getName())
throw XmlError("Expecting <" + elemId.getName() + "> but got <" + el->getName() + ">"); throw DecoderError("Expecting <" + elemId.getName() + "> but got <" + el->getName() + ">");
elStack.push_back(el); elStack.push_back(el);
iterStack.push_back(el->getChildren().begin()); iterStack.push_back(el->getChildren().begin());
attributeIndex = -1; attributeIndex = -1;
@ -197,9 +191,9 @@ void XmlDecode::closeElement(uint4 id)
#ifdef CPUI_DEBUG #ifdef CPUI_DEBUG
const Element *el = elStack.back(); const Element *el = elStack.back();
if (iterStack.back() != el->getChildren().end()) if (iterStack.back() != el->getChildren().end())
throw XmlError("Closing element <" + el->getName() + "> with additional children"); throw DecoderError("Closing element <" + el->getName() + "> with additional children");
if (ElementId::find(el->getName()) != id) if (ElementId::find(el->getName()) != id)
throw XmlError("Trying to close <" + el->getName() + "> with mismatching id"); throw DecoderError("Trying to close <" + el->getName() + "> with mismatching id");
#endif #endif
elStack.pop_back(); elStack.pop_back();
iterStack.pop_back(); iterStack.pop_back();
@ -212,7 +206,7 @@ void XmlDecode::closeElementSkipping(uint4 id)
#ifdef CPUI_DEBUG #ifdef CPUI_DEBUG
const Element *el = elStack.back(); const Element *el = elStack.back();
if (ElementId::find(el->getName()) != id) if (ElementId::find(el->getName()) != id)
throw XmlError("Trying to close <" + el->getName() + "> with mismatching id"); throw DecoderError("Trying to close <" + el->getName() + "> with mismatching id");
#endif #endif
elStack.pop_back(); elStack.pop_back();
iterStack.pop_back(); iterStack.pop_back();
@ -251,7 +245,7 @@ int4 XmlDecode::findMatchingAttribute(const Element *el,const string &attribName
if (el->getAttributeName(i) == attribName) if (el->getAttributeName(i) == attribName)
return i; return i;
} }
throw XmlError("Attribute missing: " + attribName); throw DecoderError("Attribute missing: " + attribName);
} }
bool XmlDecode::readBool(void) bool XmlDecode::readBool(void)
@ -355,7 +349,7 @@ AddrSpace *XmlDecode::readSpace(void)
string nm = el->getAttributeValue(attributeIndex); string nm = el->getAttributeValue(attributeIndex);
AddrSpace *res = spcManager->getSpaceByName(nm); AddrSpace *res = spcManager->getSpaceByName(nm);
if (res == (AddrSpace *)0) if (res == (AddrSpace *)0)
throw XmlError("Unknown address space name: "+nm); throw DecoderError("Unknown address space name: "+nm);
return res; return res;
} }
@ -373,7 +367,7 @@ AddrSpace *XmlDecode::readSpace(const AttributeId &attribId)
} }
AddrSpace *res = spcManager->getSpaceByName(nm); AddrSpace *res = spcManager->getSpaceByName(nm);
if (res == (AddrSpace *)0) if (res == (AddrSpace *)0)
throw XmlError("Unknown address space name: "+nm); throw DecoderError("Unknown address space name: "+nm);
return res; return res;
} }
@ -472,6 +466,543 @@ void XmlEncode::writeSpace(const AttributeId &attribId,const AddrSpace *spc)
a_v(outStream,attribId.getName(),spc->getName()); a_v(outStream,attribId.getName(),spc->getName());
} }
/// The integer is encoded, 7-bits per byte, starting with the most significant 7-bits.
/// The integer is decode from the \e current position, and the position is advanced.
/// \param len is the number of bytes to extract
uint8 PackedDecode::readInteger(int4 len)
{
uint8 res = 0;
while(len > 0) {
res <<= RAWDATA_BITSPERBYTE;
res |= (getNextByte(curPos) & RAWDATA_MASK);
len -= 1;
}
return res;
}
/// The \e current position is reset to the start of the current open element. Attributes are scanned
/// and skipped until the attribute matching the given id is found. The \e current position is set to the
/// start of the matching attribute, in preparation for one of the read*() methods.
/// If the id is not found an exception is thrown.
/// \param attribId is the attribute id to scan for.
void PackedDecode::findMatchingAttribute(const AttributeId &attribId)
{
curPos = startPos;
for(;;) {
uint1 header1 = getByte(curPos);
if ((header1 & HEADER_MASK) != ATTRIBUTE) break;
uint4 id = header1 & ELEMENTID_MASK;
if ((header1 & HEADEREXTEND_MASK) != 0) {
id <<= RAWDATA_BITSPERBYTE;
id |= (getBytePlus1(curPos) & RAWDATA_MASK);
}
if (attribId.getId() == id)
return; // Found it
skipAttribute();
}
throw DecoderError("Attribute " + attribId.getName() + " is not present");
}
/// The attribute at the \e current position is scanned enough to determine its length, and the position
/// is advanced to the following byte.
void PackedDecode::skipAttribute(void)
{
uint1 header1 = getNextByte(curPos); // Attribute header
if ((header1 & HEADEREXTEND_MASK) != 0)
getNextByte(curPos); // Extra byte for extended id
uint1 typeByte = getNextByte(curPos); // Type (and length) byte
uint1 attribType = typeByte >> TYPECODE_SHIFT;
if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE)
return; // has no additional data
uint4 length = readLengthCode(typeByte); // Length of data in bytes
if (attribType == TYPECODE_STRING) {
length = readInteger(length); // Read length field to get final length of string
}
advancePosition(curPos, length); // Skip -length- data
}
/// This assumes the header and \b type \b byte have been read. Decode type and length info and finish
/// skipping over the attribute so that the next call to getNextAttributeId() is on cut.
/// \param typeByte is the previously scanned type byte
void PackedDecode::skipAttributeRemaining(uint1 typeByte)
{
uint1 attribType = typeByte >> TYPECODE_SHIFT;
if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE)
return; // has no additional data
uint4 length = readLengthCode(typeByte); // Length of data in bytes
if (attribType == TYPECODE_STRING) {
length = readInteger(length); // Read length field to get final length of string
}
advancePosition(curPos, length); // Skip -length- data
}
PackedDecode::~PackedDecode(void)
{
list<ByteChunk>::const_iterator iter;
for(iter=inStream.begin();iter!=inStream.end();++iter) {
delete [] (*iter).start;
}
}
void PackedDecode::ingestStream(istream &s)
{
int4 gcount = 0;
while(s.peek() > 0) {
uint1 *buf = new uint1[BUFFER_SIZE + 1];
inStream.emplace_back(buf,buf+BUFFER_SIZE);
s.get((char *)buf,BUFFER_SIZE+1,'\0');
gcount = s.gcount();
}
endPos.seqIter = inStream.begin();
if (endPos.seqIter != inStream.end()) {
endPos.current = (*endPos.seqIter).start;
endPos.end = (*endPos.seqIter).end;
// Make sure there is at least one character after ingested buffer
if (gcount == BUFFER_SIZE) {
// Last buffer was entirely filled
uint1 *endbuf = new uint1[1]; // Add one more buffer
inStream.emplace_back(endbuf,endbuf + 1);
gcount = 0;
}
uint1 *buf = inStream.back().start;
buf[gcount] = ELEMENT_END;
}
}
uint4 PackedDecode::peekElement(void)
{
uint1 header1 = getByte(endPos);
if ((header1 & HEADER_MASK) != ELEMENT_START)
return 0;
uint4 id = header1 & ELEMENTID_MASK;
if ((header1 & HEADEREXTEND_MASK) != 0) {
id <<= RAWDATA_BITSPERBYTE;
id |= (getBytePlus1(endPos) & RAWDATA_MASK);
}
return id;
}
uint4 PackedDecode::openElement(void)
{
uint1 header1 = getByte(endPos);
if ((header1 & HEADER_MASK) != ELEMENT_START)
return 0;
getNextByte(endPos);
uint4 id = header1 & ELEMENTID_MASK;
if ((header1 & HEADEREXTEND_MASK) != 0) {
id <<= RAWDATA_BITSPERBYTE;
id |= (getNextByte(endPos) & RAWDATA_MASK);
}
startPos = endPos;
curPos = endPos;
header1 = getByte(curPos);
while((header1 & HEADER_MASK) == ATTRIBUTE) {
skipAttribute();
header1 = getByte(curPos);
}
endPos = curPos;
curPos = startPos;
attributeRead = true; // "Last attribute was read" is vacuously true
return id;
}
uint4 PackedDecode::openElement(const ElementId &elemId)
{
uint4 id = openElement();
if (id != elemId.getId()) {
if (id == 0)
throw DecoderError("Expecting <" + elemId.getName() + "> but did not scan an element");
throw DecoderError("Expecting <" + elemId.getName() + "> but id did not match");
}
return id;
}
void PackedDecode::closeElement(uint4 id)
{
uint1 header1 = getNextByte(endPos);
if ((header1 & HEADER_MASK) != ELEMENT_END)
throw DecoderError("Expecting element close");
uint4 closeId = header1 & ELEMENTID_MASK;
if ((header1 & HEADEREXTEND_MASK) != 0) {
closeId <<= RAWDATA_BITSPERBYTE;
closeId |= (getNextByte(endPos) & RAWDATA_MASK);
}
if (id != closeId)
throw DecoderError("Did not see expected closing element");
}
void PackedDecode::closeElementSkipping(uint4 id)
{
vector<uint4> idstack;
idstack.push_back(id);
do {
uint1 header1 = getByte(endPos) & HEADER_MASK;
if (header1 == ELEMENT_END) {
closeElement(idstack.back());
idstack.pop_back();
}
else if (header1 == ELEMENT_START) {
idstack.push_back(openElement());
}
else
throw DecoderError("Corrupt stream");
} while(!idstack.empty());
}
void PackedDecode::rewindAttributes(void)
{
curPos = startPos;
attributeRead = true;
}
uint4 PackedDecode::getNextAttributeId(void)
{
if (!attributeRead)
skipAttribute();
uint1 header1 = getByte(curPos);
if ((header1 & HEADER_MASK) != ATTRIBUTE)
return 0;
uint4 id = header1 & ELEMENTID_MASK;
if ((header1 & HEADEREXTEND_MASK) != 0) {
id <<= RAWDATA_BITSPERBYTE;
id |= (getBytePlus1(curPos) & RAWDATA_MASK);
}
attributeRead = false;
return id;
}
bool PackedDecode::readBool(void)
{
uint1 header1 = getNextByte(curPos);
if ((header1 & HEADEREXTEND_MASK)!=0)
getNextByte(curPos);
uint1 typeByte = getNextByte(curPos);
if ((typeByte >> TYPECODE_SHIFT) != TYPECODE_BOOLEAN)
throw DecoderError("Expecting boolean attribute");
attributeRead = true;
return ((typeByte & LENGTHCODE_MASK) != 0);
}
bool PackedDecode::readBool(const AttributeId &attribId)
{
findMatchingAttribute(attribId);
bool res = readBool();
curPos = startPos;
return res;
}
intb PackedDecode::readSignedInteger(void)
{
uint1 header1 = getNextByte(curPos);
if ((header1 & HEADEREXTEND_MASK)!=0)
getNextByte(curPos);
uint1 typeByte = getNextByte(curPos);
uint4 typeCode = typeByte >> TYPECODE_SHIFT;
intb res;
if (typeCode == TYPECODE_SIGNEDINT_POSITIVE) {
res = readInteger(readLengthCode(typeByte));
}
else if (typeCode == TYPECODE_SIGNEDINT_NEGATIVE) {
res = readInteger(readLengthCode(typeByte));
res = -res;
}
else {
skipAttributeRemaining(typeByte);
throw DecoderError("Expecting signed integer attribute");
}
attributeRead = true;
return res;
}
intb PackedDecode::readSignedInteger(const AttributeId &attribId)
{
findMatchingAttribute(attribId);
intb res = readSignedInteger();
curPos = startPos;
return res;
}
uintb PackedDecode::readUnsignedInteger(void)
{
uint1 header1 = getNextByte(curPos);
if ((header1 & HEADEREXTEND_MASK)!=0)
getNextByte(curPos);
uint1 typeByte = getNextByte(curPos);
uint4 typeCode = typeByte >> TYPECODE_SHIFT;
uintb res;
if (typeCode == TYPECODE_UNSIGNEDINT) {
res = readInteger(readLengthCode(typeByte));
}
else {
skipAttributeRemaining(typeByte);
throw DecoderError("Expecting unsigned integer attribute");
}
attributeRead = true;
return res;
}
uintb PackedDecode::readUnsignedInteger(const AttributeId &attribId)
{
findMatchingAttribute(attribId);
uintb res = readUnsignedInteger();
curPos = startPos;
return res;
}
string PackedDecode::readString(void)
{
uint1 header1 = getNextByte(curPos);
if ((header1 & HEADEREXTEND_MASK)!=0)
getNextByte(curPos);
uint1 typeByte = getNextByte(curPos);
uint4 typeCode = typeByte >> TYPECODE_SHIFT;
if (typeCode != TYPECODE_STRING) {
skipAttributeRemaining(typeByte);
throw DecoderError("Expecting string attribute");
}
int4 length = readLengthCode(typeByte);
length = readInteger(length);
attributeRead = true;
int4 curLen = curPos.end - curPos.current;
if (curLen >= length) {
string res((const char *)curPos.current,length);
advancePosition(curPos, length);
return res;
}
string res((const char *)curPos.current,curLen);
length -= curLen;
advancePosition(curPos, curLen);
while(length > 0) {
curLen = curPos.end - curPos.current;
if (curLen > length)
curLen = length;
res.append((const char *)curPos.current,curLen);
length -= curLen;
advancePosition(curPos, curLen);
}
return res;
}
string PackedDecode::readString(const AttributeId &attribId)
{
findMatchingAttribute(attribId);
string res = readString();
curPos = startPos;
return res;
}
AddrSpace *PackedDecode::readSpace(void)
{
uint1 header1 = getNextByte(curPos);
if ((header1 & HEADEREXTEND_MASK)!=0)
getNextByte(curPos);
uint1 typeByte = getNextByte(curPos);
uint4 typeCode = typeByte >> TYPECODE_SHIFT;
int4 res;
AddrSpace *spc;
if (typeCode == TYPECODE_ADDRESSSPACE) {
res = readInteger(readLengthCode(typeByte));
spc = spcManager->getSpace(res);
if (spc == (AddrSpace *)0)
throw DecoderError("Unknown address space index");
}
else if (typeCode == TYPECODE_SPECIALSPACE) {
uint4 specialCode = readLengthCode(typeByte);
if (specialCode == SPECIALSPACE_STACK)
spc = spcManager->getStackSpace();
else if (specialCode == SPECIALSPACE_JOIN) {
spc = spcManager->getJoinSpace();
}
else {
throw DecoderError("Cannot marshal special address space");
}
}
else {
skipAttributeRemaining(typeByte);
throw DecoderError("Expecting space attribute");
}
attributeRead = true;
return spc;
}
AddrSpace *PackedDecode::readSpace(const AttributeId &attribId)
{
findMatchingAttribute(attribId);
AddrSpace *res = readSpace();
curPos = startPos;
return res;
}
void PackedEncode::writeInteger(uint1 typeByte,uint8 val)
{
uint1 lenCode;
int4 sa;
if (val == 0) {
lenCode = 0;
sa = -1;
}
if (val < 0x800000000) {
if (val < 0x200000) {
if (val < 0x80) {
lenCode = 1; // 7-bits
sa = 0;
}
else if (val < 0x4000) {
lenCode = 2; // 14-bits
sa = RAWDATA_BITSPERBYTE;
}
else {
lenCode = 3; // 21-bits
sa = 2*RAWDATA_BITSPERBYTE;
}
}
else if (val < 0x10000000) {
lenCode = 4; // 28-bits
sa = 3*RAWDATA_BITSPERBYTE;
}
else {
lenCode = 5; // 35-bits
sa = 4*RAWDATA_BITSPERBYTE;
}
}
else if (val < 0x2000000000000) {
if (val < 0x40000000000) {
lenCode = 6;
sa = 5*RAWDATA_BITSPERBYTE;
}
else {
lenCode = 7;
sa = 6*RAWDATA_BITSPERBYTE;
}
}
else {
if (val < 0x100000000000000) {
lenCode = 8;
sa = 7*RAWDATA_BITSPERBYTE;
}
else if (val < 0x8000000000000000) {
lenCode = 9;
sa = 8*RAWDATA_BITSPERBYTE;
}
else {
lenCode = 10;
sa = 9*RAWDATA_BITSPERBYTE;
}
}
typeByte |= lenCode;
outStream.put(typeByte);
for(;sa >= 0;sa -= RAWDATA_BITSPERBYTE) {
uint1 piece = (val >> sa) & RAWDATA_MASK;
piece |= RAWDATA_MARKER;
outStream.put(piece);
}
}
void PackedEncode::openElement(const ElementId &elemId)
{
writeHeader(ELEMENT_START, elemId.getId());
}
void PackedEncode::closeElement(const ElementId &elemId)
{
writeHeader(ELEMENT_END, elemId.getId());
}
void PackedEncode::writeBool(const AttributeId &attribId,bool val)
{
writeHeader(ATTRIBUTE, attribId.getId());
uint1 typeByte = val ? ((TYPECODE_BOOLEAN << TYPECODE_SHIFT) | 1) : (TYPECODE_BOOLEAN << TYPECODE_SHIFT);
outStream.put(typeByte);
}
void PackedEncode::writeSignedInteger(const AttributeId &attribId,intb val)
{
writeHeader(ATTRIBUTE, attribId.getId());
uint1 typeByte;
uint8 num;
if (val < 0) {
typeByte = (TYPECODE_SIGNEDINT_NEGATIVE << TYPECODE_SHIFT);
num = -val;
}
else {
typeByte = (TYPECODE_SIGNEDINT_POSITIVE << TYPECODE_SHIFT);
num = val;
}
writeInteger(typeByte, num);
}
void PackedEncode::writeUnsignedInteger(const AttributeId &attribId,uintb val)
{
writeHeader(ATTRIBUTE, attribId.getId());
writeInteger((TYPECODE_UNSIGNEDINT << TYPECODE_SHIFT),val);
}
void PackedEncode::writeString(const AttributeId &attribId,const string &val)
{
uint8 length = val.length();
writeHeader(ATTRIBUTE, attribId.getId());
writeInteger((TYPECODE_STRING << TYPECODE_SHIFT), length);
outStream.write(val.c_str(), length);
}
void PackedEncode::writeSpace(const AttributeId &attribId,const AddrSpace *spc)
{
writeHeader(ATTRIBUTE, attribId.getId());
switch(spc->getType()) {
case IPTR_FSPEC:
outStream.put((TYPECODE_SPECIALSPACE << TYPECODE_SHIFT) | SPECIALSPACE_FSPEC);
break;
case IPTR_IOP:
outStream.put((TYPECODE_SPECIALSPACE << TYPECODE_SHIFT) | SPECIALSPACE_IOP);
break;
case IPTR_JOIN:
outStream.put((TYPECODE_SPECIALSPACE << TYPECODE_SHIFT) | SPECIALSPACE_JOIN);
break;
case IPTR_SPACEBASE:
if (spc->isFormalStackSpace())
outStream.put((TYPECODE_SPECIALSPACE << TYPECODE_SHIFT) | SPECIALSPACE_STACK);
else
outStream.put((TYPECODE_SPECIALSPACE << TYPECODE_SHIFT) | SPECIALSPACE_SPACEBASE); // A secondary register offset space
break;
default:
uint8 spcId = spc->getIndex();
writeInteger((TYPECODE_ADDRESSSPACE << TYPECODE_SHIFT), spcId);
break;
}
}
// Common attributes. Attributes with multiple uses // Common attributes. Attributes with multiple uses
AttributeId ATTRIB_CONTENT = AttributeId("XMLcontent",1); AttributeId ATTRIB_CONTENT = AttributeId("XMLcontent",1);
AttributeId ATTRIB_ALIGN = AttributeId("align",2); AttributeId ATTRIB_ALIGN = AttributeId("align",2);
@ -513,4 +1044,4 @@ ElementId ELEM_VAL = ElementId("val",8);
ElementId ELEM_VALUE = ElementId("value",9); ElementId ELEM_VALUE = ElementId("value",9);
ElementId ELEM_VOID = ElementId("void",10); ElementId ELEM_VOID = ElementId("void",10);
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",251); // Number serves as next open index ElementId ELEM_UNKNOWN = ElementId("XMLunknown",270); // Number serves as next open index

View File

@ -17,6 +17,7 @@
#define __CPUI_MARSHAL__ #define __CPUI_MARSHAL__
#include "xml.hh" #include "xml.hh"
#include <list>
#include <unordered_map> #include <unordered_map>
using namespace std; using namespace std;
@ -100,11 +101,6 @@ public:
const AddrSpaceManager *getAddrSpaceManager(void) const { return spcManager; } ///< Get the manager used for address space decoding const AddrSpaceManager *getAddrSpaceManager(void) const { return spcManager; } ///< Get the manager used for address space decoding
virtual ~Decoder(void) {} ///< Destructor virtual ~Decoder(void) {} ///< Destructor
/// \brief Clear any current decoding state
///
/// Allows the same decoder to be reused. Object is ready for new call to ingestStream.
virtual void clear(void)=0;
/// \brief Prepare to decode a given stream /// \brief Prepare to decode a given stream
/// ///
/// Called once before any decoding. Currently this is assumed to make an internal copy of the stream data, /// Called once before any decoding. Currently this is assumed to make an internal copy of the stream data,
@ -262,11 +258,6 @@ class Encoder {
public: public:
virtual ~Encoder(void) {} ///< Destructor virtual ~Encoder(void) {} ///< Destructor
/// \brief Clear any state associated with the encoder
///
/// The encoder should be ready to write a new document after this call.
virtual void clear(void)=0;
/// \brief Begin a new element in the encoding /// \brief Begin a new element in the encoding
/// ///
/// The element will have the given ElementId annotation and becomes the \e current element. /// The element will have the given ElementId annotation and becomes the \e current element.
@ -333,7 +324,6 @@ public:
XmlDecode(const AddrSpaceManager *spc) : Decoder(spc) { XmlDecode(const AddrSpaceManager *spc) : Decoder(spc) {
document = (Document *)0; rootElement = (const Element *)0; attributeIndex = -1; } ///< Constructor for use with ingestStream document = (Document *)0; rootElement = (const Element *)0; attributeIndex = -1; } ///< Constructor for use with ingestStream
virtual ~XmlDecode(void); virtual ~XmlDecode(void);
virtual void clear(void);
virtual void ingestStream(istream &s); virtual void ingestStream(istream &s);
virtual uint4 peekElement(void); virtual uint4 peekElement(void);
virtual uint4 openElement(void); virtual uint4 openElement(void);
@ -364,7 +354,6 @@ class XmlEncode : public Encoder {
bool elementTagIsOpen; ///< If \b true, new attributes can be written to the current element bool elementTagIsOpen; ///< If \b true, new attributes can be written to the current element
public: public:
XmlEncode(ostream &s) : outStream(s) { elementTagIsOpen = false; } ///< Construct from a stream XmlEncode(ostream &s) : outStream(s) { elementTagIsOpen = false; } ///< Construct from a stream
virtual void clear(void) { elementTagIsOpen = false; }
virtual void openElement(const ElementId &elemId); virtual void openElement(const ElementId &elemId);
virtual void closeElement(const ElementId &elemId); virtual void closeElement(const ElementId &elemId);
virtual void writeBool(const AttributeId &attribId,bool val); virtual void writeBool(const AttributeId &attribId,bool val);
@ -374,6 +363,206 @@ public:
virtual void writeSpace(const AttributeId &attribId,const AddrSpace *spc); virtual void writeSpace(const AttributeId &attribId,const AddrSpace *spc);
}; };
/// \brief Protocol format for PackedEncode and PackedDecode classes
///
/// All bytes in the encoding are expected to be non-zero. Element encoding looks like
/// - 01xiiiii is an element start
/// - 10xiiiii is an element end
/// - 11xiiiii is an attribute start
///
/// Where iiiii is the (first) 5 bits of the element/attribute id.
/// If x=0, the id is complete. If x=1, the next byte contains 7 more bits of the id: 1iiiiiii
///
/// After an attribute start, there follows a \e type byte: ttttllll, where the first 4 bits indicate the
/// type of attribute and final 4 bits are a \b length \b code. The types are:
/// - 1 = boolean (lengthcode=0 for false, lengthcode=1 for true)
/// - 2 = positive signed integer
/// - 3 = negative signed integer (stored in negated form)
/// - 4 = unsigned integer
/// - 5 = basic address space (encoded as the integer index of the space)
/// - 6 = special address space (lengthcode 0=>stack 1=>join 2=>fspec 3=>iop)
/// - 7 = string
///
/// All attribute types except \e boolean and \e special, have an encoded integer after the \e type byte.
/// The \b length \b code, indicates the number bytes used to encode the integer, 7-bits of info per byte, 1iiiiiii.
/// A \b length \b code of zero is used to encode an integer value of 0, with no following bytes.
///
/// For strings, the integer encoded after the \e type byte, is the actual length of the string. The
/// string data itself is stored immediately after the length integer using UTF8 format.
namespace PackedFormat {
static const uint1 HEADER_MASK = 0xc0;
static const uint1 ELEMENT_START = 0x40;
static const uint1 ELEMENT_END = 0x80;
static const uint1 ATTRIBUTE = 0xc0;
static const uint1 HEADEREXTEND_MASK = 0x20;
static const uint1 ELEMENTID_MASK = 0x1f;
static const uint1 RAWDATA_MASK = 0x7f;
static const int4 RAWDATA_BITSPERBYTE = 7;
static const uint1 RAWDATA_MARKER = 0x80;
static const int4 TYPECODE_SHIFT = 4;
static const uint1 LENGTHCODE_MASK = 0xf;
static const uint1 TYPECODE_BOOLEAN = 1;
static const uint1 TYPECODE_SIGNEDINT_POSITIVE = 2;
static const uint1 TYPECODE_SIGNEDINT_NEGATIVE = 3;
static const uint1 TYPECODE_UNSIGNEDINT = 4;
static const uint1 TYPECODE_ADDRESSSPACE = 5;
static const uint1 TYPECODE_SPECIALSPACE = 6;
static const uint1 TYPECODE_STRING = 7;
static const uint4 SPECIALSPACE_STACK = 0;
static const uint4 SPECIALSPACE_JOIN = 1;
static const uint4 SPECIALSPACE_FSPEC = 2;
static const uint4 SPECIALSPACE_IOP = 3;
static const uint4 SPECIALSPACE_SPACEBASE = 4;
}
/// \brief A byte-based decoder designed to marshal info to the decompiler efficiently
///
/// The decoder expects an encoding as described in PackedFormat. When ingested, the stream bytes are
/// held in a sequence of arrays (ByteChunk). During decoding, \b this object maintains a Position in the
/// stream at the start and end of the current open element, and a Position of the next attribute to read to
/// facilitate getNextAttributeId() and associated read*() methods.
class PackedDecode : public Decoder {
public:
static const int4 BUFFER_SIZE; ///< The size, in bytes, of a single cached chunk of the input stream
private:
/// \brief A bounded array of bytes
class ByteChunk {
friend class PackedDecode;
uint1 *start; ///< Start of the byte array
uint1 *end; ///< End of the byte array
public:
ByteChunk(uint1 *s,uint1 *e) { start = s; end = e; } ///< Constructor
};
/// \brief An iterator into input stream
class Position {
friend class PackedDecode;
list<ByteChunk>::const_iterator seqIter; ///< Current byte sequence
uint1 *current; ///< Current position in sequence
uint1 *end; ///< End of current sequence
};
list<ByteChunk> inStream; ///< Incoming raw data as a sequence of byte arrays
Position startPos; ///< Position at the start of the current open element
Position curPos; ///< Position of the next attribute as returned by getNextAttributeId
Position endPos; ///< Ending position after all attributes in current open element
bool attributeRead; ///< Has the last attribute returned by getNextAttributeId been read
uint1 getByte(Position &pos) { return *pos.current; } ///< Get the byte at the current position, do not advance
uint1 getBytePlus1(Position &pos); ///< Get the byte following the current byte, do not advance position
uint1 getNextByte(Position &pos); ///< Get the byte at the current position and advance to the next byte
void advancePosition(Position &pos,int4 skip); ///< Advance the position by the given number of bytes
uint8 readInteger(int4 len); ///< Read an integer from the \e current position given its length in bytes
uint4 readLengthCode(uint1 typeByte) { return ((uint4)typeByte & PackedFormat::LENGTHCODE_MASK); } ///< Extract length code from type byte
void findMatchingAttribute(const AttributeId &attribId); ///< Find attribute matching the given id in open element
void skipAttribute(void); ///< Skip over the attribute at the current position
void skipAttributeRemaining(uint1 typeByte); ///< Skip over remaining attribute data, after a mismatch
public:
PackedDecode(const AddrSpaceManager *spcManager) : Decoder(spcManager) {} ///< Constructor
virtual ~PackedDecode(void);
virtual void ingestStream(istream &s);
virtual uint4 peekElement(void);
virtual uint4 openElement(void);
virtual uint4 openElement(const ElementId &elemId);
virtual void closeElement(uint4 id);
virtual void closeElementSkipping(uint4 id);
virtual void rewindAttributes(void);
virtual uint4 getNextAttributeId(void);
virtual bool readBool(void);
virtual bool readBool(const AttributeId &attribId);
virtual intb readSignedInteger(void);
virtual intb readSignedInteger(const AttributeId &attribId);
virtual uintb readUnsignedInteger(void);
virtual uintb readUnsignedInteger(const AttributeId &attribId);
virtual string readString(void);
virtual string readString(const AttributeId &attribId);
virtual AddrSpace *readSpace(void);
virtual AddrSpace *readSpace(const AttributeId &attribId);
};
/// \brief A byte-based encoder designed to marshal from the decompiler efficiently
///
/// See PackedDecode for details of the encoding format.
class PackedEncode : public Encoder {
ostream &outStream; ///< The stream receiving the encoded data
void writeHeader(uint1 header,uint4 id);
void writeInteger(uint1 typeByte,uint8 val);
public:
PackedEncode(ostream &s) : outStream(s) {} ///< Construct from a stream
virtual void openElement(const ElementId &elemId);
virtual void closeElement(const ElementId &elemId);
virtual void writeBool(const AttributeId &attribId,bool val);
virtual void writeSignedInteger(const AttributeId &attribId,intb val);
virtual void writeUnsignedInteger(const AttributeId &attribId,uintb val);
virtual void writeString(const AttributeId &attribId,const string &val);
virtual void writeSpace(const AttributeId &attribId,const AddrSpace *spc);
};
/// An exception is thrown if the position currently points to the last byte in the stream
/// \param pos is the position in the stream to look ahead from
/// \return the next byte
inline uint1 PackedDecode::getBytePlus1(Position &pos)
{
uint1 *ptr = pos.current + 1;
if (ptr == pos.end) {
list<ByteChunk>::const_iterator iter = pos.seqIter;
++iter;
if (iter == inStream.end())
throw DecoderError("Unexpected end of stream");
ptr = (*iter).start;
}
return *ptr;
}
/// An exception is thrown if there are no additional bytes in the stream
/// \param pos is the position of the byte
/// \return the byte at the current position
inline uint1 PackedDecode::getNextByte(Position &pos)
{
uint1 res = *pos.current;
pos.current += 1;
if (pos.current != pos.end)
return res;
++pos.seqIter;
if (pos.seqIter == inStream.end())
throw DecoderError("Unexpected end of stream");
pos.current = (*pos.seqIter).start;
pos.end = (*pos.seqIter).end;
return res;
}
/// An exception is thrown of position is advanced past the end of the stream
/// \param pos is the position being advanced
/// \param skip is the number of bytes to advance
inline void PackedDecode::advancePosition(Position &pos,int4 skip)
{
while(pos.end - pos.current <= skip) {
skip -= (pos.end - pos.current);
++pos.seqIter;
if (pos.seqIter == inStream.end())
throw DecoderError("Unexpected end of stream");
pos.current = (*pos.seqIter).start;
pos.end = (*pos.seqIter).end;
}
pos.current += skip;
}
inline void PackedEncode::writeHeader(uint1 header,uint4 id)
{
if (id > 0x1f) {
header |= PackedFormat::HEADEREXTEND_MASK;
header |= (id >> PackedFormat::RAWDATA_BITSPERBYTE);
uint1 extendByte = (id & PackedFormat::RAWDATA_MASK) | PackedFormat::RAWDATA_MARKER;
outStream.put(header);
outStream.put(extendByte);
}
else {
header |= id;
outStream.put(header);
}
}
extern ElementId ELEM_UNKNOWN; ///< Special element to represent an element with an unrecognized name extern ElementId ELEM_UNKNOWN; ///< Special element to represent an element with an unrecognized name
extern AttributeId ATTRIB_UNKNOWN; ///< Special attribute to represent an attribute with an unrecognized name extern AttributeId ATTRIB_UNKNOWN; ///< Special attribute to represent an attribute with an unrecognized name
extern AttributeId ATTRIB_CONTENT; ///< Special attribute for XML text content of an element extern AttributeId ATTRIB_CONTENT; ///< Special attribute for XML text content of an element

View File

@ -230,6 +230,7 @@ public:
const string &getOpName(void) const { return opcode->getName(); } ///< Return the name of this op const string &getOpName(void) const { return opcode->getName(); } ///< Return the name of this op
void printDebug(ostream &s) const; ///< Print debug description of this op to stream void printDebug(ostream &s) const; ///< Print debug description of this op to stream
void encode(Encoder &encoder) const; ///< Encode a description of \b this op to stream void encode(Encoder &encoder) const; ///< Encode a description of \b this op to stream
/// \brief Retrieve the PcodeOp encoded as the address \e addr /// \brief Retrieve the PcodeOp encoded as the address \e addr
static PcodeOp *getOpFromConst(const Address &addr) { return (PcodeOp *)(uintp)addr.getOffset(); } static PcodeOp *getOpFromConst(const Address &addr) { return (PcodeOp *)(uintp)addr.getOffset(); }

View File

@ -63,3 +63,39 @@ bool VarnodeData::contains(const VarnodeData &op2) const
if ((offset + (size-1)) < (op2.offset + (op2.size-1))) return false; if ((offset + (size-1)) < (op2.offset + (op2.size-1))) return false;
return true; return true;
} }
/// This assumes the \<op> element is already open.
/// Decode info suitable for call to PcodeEmit::dump. The output pointer is changed to null if there
/// is no output for this op, otherwise the existing pointer is used to store the output.
/// \param decoder is the stream decoder
/// \param isize is the (preparsed) number of input parameters for the p-code op
/// \param invar is an array of storage for the input Varnodes
/// \param outvar is a (handle) to the storage for the output Varnode
/// \return the p-code op OpCode
OpCode PcodeOpRaw::decode(Decoder &decoder,int4 isize,VarnodeData *invar,VarnodeData **outvar)
{
OpCode opcode = (OpCode)decoder.readSignedInteger(ATTRIB_CODE);
uint4 subId = decoder.peekElement();
if (subId == ELEM_VOID) {
decoder.openElement();
decoder.closeElement(subId);
*outvar = (VarnodeData *)0;
}
else {
(*outvar)->decode(decoder);
}
for(int4 i=0;i<isize;++i) {
subId = decoder.peekElement();
if (subId == ELEM_SPACEID) {
decoder.openElement();
invar[i].space = decoder.getAddrSpaceManager()->getConstantSpace();
invar[i].offset = (uintb)(uintp)decoder.readSpace(ATTRIB_NAME);
invar[i].size = sizeof(void *);
decoder.closeElement(subId);
}
else
invar[i].decode(decoder);
}
return opcode;
}

View File

@ -120,6 +120,9 @@ public:
void clearInputs(void); ///< Remove all input varnodes to this op void clearInputs(void); ///< Remove all input varnodes to this op
int4 numInput(void) const; ///< Get the number of input varnodes to this op int4 numInput(void) const; ///< Get the number of input varnodes to this op
VarnodeData *getInput(int4 i) const; ///< Get the i-th input varnode for this op VarnodeData *getInput(int4 i) const; ///< Get the i-th input varnode for this op
/// \brief Decode the raw OpCode and input/output Varnode data for a PcodeOp
static OpCode decode(Decoder &decoder,int4 isize,VarnodeData *invar,VarnodeData **outvar);
}; };
/// The core behavior for this operation is controlled by an OpBehavior object /// The core behavior for this operation is controlled by an OpBehavior object

View File

@ -287,7 +287,7 @@ void EmitMarkup::setOutputStream(ostream *t)
if (encoder != (Encoder *)0) if (encoder != (Encoder *)0)
delete encoder; delete encoder;
s = t; s = t;
encoder = new XmlEncode(*s); encoder = new PackedEncode(*s);
} }
int4 TokenSplit::countbase = 0; int4 TokenSplit::countbase = 0;

View File

@ -126,7 +126,7 @@ void SleighArchitecture::loadLanguageDescription(const string &specfile,ostream
try { try {
decoder.ingestStream(s); decoder.ingestStream(s);
} }
catch(XmlError &err) { catch(DecoderError &err) {
errs << "WARNING: Unable to parse sleigh specfile: " << specfile; errs << "WARNING: Unable to parse sleigh specfile: " << specfile;
return; return;
} }
@ -246,7 +246,7 @@ void SleighArchitecture::buildSpecFile(DocumentStorage &store)
Document *doc = store.openDocument(processorfile); Document *doc = store.openDocument(processorfile);
store.registerTag(doc->getRoot()); store.registerTag(doc->getRoot());
} }
catch(XmlError &err) { catch(DecoderError &err) {
ostringstream serr; ostringstream serr;
serr << "XML error parsing processor specification: " << processorfile; serr << "XML error parsing processor specification: " << processorfile;
serr << "\n " << err.explain; serr << "\n " << err.explain;
@ -263,7 +263,7 @@ void SleighArchitecture::buildSpecFile(DocumentStorage &store)
Document *doc = store.openDocument(compilerfile); Document *doc = store.openDocument(compilerfile);
store.registerTag(doc->getRoot()); store.registerTag(doc->getRoot());
} }
catch(XmlError &err) { catch(DecoderError &err) {
ostringstream serr; ostringstream serr;
serr << "XML error parsing compiler specification: " << compilerfile; serr << "XML error parsing compiler specification: " << compilerfile;
serr << "\n " << err.explain; serr << "\n " << err.explain;
@ -281,7 +281,7 @@ void SleighArchitecture::buildSpecFile(DocumentStorage &store)
Document *doc = store.openDocument(slafile); Document *doc = store.openDocument(slafile);
store.registerTag(doc->getRoot()); store.registerTag(doc->getRoot());
} }
catch(XmlError &err) { catch(DecoderError &err) {
ostringstream serr; ostringstream serr;
serr << "XML error parsing SLEIGH file: " << slafile; serr << "XML error parsing SLEIGH file: " << slafile;
serr << "\n " << err.explain; serr << "\n " << err.explain;

View File

@ -3577,7 +3577,7 @@ static int4 run_xml(const string &filein,SleighCompile &compiler)
try { try {
doc = xml_tree(s); doc = xml_tree(s);
} }
catch(XmlError &err) { catch(DecoderError &err) {
cerr << "Unable to parse single input file as XML spec: " << filein << endl; cerr << "Unable to parse single input file as XML spec: " << filein << endl;
exit(1); exit(1);
} }

View File

@ -170,7 +170,7 @@ uintb AddrSpace::decodeAttributes(Decoder &decoder,uint4 &size) const
offset = decoder.readUnsignedInteger(); offset = decoder.readUnsignedInteger();
} }
else if (attribId == ATTRIB_SIZE) { else if (attribId == ATTRIB_SIZE) {
size = decoder.readUnsignedInteger(); size = decoder.readSignedInteger();
} }
} }
if (!foundoffset) if (!foundoffset)
@ -316,7 +316,7 @@ void AddrSpace::decodeBasicAttributes(Decoder &decoder)
if (attribId == ATTRIB_INDEX) if (attribId == ATTRIB_INDEX)
index = decoder.readSignedInteger(); index = decoder.readSignedInteger();
else if (attribId == ATTRIB_SIZE) else if (attribId == ATTRIB_SIZE)
addressSize = decoder.readUnsignedInteger(); addressSize = decoder.readSignedInteger();
else if (attribId == ATTRIB_WORDSIZE) else if (attribId == ATTRIB_WORDSIZE)
wordsize = decoder.readUnsignedInteger(); wordsize = decoder.readUnsignedInteger();
else if (attribId == ATTRIB_BIGENDIAN) { else if (attribId == ATTRIB_BIGENDIAN) {

View File

@ -94,12 +94,13 @@ public:
does_deadcode = 4, ///< Dead-code analysis is done on this space does_deadcode = 4, ///< Dead-code analysis is done on this space
programspecific = 8, ///< Space is specific to a particular loadimage programspecific = 8, ///< Space is specific to a particular loadimage
reverse_justification = 16, ///< Justification within aligned word is opposite of endianness reverse_justification = 16, ///< Justification within aligned word is opposite of endianness
overlay = 32, ///< This space is an overlay of another space formal_stackspace = 0x20, ///< Space attached to the formal \b stack \b pointer
overlaybase = 64, ///< This is the base space for overlay space(s) overlay = 0x40, ///< This space is an overlay of another space
truncated = 128, ///< Space is truncated from its original size, expect pointers larger than this size overlaybase = 0x80, ///< This is the base space for overlay space(s)
hasphysical = 256, ///< Has physical memory associated with it truncated = 0x100, ///< Space is truncated from its original size, expect pointers larger than this size
is_otherspace = 512, ///< Quick check for the OtherSpace derived class hasphysical = 0x200, ///< Has physical memory associated with it
has_nearpointers = 0x400 ///< Does there exist near pointers into this space is_otherspace = 0x400, ///< Quick check for the OtherSpace derived class
has_nearpointers = 0x800 ///< Does there exist near pointers into this space
}; };
private: private:
spacetype type; ///< Type of space (PROCESSOR, CONSTANT, INTERNAL, ...) spacetype type; ///< Type of space (PROCESSOR, CONSTANT, INTERNAL, ...)
@ -149,6 +150,7 @@ public:
bool hasPhysical(void) const; ///< Return \b true if data is physically stored in this bool hasPhysical(void) const; ///< Return \b true if data is physically stored in this
bool isBigEndian(void) const; ///< Return \b true if values in this space are big endian bool isBigEndian(void) const; ///< Return \b true if values in this space are big endian
bool isReverseJustified(void) const; ///< Return \b true if alignment justification does not match endianness bool isReverseJustified(void) const; ///< Return \b true if alignment justification does not match endianness
bool isFormalStackSpace(void) const; ///< Return \b true if \b this is attached to the formal \b stack \b pointer
bool isOverlay(void) const; ///< Return \b true if this is an overlay space bool isOverlay(void) const; ///< Return \b true if this is an overlay space
bool isOverlayBase(void) const; ///< Return \b true if other spaces overlay this space bool isOverlayBase(void) const; ///< Return \b true if other spaces overlay this space
bool isOtherSpace(void) const; ///< Return \b true if \b this is the \e other address space bool isOtherSpace(void) const; ///< Return \b true if \b this is the \e other address space
@ -446,6 +448,11 @@ inline bool AddrSpace::isReverseJustified(void) const {
return ((flags&reverse_justification)!=0); return ((flags&reverse_justification)!=0);
} }
/// Currently an architecture can declare only one formal stack pointer.
inline bool AddrSpace::isFormalStackSpace(void) const {
return ((flags&formal_stackspace)!=0);
}
inline bool AddrSpace::isOverlay(void) const { inline bool AddrSpace::isOverlay(void) const {
return ((flags&overlay)!=0); return ((flags&overlay)!=0);
} }

View File

@ -108,7 +108,7 @@ void FunctionTestCollection::buildProgram(DocumentStorage &docStorage)
try { try {
dcp->conf->init(docStorage); dcp->conf->init(docStorage);
dcp->conf->readLoaderSymbols("::"); // Read in loader symbols dcp->conf->readLoaderSymbols("::"); // Read in loader symbols
} catch(XmlError &err) { } catch(DecoderError &err) {
errmsg = err.explain; errmsg = err.explain;
iserror = true; iserror = true;
} catch(LowlevelError &err) { } catch(LowlevelError &err) {

View File

@ -43,7 +43,7 @@ void TruncationTag::decode(Decoder &decoder)
} }
/// Construct a virtual space. This is usually used for the stack /// Construct a virtual space. This is usually used for the stack
/// space, but multiple such spaces are allowed. /// space, which is indicated by the \b isFormal parameters, but multiple such spaces are allowed.
/// \param m is the manager for this \b program \b specific address space /// \param m is the manager for this \b program \b specific address space
/// \param t is associated processor translator /// \param t is associated processor translator
/// \param nm is the name of the space /// \param nm is the name of the space
@ -51,13 +51,16 @@ void TruncationTag::decode(Decoder &decoder)
/// \param sz is the size of the space /// \param sz is the size of the space
/// \param base is the containing space /// \param base is the containing space
/// \param dl is the heritage delay /// \param dl is the heritage delay
/// \param isFormal is the formal stack space indicator
SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,int4 sz, SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,int4 sz,
AddrSpace *base,int4 dl) AddrSpace *base,int4 dl,bool isFormal)
: AddrSpace(m,t,IPTR_SPACEBASE,nm,sz,base->getWordSize(),ind,0,dl) : AddrSpace(m,t,IPTR_SPACEBASE,nm,sz,base->getWordSize(),ind,0,dl)
{ {
contain = base; contain = base;
hasbaseregister = false; // No base register assigned yet hasbaseregister = false; // No base register assigned yet
isNegativeStack = true; // default stack growth isNegativeStack = true; // default stack growth
if (isFormal)
setFlags(formal_stackspace);
} }
/// This is a partial constructor, which must be followed up /// This is a partial constructor, which must be followed up
@ -907,124 +910,24 @@ const FloatFormat *Translate::getFloatFormat(int4 size) const
/// A single pcode operation is parsed from an \<op> element and /// A single pcode operation is parsed from an \<op> element and
/// returned to the application via the PcodeEmit::dump method. /// returned to the application via the PcodeEmit::dump method.
/// \param decoder is the stream decoder /// \param decoder is the stream decoder
void PcodeEmit::decodeOp(Decoder &decoder) void PcodeEmit::decodeOp(const Address &addr,Decoder &decoder)
{ {
int4 opcode; int4 opcode;
int4 isize;
VarnodeData outvar; VarnodeData outvar;
VarnodeData invar[30]; VarnodeData invar[16];
VarnodeData *outptr; VarnodeData *outptr;
uint4 elemId = decoder.openElement(ELEM_OP); uint4 elemId = decoder.openElement(ELEM_OP);
opcode = decoder.readSignedInteger(ATTRIB_CODE); isize = decoder.readSignedInteger(ATTRIB_SIZE);
Address pc = Address::decode(decoder); outptr = &outvar;
uint4 subId = decoder.peekElement(); if (isize <= 16)
if (subId == ELEM_VOID) { opcode = PcodeOpRaw::decode(decoder, isize, invar, &outptr);
decoder.openElement();
decoder.closeElement(subId);
outptr = (VarnodeData *)0;
}
else { else {
outvar.decode(decoder); vector<VarnodeData> varStorage(isize,VarnodeData());
outptr = &outvar; opcode = PcodeOpRaw::decode(decoder, isize, varStorage.data(), &outptr);
}
int4 isize = 0;
while(isize < 30) {
subId = decoder.peekElement();
if (subId == 0) break;
if (subId == ELEM_SPACEID) {
decoder.openElement();
invar[isize].space = decoder.getAddrSpaceManager()->getConstantSpace();
invar[isize].offset = (uintb)(uintp)decoder.readSpace(ATTRIB_NAME);
invar[isize].size = sizeof(void *);
decoder.closeElement(subId);
}
else
invar[isize].decode(decoder);
isize += 1;
} }
decoder.closeElement(elemId); decoder.closeElement(elemId);
dump(pc,(OpCode)opcode,outptr,invar,isize);
}
/// A Helper function for PcodeEmit::restorePackedOp that reads an unsigned offset from a packed stream
/// \param ptr is a pointer into a packed byte stream
/// \param off is where the offset read from the stream is stored
/// \return a pointer to the next unconsumed byte of the stream
const uint1 *PcodeEmit::unpackOffset(const uint1 *ptr,uintb &off)
{
uintb res = 0;
int4 shift;
for(shift=0;shift<67;shift+=6) {
uint1 val = *ptr++;
if (val == end_tag) {
off = res;
return ptr;
}
uintb bits = ((uintb)(val-0x20))<<shift;
res |= bits;
}
throw LowlevelError("Bad packed offset");
}
/// A Helper function for PcodeEmit::restorePackedOp that reads a varnode from a packed stream
/// \param ptr is a pointer into a packed byte stream
/// \param v is the VarnodeData object being filled in by the stream
/// \param manage is the AddrSpace manager object of the associated processor
/// \return a pointer to the next unconsumed byte of the stream
const uint1 *PcodeEmit::unpackVarnodeData(const uint1 *ptr,VarnodeData &v,const AddrSpaceManager *manage)
{
uint1 tag = *ptr++;
if (tag == addrsz_tag) {
int4 spcindex = (int4)(*ptr++ - 0x20);
v.space = manage->getSpace(spcindex);
ptr = unpackOffset(ptr,v.offset);
v.size = (uint4)(*ptr++ - 0x20);
}
else if (tag == spaceid_tag) {
v.space = manage->getConstantSpace();
int4 spcindex = (int4)(*ptr++ - 0x20);
v.offset = (uintb)(uintp)manage->getSpace( spcindex );
v.size = sizeof(void *);
}
else
throw LowlevelError("Bad packed VarnodeData");
return ptr;
}
/// A convenience method for passing around pcode operations via a special packed format.
/// A single pcode operation is parsed from a byte stream and returned to the application
/// via the PcodeEmit::dump method.
/// \param addr is the address of the instruction that generated this pcode
/// \param ptr is a pointer into a packed byte stream
/// \param manage is the AddrSpace manager object of the associated processor
/// \return a pointer to the next unconsumed byte of the stream
const uint1 *PcodeEmit::restorePackedOp(const Address &addr,const uint1 *ptr,const AddrSpaceManager *manage)
{
int4 opcode;
VarnodeData outvar;
VarnodeData invar[30];
VarnodeData *outptr;
ptr += 1; // Consume the -op- tag
opcode = (int4)(*ptr++ - 0x20); // Opcode
if (*ptr == void_tag) {
ptr += 1;
outptr = (VarnodeData *)0;
}
else {
ptr = unpackVarnodeData(ptr,outvar,manage);
outptr = &outvar;
}
int4 isize = 0;
while(*ptr != end_tag) {
ptr = unpackVarnodeData(ptr,invar[isize],manage);
isize += 1;
}
ptr += 1; // Consume the end tag
dump(addr,(OpCode)opcode,outptr,invar,isize); dump(addr,(OpCode)opcode,outptr,invar,isize);
return ptr;
} }

View File

@ -108,23 +108,7 @@ public:
virtual void dump(const Address &addr,OpCode opc,VarnodeData *outvar,VarnodeData *vars,int4 isize)=0; virtual void dump(const Address &addr,OpCode opc,VarnodeData *outvar,VarnodeData *vars,int4 isize)=0;
/// Emit pcode directly from an \<op> element /// Emit pcode directly from an \<op> element
void decodeOp(Decoder &decoder); void decodeOp(const Address &addr,Decoder &decoder);
enum { // Tags for packed pcode format
unimpl_tag = 0x20,
inst_tag = 0x21,
op_tag = 0x22,
void_tag = 0x23,
spaceid_tag = 0x24,
addrsz_tag = 0x25,
end_tag = 0x60
};
/// Helper function for unpacking an offset from a pcode byte stream
static const uint1 *unpackOffset(const uint1 *ptr,uintb &off);
/// Helper function for unpacking a varnode from a pcode byte stream
static const uint1 *unpackVarnodeData(const uint1 *ptr,VarnodeData &v,const AddrSpaceManager *trans);
/// Emit pcode directly from a packed byte stream
const uint1 *restorePackedOp(const Address &addr,const uint1 *ptr,const AddrSpaceManager *trans);
}; };
/// \brief Abstract class for emitting disassembly to an application /// \brief Abstract class for emitting disassembly to an application
@ -192,7 +176,7 @@ class SpacebaseSpace : public AddrSpace {
VarnodeData baseOrig; ///< Original base register before any truncation VarnodeData baseOrig; ///< Original base register before any truncation
void setBaseRegister(const VarnodeData &data,int4 origSize,bool stackGrowth); ///< Set the base register at time space is created void setBaseRegister(const VarnodeData &data,int4 origSize,bool stackGrowth); ///< Set the base register at time space is created
public: public:
SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,int4 sz,AddrSpace *base,int4 dl); SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,int4 sz,AddrSpace *base,int4 dl,bool isFormal);
SpacebaseSpace(AddrSpaceManager *m,const Translate *t); ///< For use with decode SpacebaseSpace(AddrSpaceManager *m,const Translate *t); ///< For use with decode
virtual int4 numSpacebase(void) const; virtual int4 numSpacebase(void) const;
virtual const VarnodeData &getSpacebase(int4 i) const; virtual const VarnodeData &getSpacebase(int4 i) const;

View File

@ -20,13 +20,14 @@ Datatype *TypeFactoryGhidra::findById(const string &n,uint8 id,int4 sz)
{ {
Datatype *ct = TypeFactory::findById(n,id,sz); // Try internal find Datatype *ct = TypeFactory::findById(n,id,sz); // Try internal find
if (ct != (Datatype *)0) return ct; if (ct != (Datatype *)0) return ct;
XmlDecode decoder(glb); ArchitectureGhidra *ghidra = (ArchitectureGhidra *)glb;
PackedDecode decoder(ghidra);
try { try {
if (!((ArchitectureGhidra *)glb)->getType(n,id,decoder)) // See if ghidra knows about type if (!ghidra->getDataType(n,id,decoder)) // See if ghidra knows about type
return (Datatype *)0; return (Datatype *)0;
} }
catch(XmlError &err) { catch(DecoderError &err) {
throw LowlevelError("XML error: "+err.explain); throw LowlevelError("Decoder error: "+err.explain);
} }
ct = decodeType(decoder); // Parse ghidra's type ct = decodeType(decoder); // Parse ghidra's type
return ct; return ct;

View File

@ -2287,7 +2287,7 @@ const string &Element::getAttributeValue(const string &nm) const
for(uint4 i=0;i<attr.size();++i) for(uint4 i=0;i<attr.size();++i)
if (attr[i] == nm) if (attr[i] == nm)
return value[i]; return value[i];
throw XmlError("Unknown attribute: "+nm); throw DecoderError("Unknown attribute: "+nm);
} }
DocumentStorage::~DocumentStorage(void) DocumentStorage::~DocumentStorage(void)
@ -2312,7 +2312,7 @@ Document *DocumentStorage::openDocument(const string &filename)
{ {
ifstream s(filename.c_str()); ifstream s(filename.c_str());
if (!s) if (!s)
throw XmlError("Unable to open xml document "+filename); throw DecoderError("Unable to open xml document "+filename);
Document *res = parseDocument(s); Document *res = parseDocument(s);
s.close(); s.close();
return res; return res;
@ -2342,7 +2342,7 @@ Document *xml_tree(istream &i)
TreeHandler handle(doc); TreeHandler handle(doc);
if (0!=xml_parse(i,&handle)) { if (0!=xml_parse(i,&handle)) {
delete doc; delete doc;
throw XmlError(handle.getError()); throw DecoderError(handle.getError());
} }
return doc; return doc;
} }

View File

@ -285,9 +285,9 @@ public:
/// ///
/// This object holds the error message as passed to the SAX interface callback /// This object holds the error message as passed to the SAX interface callback
/// and is thrown as a formal exception. /// and is thrown as a formal exception.
struct XmlError { struct DecoderError {
string explain; ///< Explanatory string string explain; ///< Explanatory string
XmlError(const string &s) { explain = s; } ///< Constructor DecoderError(const string &s) { explain = s; } ///< Constructor
}; };
/// \brief Start-up the XML parser given a stream and a handler /// \brief Start-up the XML parser given a stream and a handler

View File

@ -565,7 +565,7 @@ const string &Element::getAttributeValue(const string &nm) const
for(uint4 i=0;i<attr.size();++i) for(uint4 i=0;i<attr.size();++i)
if (attr[i] == nm) if (attr[i] == nm)
return value[i]; return value[i];
throw XmlError("Unknown attribute: "+nm); throw DecoderError("Unknown attribute: "+nm);
} }
DocumentStorage::~DocumentStorage(void) DocumentStorage::~DocumentStorage(void)
@ -590,7 +590,7 @@ Document *DocumentStorage::openDocument(const string &filename)
{ {
ifstream s(filename.c_str()); ifstream s(filename.c_str());
if (!s) if (!s)
throw XmlError("Unable to open xml document "+filename); throw DecoderError("Unable to open xml document "+filename);
Document *res = parseDocument(s); Document *res = parseDocument(s);
s.close(); s.close();
return res; return res;
@ -620,7 +620,7 @@ Document *xml_tree(istream &i)
TreeHandler handle(doc); TreeHandler handle(doc);
if (0!=xml_parse(i,&handle)) { if (0!=xml_parse(i,&handle)) {
delete doc; delete doc;
throw XmlError(handle.getError()); throw DecoderError(handle.getError());
} }
return doc; return doc;
} }

View File

@ -0,0 +1,508 @@
/* ###
* 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.
*/
#include "translate.hh"
#include "test.hh"
class TestAddrSpaceManager : public AddrSpaceManager {
public:
TestAddrSpaceManager(Translate *t);
};
class DummyTranslate : public Translate {
public:
virtual void initialize(DocumentStorage &store) {}
virtual const VarnodeData &getRegister(const string &nm) const { throw LowlevelError("Cannot add register to DummyTranslate"); }
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; }
virtual void getAllRegisters(map<VarnodeData,string> &reglist) const {}
virtual void getUserOpNames(vector<string> &res) const {}
virtual int4 instructionLength(const Address &baseaddr) const { return -1; }
virtual int4 oneInstruction(PcodeEmit &emit,const Address &baseaddr) const { return -1; }
virtual int4 printAssembly(AssemblyEmit &emit,const Address &baseaddr) const { return -1; }
};
class MarshalTestEnvironment {
DummyTranslate translate;
TestAddrSpaceManager addrSpaceManage;
public:
MarshalTestEnvironment(void);
static void build(void);
};
static AddrSpaceManager *spcManager = (AddrSpaceManager *)0;
static MarshalTestEnvironment theEnviron;
TestAddrSpaceManager::TestAddrSpaceManager(Translate *t)
: AddrSpaceManager()
{
insertSpace(new AddrSpace(this,t,IPTR_PROCESSOR,"ram",8,1,3,AddrSpace::hasphysical,1));
}
MarshalTestEnvironment::MarshalTestEnvironment(void)
: translate(), addrSpaceManage(&translate)
{
}
void MarshalTestEnvironment::build(void)
{
spcManager = &theEnviron.addrSpaceManage;
}
void test_signed_attributes(ostringstream &outStream,Encoder &encoder,Decoder &decoder)
{
encoder.openElement(ELEM_ADDR);
encoder.writeSignedInteger(ATTRIB_ALIGN, 3); // 7-bits
encoder.writeSignedInteger(ATTRIB_BIGENDIAN, -0x100); // 14-bits
encoder.writeSignedInteger(ATTRIB_CONSTRUCTOR, 0x1fffff); // 21-bits
encoder.writeSignedInteger(ATTRIB_DESTRUCTOR, -0xabcdefa); // 28-bits
encoder.writeSignedInteger(ATTRIB_EXTRAPOP, 0x300000000); // 35-bits
encoder.writeSignedInteger(ATTRIB_FORMAT, -0x30101010101); // 42-bits
encoder.writeSignedInteger(ATTRIB_ID, 0x123456789011); // 49-bits
encoder.writeSignedInteger(ATTRIB_INDEX, -0xf0f0f0f0f0f0f0); // 56-bits
encoder.writeSignedInteger(ATTRIB_METATYPE, 0x7fffffffffffffff); // 63-bits
encoder.closeElement(ELEM_ADDR);
istringstream inStream(outStream.str());
decoder.ingestStream(inStream);
uint4 el = decoder.openElement(ELEM_ADDR);
uint4 flags = 0;
for(;;) {
uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId == ATTRIB_ALIGN) {
int8 val = decoder.readSignedInteger();
flags |= 1;
ASSERT_EQUALS(val, 3);
}
else if (attribId == ATTRIB_BIGENDIAN) {
int8 val = decoder.readSignedInteger();
flags |= 2;
ASSERT_EQUALS(val, -0x100);
}
else if (attribId == ATTRIB_CONSTRUCTOR) {
int8 val = decoder.readSignedInteger();
flags |= 4;
ASSERT_EQUALS(val, 0x1fffff);
}
else if (attribId == ATTRIB_DESTRUCTOR) {
int8 val = decoder.readSignedInteger();
flags |= 8;
ASSERT_EQUALS(val, -0xabcdefa);
}
else if (attribId == ATTRIB_EXTRAPOP) {
int8 val = decoder.readSignedInteger();
flags |= 0x10;
ASSERT_EQUALS(val, 0x300000000);
}
else if (attribId == ATTRIB_FORMAT) {
int8 val = decoder.readSignedInteger();
flags |= 0x20;
ASSERT_EQUALS(val, -0x30101010101);
}
else if (attribId == ATTRIB_ID) {
int8 val = decoder.readSignedInteger();
flags |= 0x40;
ASSERT_EQUALS(val, 0x123456789011);
}
else if (attribId == ATTRIB_INDEX) {
int8 val = decoder.readSignedInteger();
flags |= 0x80;
ASSERT_EQUALS(val, -0xf0f0f0f0f0f0f0);
}
else if (attribId == ATTRIB_METATYPE) {
int8 val = decoder.readSignedInteger();
flags |= 0x100;
ASSERT_EQUALS(val, 0x7fffffffffffffff);
}
}
decoder.closeElement(el);
ASSERT_EQUALS(flags,0x1ff);
}
void test_unsigned_attributes(ostringstream &outStream,Encoder &encoder,Decoder &decoder)
{
encoder.openElement(ELEM_ADDR);
encoder.writeUnsignedInteger(ATTRIB_ALIGN, 3); // 7-bits
encoder.writeUnsignedInteger(ATTRIB_BIGENDIAN, 0x100); // 14-bits
encoder.writeUnsignedInteger(ATTRIB_CONSTRUCTOR, 0x1fffff); // 21-bits
encoder.writeUnsignedInteger(ATTRIB_DESTRUCTOR, 0xabcdefa); // 28-bits
encoder.writeUnsignedInteger(ATTRIB_EXTRAPOP, 0x300000000); // 35-bits
encoder.writeUnsignedInteger(ATTRIB_FORMAT, 0x30101010101); // 42-bits
encoder.writeUnsignedInteger(ATTRIB_ID, 0x123456789011); // 49-bits
encoder.writeUnsignedInteger(ATTRIB_INDEX, 0xf0f0f0f0f0f0f0); // 56-bits
encoder.writeUnsignedInteger(ATTRIB_METATYPE, 0x7fffffffffffffff); // 63-bits
encoder.writeUnsignedInteger(ATTRIB_MODEL, 0x8000000000000000); // 64-bits
encoder.closeElement(ELEM_ADDR);
istringstream inStream(outStream.str());
decoder.ingestStream(inStream);
uint4 el = decoder.openElement(ELEM_ADDR);
uint8 val = decoder.readUnsignedInteger(ATTRIB_ALIGN);
ASSERT_EQUALS(val, 3);
val = decoder.readUnsignedInteger(ATTRIB_BIGENDIAN);
ASSERT_EQUALS(val, 0x100);
val = decoder.readUnsignedInteger(ATTRIB_CONSTRUCTOR);
ASSERT_EQUALS(val, 0x1fffff);
val = decoder.readUnsignedInteger(ATTRIB_DESTRUCTOR);
ASSERT_EQUALS(val, 0xabcdefa);
val = decoder.readUnsignedInteger(ATTRIB_EXTRAPOP);
ASSERT_EQUALS(val, 0x300000000);
val = decoder.readUnsignedInteger(ATTRIB_FORMAT);
ASSERT_EQUALS(val, 0x30101010101);
val = decoder.readUnsignedInteger(ATTRIB_ID);
ASSERT_EQUALS(val, 0x123456789011);
val = decoder.readUnsignedInteger(ATTRIB_INDEX);
ASSERT_EQUALS(val, 0xf0f0f0f0f0f0f0);
val = decoder.readUnsignedInteger(ATTRIB_METATYPE);
ASSERT_EQUALS(val, 0x7fffffffffffffff);
val = decoder.readUnsignedInteger(ATTRIB_MODEL);
ASSERT_EQUALS(val, 0x8000000000000000);
decoder.closeElement(el);
}
TEST(marshal_signed_packed) {
ostringstream outStream;
theEnviron.build();
PackedEncode encoder(outStream);
PackedDecode decoder(spcManager);
test_signed_attributes(outStream, encoder, decoder);
}
TEST(marshal_signed_xml) {
ostringstream outStream;
theEnviron.build();
XmlEncode encoder(outStream);
XmlDecode decoder(spcManager);
test_signed_attributes(outStream, encoder, decoder);
}
TEST(marshal_unsigned_packed) {
ostringstream outStream;
theEnviron.build();
PackedEncode encoder(outStream);
PackedDecode decoder(spcManager);
test_unsigned_attributes(outStream, encoder, decoder);
}
TEST(marshal_unsigned_xml) {
ostringstream outStream;
theEnviron.build();
XmlEncode encoder(outStream);
XmlDecode decoder(spcManager);
test_unsigned_attributes(outStream, encoder, decoder);
}
void test_attributes(ostringstream &outStream,Encoder &encoder,Decoder &decoder)
{
encoder.openElement(ELEM_DATA);
encoder.writeBool(ATTRIB_ALIGN, true);
encoder.writeBool(ATTRIB_BIGENDIAN, false);
AddrSpace *spc = spcManager->getSpace(3);
encoder.writeSpace(ATTRIB_SPACE, spc);
encoder.writeString(ATTRIB_VAL,""); // Empty string
encoder.writeString(ATTRIB_VALUE,"hello");
encoder.writeString(ATTRIB_CONSTRUCTOR,"<<\xe2\x82\xac>>&\"bl a h\'\\bleh\n\t");
string longString = "one to three four five six seven eight nine ten eleven twelve thirteen "
"fourteen fifteen sixteen seventeen eighteen nineteen twenty twenty one "
"blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah";
encoder.writeString(ATTRIB_DESTRUCTOR,longString);
encoder.closeElement(ELEM_DATA);
istringstream inStream(outStream.str());
decoder.ingestStream(inStream);
uint4 el = decoder.openElement(ELEM_DATA);
bool bval = decoder.readBool(ATTRIB_ALIGN);
ASSERT(bval);
bval = decoder.readBool(ATTRIB_BIGENDIAN);
ASSERT(!bval);
spc = decoder.readSpace(ATTRIB_SPACE);
ASSERT_EQUALS(spc,spcManager->getSpace(3));
string val = decoder.readString(ATTRIB_VAL);
ASSERT_EQUALS(val,"");
val = decoder.readString(ATTRIB_VALUE);
ASSERT_EQUALS(val,"hello");
val = decoder.readString(ATTRIB_CONSTRUCTOR);
ASSERT_EQUALS(val,"<<\xe2\x82\xac>>&\"bl a h\'\\bleh\n\t");
val = decoder.readString(ATTRIB_DESTRUCTOR);
ASSERT_EQUALS(val,longString);
decoder.closeElement(el);
}
TEST(marshal_attribs_packed) {
ostringstream outStream;
theEnviron.build();
PackedEncode encoder(outStream);
PackedDecode decoder(spcManager);
test_attributes(outStream, encoder, decoder);
}
TEST(marshal_attribs_xml) {
ostringstream outStream;
theEnviron.build();
XmlEncode encoder(outStream);
XmlDecode decoder(spcManager);
test_attributes(outStream, encoder, decoder);
}
void test_hierarchy(ostringstream &outStream,Encoder &encoder,Decoder &decoder)
{
encoder.openElement(ELEM_DATA); // el1
encoder.writeBool(ATTRIB_CONTENT, true);
encoder.openElement(ELEM_INPUT); // el2
encoder.openElement(ELEM_OUTPUT); // el3
encoder.writeSignedInteger(ATTRIB_ID, 0x1000);
encoder.openElement(ELEM_DATA); // el4
encoder.openElement(ELEM_DATA); // el5
encoder.openElement(ELEM_OFF); // el6
encoder.closeElement(ELEM_OFF);
encoder.openElement(ELEM_OFF); // el6
encoder.writeString(ATTRIB_ID,"blahblah");
encoder.closeElement(ELEM_OFF);
encoder.openElement(ELEM_OFF); // el6
encoder.closeElement(ELEM_OFF);
encoder.closeElement(ELEM_DATA); // close el5
encoder.closeElement(ELEM_DATA); // close el4
encoder.openElement(ELEM_SYMBOL); // skip4
encoder.writeUnsignedInteger(ATTRIB_ID, 17);
encoder.openElement(ELEM_TARGET); // skip5
encoder.closeElement(ELEM_TARGET); // close skip5
encoder.closeElement(ELEM_SYMBOL); // close skip4
encoder.closeElement(ELEM_OUTPUT); // close el3
encoder.closeElement(ELEM_INPUT); // close el2
encoder.openElement(ELEM_INPUT); // el2
encoder.closeElement(ELEM_INPUT);
encoder.openElement(ELEM_INPUT); // el2
encoder.closeElement(ELEM_INPUT);
encoder.openElement(ELEM_INPUT); // el2
encoder.closeElement(ELEM_INPUT);
encoder.openElement(ELEM_INPUT); // el2
encoder.closeElement(ELEM_INPUT);
encoder.openElement(ELEM_INPUT); // el2
encoder.closeElement(ELEM_INPUT);
encoder.openElement(ELEM_INPUT); // el2
encoder.closeElement(ELEM_INPUT);
encoder.closeElement(ELEM_DATA); // close el1
istringstream inStream(outStream.str());
decoder.ingestStream(inStream);
uint4 el1 = decoder.openElement(ELEM_DATA);
// Skip over the bool
uint4 el2 = decoder.openElement(ELEM_INPUT);
uint4 el3 = decoder.openElement(ELEM_OUTPUT);
int4 val = decoder.readSignedInteger(ATTRIB_ID);
ASSERT_EQUALS(val, 0x1000);
uint4 el4 = decoder.peekElement();
ASSERT_EQUALS(el4, ELEM_DATA.getId());
decoder.openElement();
uint4 el5 = decoder.openElement();
ASSERT_EQUALS(el5, ELEM_DATA.getId());
uint4 el6 = decoder.openElement(ELEM_OFF);
decoder.closeElement(el6);
el6 = decoder.openElement(ELEM_OFF);
decoder.closeElement(el6);
el6 = decoder.openElement(ELEM_OFF);
decoder.closeElement(el6);
decoder.closeElement(el5);
decoder.closeElement(el4);
decoder.closeElementSkipping(el3);
decoder.closeElement(el2);
el2 = decoder.openElement(ELEM_INPUT);
decoder.closeElement(el2);
el2 = decoder.openElement(ELEM_INPUT);
decoder.closeElement(el2);
decoder.closeElementSkipping(el1);
}
TEST(marshal_hierarchy_packed) {
ostringstream outStream;
theEnviron.build();
PackedEncode encoder(outStream);
PackedDecode decoder(spcManager);
test_hierarchy(outStream, encoder, decoder);
}
TEST(marshal_hierarchy_xml) {
ostringstream outStream;
theEnviron.build();
XmlEncode encoder(outStream);
XmlDecode decoder(spcManager);
test_hierarchy(outStream, encoder, decoder);
}
void test_unexpected_eof(ostringstream &outStream,Encoder &encoder,Decoder &decoder)
{
encoder.openElement(ELEM_DATA);
encoder.openElement(ELEM_INPUT);
encoder.writeString(ATTRIB_NAME,"hello");
encoder.closeElement(ELEM_INPUT);
bool sawUnexpectedError = false;
try {
istringstream inStream(outStream.str());
decoder.ingestStream(inStream);
uint4 el1 = decoder.openElement(ELEM_DATA);
uint4 el2 = decoder.openElement(ELEM_INPUT);
decoder.closeElement(el2);
decoder.closeElement(el1);
} catch(DecoderError &err) {
sawUnexpectedError = true;
}
ASSERT(sawUnexpectedError);
}
TEST(marshal_unexpected_packed) {
ostringstream outStream;
theEnviron.build();
PackedEncode encoder(outStream);
PackedDecode decoder(spcManager);
test_unexpected_eof(outStream, encoder, decoder);
}
TEST(marshal_unexpected_xml) {
ostringstream outStream;
theEnviron.build();
XmlEncode encoder(outStream);
XmlDecode decoder(spcManager);
test_unexpected_eof(outStream, encoder, decoder);
}
void test_noremaining(ostringstream &outStream,Encoder &encoder,Decoder &decoder)
{
encoder.openElement(ELEM_INPUT);
encoder.openElement(ELEM_OFF);
encoder.closeElement(ELEM_OFF);
encoder.closeElement(ELEM_INPUT);
istringstream inStream(outStream.str());
decoder.ingestStream(inStream);
decoder.openElement(ELEM_INPUT);
uint4 el2 = decoder.openElement(ELEM_OFF);
decoder.closeElement(el2);
bool sawNoRemaining = false;
try {
el2 = decoder.openElement(ELEM_OFF);
} catch(DecoderError &err) {
sawNoRemaining = true;
}
ASSERT(sawNoRemaining);
}
void test_openmismatch(ostringstream &outStream,Encoder &encoder,Decoder &decoder)
{
encoder.openElement(ELEM_INPUT);
encoder.openElement(ELEM_OFF);
encoder.closeElement(ELEM_OFF);
encoder.closeElement(ELEM_INPUT);
istringstream inStream(outStream.str());
decoder.ingestStream(inStream);
decoder.openElement(ELEM_INPUT);
bool sawOpenMismatch = false;
try {
decoder.openElement(ELEM_OUTPUT);
} catch(DecoderError &err) {
sawOpenMismatch = true;
}
ASSERT(sawOpenMismatch);
}
void test_closemismatch(ostringstream &outStream,Encoder &encoder,Decoder &decoder)
{
encoder.openElement(ELEM_INPUT);
encoder.openElement(ELEM_OFF);
encoder.closeElement(ELEM_OFF);
encoder.closeElement(ELEM_INPUT);
istringstream inStream(outStream.str());
decoder.ingestStream(inStream);
uint4 el1 = decoder.openElement(ELEM_INPUT);
bool sawCloseMismatch = false;
try {
decoder.closeElement(el1);
} catch(DecoderError &err) {
sawCloseMismatch = true;
}
ASSERT(sawCloseMismatch);
}
TEST(marshal_noremaining_packed) {
ostringstream outStream;
theEnviron.build();
PackedEncode encoder(outStream);
PackedDecode decoder(spcManager);
test_noremaining(outStream, encoder, decoder);
}
TEST(marshal_noremaining_xml) {
ostringstream outStream;
theEnviron.build();
XmlEncode encoder(outStream);
XmlDecode decoder(spcManager);
test_noremaining(outStream, encoder, decoder);
}
TEST(marshal_openmismatch_packed) {
ostringstream outStream;
theEnviron.build();
PackedEncode encoder(outStream);
PackedDecode decoder(spcManager);
test_openmismatch(outStream, encoder, decoder);
}
TEST(marshal_openmismatch_xml) {
ostringstream outStream;
theEnviron.build();
XmlEncode encoder(outStream);
XmlDecode decoder(spcManager);
test_openmismatch(outStream, encoder, decoder);
}
TEST(marshal_closemismatch_packed) {
ostringstream outStream;
theEnviron.build();
PackedEncode encoder(outStream);
PackedDecode decoder(spcManager);
test_closemismatch(outStream, encoder, decoder);
}
TEST(marshal_bufferpad) {
ASSERT_EQUALS(PackedDecode::BUFFER_SIZE,1024);
ostringstream s;
PackedEncode encoder(s);
encoder.openElement(ELEM_INPUT); // 1-byte
for(int4 i=0;i<511;++i) // 1022-bytes
encoder.writeBool(ATTRIB_CONTENT, (i&1) == 0);
encoder.closeElement(ELEM_INPUT);
ASSERT_EQUALS(s.str().length(),1024); // Encoding should exactly fill one buffer
istringstream s2(s.str());
PackedDecode decoder(spcManager);
decoder.ingestStream(s2);
uint4 el = decoder.openElement(ELEM_INPUT);
for(int4 i=0;i<511;++i) {
uint4 attribId = decoder.getNextAttributeId();
ASSERT_EQUALS(attribId,ATTRIB_CONTENT.getId());
bool val = decoder.readBool();
ASSERT_EQUALS(val, (i&1) == 0);
}
uint4 nextel = decoder.peekElement();
ASSERT_EQUALS(nextel,0);
decoder.closeElement(el);
}

View File

@ -31,7 +31,7 @@ public:
static void build(void); static void build(void);
}; };
TypeTestEnvironment theEnviron; static TypeTestEnvironment theEnviron;
TypeTestEnvironment::TypeTestEnvironment(void) TypeTestEnvironment::TypeTestEnvironment(void)

View File

@ -36,8 +36,8 @@ public class ClangBreak extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
indent = (int) decoder.readSignedInteger(AttributeId.ATTRIB_INDENT); indent = (int) decoder.readSignedInteger(AttributeId.ATTRIB_INDENT);
super.decode(decoder, pfactory); setText("");
} }
} }

View File

@ -56,7 +56,7 @@ public class ClangCommentToken extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
AddressSpace spc = decoder.readSpace(AttributeId.ATTRIB_SPACE); AddressSpace spc = decoder.readSpace(AttributeId.ATTRIB_SPACE);
long offset = decoder.readUnsignedInteger(AttributeId.ATTRIB_OFF); long offset = decoder.readUnsignedInteger(AttributeId.ATTRIB_OFF);
srcaddr = spc.getAddress(offset); srcaddr = spc.getAddress(offset);

View File

@ -54,7 +54,7 @@ public class ClangFieldToken extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
String datatypestring = null; String datatypestring = null;
long id = 0; long id = 0;
for (;;) { for (;;) {

View File

@ -66,7 +66,7 @@ public class ClangFuncNameToken extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) { for (;;) {
int attribId = decoder.getNextAttributeId(); int attribId = decoder.getNextAttributeId();
if (attribId == 0) { if (attribId == 0) {

View File

@ -43,7 +43,7 @@ public class ClangLabelToken extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
AddressSpace spc = decoder.readSpace(AttributeId.ATTRIB_SPACE); AddressSpace spc = decoder.readSpace(AttributeId.ATTRIB_SPACE);
long offset = decoder.readUnsignedInteger(AttributeId.ATTRIB_OFF); long offset = decoder.readUnsignedInteger(AttributeId.ATTRIB_OFF);
blockaddr = spc.getAddress(offset); blockaddr = spc.getAddress(offset);

View File

@ -36,7 +36,7 @@ public abstract class ClangMarkup { // Placeholder for CLANG XML identifiers
public static final String GLOBAL_COLOR = "global"; public static final String GLOBAL_COLOR = "global";
public static ClangTokenGroup buildClangTree(Decoder decoder, HighFunction hfunc) public static ClangTokenGroup buildClangTree(Decoder decoder, HighFunction hfunc)
throws PcodeXMLException { throws DecoderException {
ClangTokenGroup docroot; ClangTokenGroup docroot;
int el = decoder.openElement(); int el = decoder.openElement();
if (el == ElementId.ELEM_FUNCTION.id()) { if (el == ElementId.ELEM_FUNCTION.id()) {

View File

@ -61,7 +61,7 @@ public class ClangOpToken extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) { for (;;) {
int attribId = decoder.getNextAttributeId(); int attribId = decoder.getNextAttributeId();
if (attribId == 0) { if (attribId == 0) {

View File

@ -50,7 +50,7 @@ public class ClangReturnType extends ClangTokenGroup {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) { for (;;) {
int attribId = decoder.getNextAttributeId(); int attribId = decoder.getNextAttributeId();
if (attribId == 0) { if (attribId == 0) {

View File

@ -48,7 +48,7 @@ public class ClangStatement extends ClangTokenGroup {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) { for (;;) {
int attribId = decoder.getNextAttributeId(); int attribId = decoder.getNextAttributeId();
if (attribId == 0) { if (attribId == 0) {

View File

@ -56,7 +56,7 @@ public class ClangSyntaxToken extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) { for (;;) {
int attribId = decoder.getNextAttributeId(); int attribId = decoder.getNextAttributeId();
if (attribId == 0) { if (attribId == 0) {

View File

@ -155,7 +155,7 @@ public class ClangToken implements ClangNode {
this.text = text; this.text = text;
} }
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
String col = null; String col = null;
for (;;) { for (;;) {
int attribId = decoder.getNextAttributeId(); int attribId = decoder.getNextAttributeId();
@ -177,7 +177,7 @@ public class ClangToken implements ClangNode {
} }
static public ClangToken buildToken(int node, ClangNode par, Decoder decoder, static public ClangToken buildToken(int node, ClangNode par, Decoder decoder,
PcodeFactory pfactory) throws PcodeXMLException { PcodeFactory pfactory) throws DecoderException {
ClangToken token = null; ClangToken token = null;
if (node == ELEM_VARIABLE.id()) { if (node == ELEM_VARIABLE.id()) {
token = new ClangVariableToken(par); token = new ClangVariableToken(par);
@ -207,7 +207,7 @@ public class ClangToken implements ClangNode {
token = new ClangFieldToken(par); token = new ClangFieldToken(par);
} }
else { else {
throw new PcodeXMLException("Expecting token element"); throw new DecoderException("Expecting token element");
} }
token.decode(decoder, pfactory); token.decode(decoder, pfactory);
return token; return token;

View File

@ -106,7 +106,7 @@ public class ClangTokenGroup implements ClangNode, Iterable<ClangNode> {
} }
} }
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) { for (;;) {
int elem = decoder.openElement(); int elem = decoder.openElement();
if (elem == 0) { if (elem == 0) {

View File

@ -51,7 +51,7 @@ public class ClangTypeToken extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
long id = 0; long id = 0;
for (;;) { for (;;) {
int attribId = decoder.getNextAttributeId(); int attribId = decoder.getNextAttributeId();

View File

@ -51,7 +51,7 @@ public class ClangVariableDecl extends ClangTokenGroup {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
long symref = decoder.readUnsignedInteger(AttributeId.ATTRIB_SYMREF); long symref = decoder.readUnsignedInteger(AttributeId.ATTRIB_SYMREF);
super.decode(decoder, pfactory); super.decode(decoder, pfactory);
HighSymbol sym = pfactory.getSymbol(symref); HighSymbol sym = pfactory.getSymbol(symref);

View File

@ -86,7 +86,7 @@ public class ClangVariableToken extends ClangToken {
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) { for (;;) {
int attribId = decoder.getNextAttributeId(); int attribId = decoder.getNextAttributeId();
if (attribId == 0) { if (attribId == 0) {

View File

@ -27,7 +27,6 @@ import generic.jar.ResourceFile;
import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.plugin.processors.sleigh.UniqueLayout; import ghidra.app.plugin.processors.sleigh.UniqueLayout;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
@ -49,7 +48,7 @@ import ghidra.util.task.TaskMonitor;
* DecompInterface ifc = new DecompInterface(); * DecompInterface ifc = new DecompInterface();
* *
* // Setup any options or other initialization * // Setup any options or other initialization
* ifc.setOptions(xmlOptions); // Inform interface of global options * ifc.setOptions(options); // Inform interface of global options
* // ifc.toggleSyntaxTree(false); // Don't produce syntax trees * // ifc.toggleSyntaxTree(false); // Don't produce syntax trees
* // ifc.toggleCCode(false); // Don't produce C code * // ifc.toggleCCode(false); // Don't produce C code
* // ifc.setSimplificationStyle("normalize"); // Alternate analysis style * // ifc.setSimplificationStyle("normalize"); // Alternate analysis style
@ -88,7 +87,9 @@ public class DecompInterface {
protected CompilerSpec compilerSpec; protected CompilerSpec compilerSpec;
protected DecompileProcess decompProcess; protected DecompileProcess decompProcess;
protected DecompileCallback decompCallback; protected DecompileCallback decompCallback;
protected Encoder encoder; protected PackedEncode paramEncode; // Encoder for decompiler command parameters
protected Decoder decoder; // Decoder for the Decompiler's main outputs
protected StringIngest stringResponse = new StringIngest(); // Ingester for simple responses
private DecompileDebug debug; private DecompileDebug debug;
protected CancelledListener monitorListener = new CancelledListener() { protected CancelledListener monitorListener = new CancelledListener() {
@Override @Override
@ -99,7 +100,7 @@ public class DecompInterface {
// Initialization state // Initialization state
private String actionname; // Name of simplification action private String actionname; // Name of simplification action
private DecompileOptions xmlOptions; // Current decompiler options private DecompileOptions options; // Current decompiler options
private boolean printSyntaxTree; // Whether syntax tree is returned private boolean printSyntaxTree; // Whether syntax tree is returned
private boolean printCCode; // Whether C code is returned private boolean printCCode; // Whether C code is returned
private boolean sendParamMeasures; // Whether Parameter Measures are returned private boolean sendParamMeasures; // Whether Parameter Measures are returned
@ -110,8 +111,9 @@ public class DecompInterface {
pcodelanguage = null; pcodelanguage = null;
dtmanage = null; dtmanage = null;
decompCallback = null; decompCallback = null;
xmlOptions = null; options = null;
encoder = null; paramEncode = null;
decoder = null;
debug = null; debug = null;
decompileMessage = ""; decompileMessage = "";
compilerSpec = null; compilerSpec = null;
@ -215,31 +217,33 @@ public class DecompInterface {
decompProcess = DecompileProcessFactory.get(); decompProcess = DecompileProcessFactory.get();
} }
long uniqueBase = UniqueLayout.SLEIGH_BASE.getOffset(pcodelanguage); long uniqueBase = UniqueLayout.SLEIGH_BASE.getOffset(pcodelanguage);
encoder.clear(); XmlEncode xmlEncode = new XmlEncode();
pcodelanguage.encodeTranslator(encoder, program.getAddressFactory(), uniqueBase); pcodelanguage.encodeTranslator(xmlEncode, program.getAddressFactory(), uniqueBase);
String tspec = encoder.toString(); String tspec = xmlEncode.toString();
encoder.clear(); xmlEncode.clear();
dtmanage.encodeCoreTypes(encoder); dtmanage.encodeCoreTypes(xmlEncode);
String coretypes = encoder.toString(); String coretypes = xmlEncode.toString();
SleighLanguageDescription sleighdescription = SleighLanguageDescription sleighdescription =
(SleighLanguageDescription) pcodelanguage.getLanguageDescription(); (SleighLanguageDescription) pcodelanguage.getLanguageDescription();
ResourceFile pspecfile = sleighdescription.getSpecFile(); ResourceFile pspecfile = sleighdescription.getSpecFile();
String pspecxml = fileToString(pspecfile); String pspecxml = fileToString(pspecfile);
XmlEncode xmlEncode = new XmlEncode(); xmlEncode.clear();
compilerSpec.encode(xmlEncode); compilerSpec.encode(xmlEncode);
String cspecxml = xmlEncode.toString(); String cspecxml = xmlEncode.toString();
decompCallback.setNativeMessage(null); decompCallback.setNativeMessage(null);
decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes); decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes,
program);
String nativeMessage = decompCallback.getNativeMessage(); String nativeMessage = decompCallback.getNativeMessage();
if ((nativeMessage != null) && (nativeMessage.length() != 0)) { if ((nativeMessage != null) && (nativeMessage.length() != 0)) {
throw new IOException("Could not register program: " + nativeMessage); throw new IOException("Could not register program: " + nativeMessage);
} }
if (xmlOptions != null) { if (options != null) {
decompProcess.setMaxResultSize(xmlOptions.getMaxPayloadMBytes()); paramEncode.clear();
if (!decompProcess.sendCommand1Param("setOptions", xmlOptions.getXML(this)) options.encode(paramEncode, this);
.toString() decompProcess.setMaxResultSize(options.getMaxPayloadMBytes());
.equals("t")) { decompProcess.sendCommand1Param("setOptions", paramEncode, stringResponse);
if (!stringResponse.toString().equals("t")) {
throw new IOException("Did not accept decompiler options"); throw new IOException("Did not accept decompiler options");
} }
} }
@ -247,35 +251,32 @@ public class DecompInterface {
throw new IOException("Decompile action not specified"); throw new IOException("Decompile action not specified");
} }
if (!actionname.equals("decompile")) { if (!actionname.equals("decompile")) {
if (!decompProcess.sendCommand2Params("setAction", actionname, "") decompProcess.sendCommand2Params("setAction", actionname, "", stringResponse);
.toString() if (!stringResponse.toString().equals("t")) {
.equals("t")) {
throw new IOException("Could not set decompile action"); throw new IOException("Could not set decompile action");
} }
} }
if (!printSyntaxTree) { if (!printSyntaxTree) {
if (!decompProcess.sendCommand2Params("setAction", "", "notree") decompProcess.sendCommand2Params("setAction", "", "notree", stringResponse);
.toString() if (!stringResponse.toString().equals("t")) {
.equals("t")) {
throw new IOException("Could not turn off syntax tree"); throw new IOException("Could not turn off syntax tree");
} }
} }
if (!printCCode) { if (!printCCode) {
if (!decompProcess.sendCommand2Params("setAction", "", "noc").toString().equals("t")) { decompProcess.sendCommand2Params("setAction", "", "noc", stringResponse);
if (!stringResponse.toString().equals("t")) {
throw new IOException("Could not turn off C printing"); throw new IOException("Could not turn off C printing");
} }
} }
if (sendParamMeasures) { if (sendParamMeasures) {
if (!decompProcess.sendCommand2Params("setAction", "", "parammeasures") decompProcess.sendCommand2Params("setAction", "", "parammeasures", stringResponse);
.toString() if (!stringResponse.toString().equals("t")) {
.equals("t")) {
throw new IOException("Could not turn on sending of parameter measures"); throw new IOException("Could not turn on sending of parameter measures");
} }
} }
if (jumpLoad) { if (jumpLoad) {
if (!decompProcess.sendCommand2Params("setAction", "", "jumpload") decompProcess.sendCommand2Params("setAction", "", "jumpload", stringResponse);
.toString() if (!stringResponse.toString().equals("t")) {
.equals("t")) {
throw new IOException("Could not turn on jumptable loads"); throw new IOException("Could not turn on jumptable loads");
} }
} }
@ -322,7 +323,8 @@ public class DecompInterface {
compilerSpec = spec; compilerSpec = spec;
dtmanage = new PcodeDataTypeManager(prog); dtmanage = new PcodeDataTypeManager(prog);
encoder = new XmlEncode(); paramEncode = new PackedEncode();
decoder = new PackedDecode(prog.getAddressFactory());
try { try {
decompCallback = decompCallback =
new DecompileCallback(prog, pcodelanguage, program.getCompilerSpec(), dtmanage); new DecompileCallback(prog, pcodelanguage, program.getCompilerSpec(), dtmanage);
@ -344,7 +346,8 @@ public class DecompInterface {
} }
program = null; program = null;
decompCallback = null; decompCallback = null;
encoder = null; paramEncode = null;
decoder = null;
return false; return false;
} }
@ -360,7 +363,8 @@ public class DecompInterface {
if (program != null) { if (program != null) {
program = null; program = null;
decompCallback = null; decompCallback = null;
encoder = null; paramEncode = null;
decoder = null;
try { try {
if ((decompProcess != null) && decompProcess.isReady()) { if ((decompProcess != null) && decompProcess.isReady()) {
decompProcess.deregisterProgram(); decompProcess.deregisterProgram();
@ -422,9 +426,8 @@ public class DecompInterface {
} }
try { try {
verifyProcess(); verifyProcess();
return decompProcess.sendCommand2Params("setAction", actionstring, "") decompProcess.sendCommand2Params("setAction", actionstring, "", stringResponse);
.toString() return stringResponse.toString().equals("t");
.equals("t");
} }
catch (IOException e) { catch (IOException e) {
// don't care // don't care
@ -460,9 +463,8 @@ public class DecompInterface {
String printstring = val ? "tree" : "notree"; String printstring = val ? "tree" : "notree";
try { try {
verifyProcess(); verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring) decompProcess.sendCommand2Params("setAction", "", printstring, stringResponse);
.toString() return stringResponse.toString().equals("t");
.equals("t");
} }
catch (IOException e) { catch (IOException e) {
// don't care // don't care
@ -499,9 +501,8 @@ public class DecompInterface {
String printstring = val ? "c" : "noc"; String printstring = val ? "c" : "noc";
try { try {
verifyProcess(); verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring) decompProcess.sendCommand2Params("setAction", "", printstring, stringResponse);
.toString() return stringResponse.toString().equals("t");
.equals("t");
} }
catch (IOException e) { catch (IOException e) {
// don't care // don't care
@ -537,9 +538,8 @@ public class DecompInterface {
String printstring = val ? "parammeasures" : "noparammeasures"; String printstring = val ? "parammeasures" : "noparammeasures";
try { try {
verifyProcess(); verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring) decompProcess.sendCommand2Params("setAction", "", printstring, stringResponse);
.toString() return stringResponse.toString().equals("t");
.equals("t");
} }
catch (IOException e) { catch (IOException e) {
// don't care // don't care
@ -568,9 +568,8 @@ public class DecompInterface {
String jumpstring = val ? "jumpload" : "nojumpload"; String jumpstring = val ? "jumpload" : "nojumpload";
try { try {
verifyProcess(); verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", jumpstring) decompProcess.sendCommand2Params("setAction", "", jumpstring, stringResponse);
.toString() return stringResponse.toString().equals("t");
.equals("t");
} }
catch (IOException e) { catch (IOException e) {
// don't care // don't care
@ -593,11 +592,11 @@ public class DecompInterface {
* recovering from decompiler process crash, the interface * recovering from decompiler process crash, the interface
* keeps the options object around and automatically * keeps the options object around and automatically
* sends it to the new decompiler process. * sends it to the new decompiler process.
* @param xmloptions the new (or changed) option object * @param options the new (or changed) option object
* @return true if the decompiler process accepted the new options * @return true if the decompiler process accepted the new options
*/ */
public synchronized boolean setOptions(DecompileOptions xmloptions) { public synchronized boolean setOptions(DecompileOptions options) {
this.xmlOptions = xmloptions; this.options = options;
decompileMessage = ""; decompileMessage = "";
// Property can be set before process exists // Property can be set before process exists
if (decompProcess == null) { if (decompProcess == null) {
@ -605,10 +604,11 @@ public class DecompInterface {
} }
try { try {
verifyProcess(); verifyProcess();
decompProcess.setMaxResultSize(xmlOptions.getMaxPayloadMBytes()); paramEncode.clear();
return decompProcess.sendCommand1Param("setOptions", xmloptions.getXML(this)) options.encode(paramEncode, this);
.toString() decompProcess.setMaxResultSize(options.getMaxPayloadMBytes());
.equals("t"); decompProcess.sendCommand1Param("setOptions", paramEncode, stringResponse);
return stringResponse.toString().equals("t");
} }
catch (IOException e) { catch (IOException e) {
// don't care // don't care
@ -626,7 +626,7 @@ public class DecompInterface {
* @return options that will be passed to the decompiler * @return options that will be passed to the decompiler
*/ */
public synchronized DecompileOptions getOptions() { public synchronized DecompileOptions getOptions() {
return this.xmlOptions; return this.options;
} }
/** /**
@ -643,8 +643,8 @@ public class DecompInterface {
int res = -1; int res = -1;
try { try {
if ((decompProcess != null) && decompProcess.isReady()) { if ((decompProcess != null) && decompProcess.isReady()) {
String retval = decompProcess.sendCommand("flushNative").toString(); decompProcess.sendCommand("flushNative", stringResponse);
return Integer.parseInt(retval); return Integer.parseInt(stringResponse.toString());
} }
} }
catch (IOException e) { catch (IOException e) {
@ -657,8 +657,8 @@ public class DecompInterface {
return res; return res;
} }
public synchronized BlockGraph structureGraph(BlockGraph ingraph, AddressFactory factory, public synchronized BlockGraph structureGraph(BlockGraph ingraph, int timeoutSecs,
int timeoutSecs, TaskMonitor monitor) { TaskMonitor monitor) {
decompileMessage = ""; decompileMessage = "";
if (monitor != null && monitor.isCancelled()) { if (monitor != null && monitor.isCancelled()) {
return null; return null;
@ -666,18 +666,15 @@ public class DecompInterface {
if (monitor != null) { if (monitor != null) {
monitor.addCancelledListener(monitorListener); monitor.addCancelledListener(monitorListener);
} }
LimitedByteBuffer res = null;
BlockGraph resgraph = null; BlockGraph resgraph = null;
try { try {
encoder.clear();
ingraph.encode(encoder);
verifyProcess(); verifyProcess();
res = decompProcess.sendCommand1ParamTimeout("structureGraph", encoder.toString(), paramEncode.clear();
timeoutSecs); ingraph.encode(paramEncode);
decompProcess.sendCommand1ParamTimeout("structureGraph", paramEncode, timeoutSecs,
decoder);
decompileMessage = decompCallback.getNativeMessage(); decompileMessage = decompCallback.getNativeMessage();
if (res != null) { if (!decoder.isEmpty()) {
XmlDecode decoder = new XmlDecode(factory);
decoder.ingestStream(res.getInputStream(), "structureGraph results");
resgraph = new BlockGraph(); resgraph = new BlockGraph();
resgraph.decode(decoder); resgraph.decode(decoder);
resgraph.transferObjectRef(ingraph); resgraph.transferObjectRef(ingraph);
@ -710,7 +707,6 @@ public class DecompInterface {
return null; return null;
} }
LimitedByteBuffer res = null;
if (monitor != null) { if (monitor != null) {
monitor.addCancelledListener(monitorListener); monitor.addCancelledListener(monitorListener);
} }
@ -726,12 +722,18 @@ public class DecompInterface {
debug.setFunction(func); debug.setFunction(func);
} }
decompCallback.setFunction(func, funcEntry, debug); decompCallback.setFunction(func, funcEntry, debug);
encoder.clear();
AddressXML.encode(encoder, funcEntry);
verifyProcess(); verifyProcess();
res = decompProcess.sendCommand1ParamTimeout("decompileAt", encoder.toString(), paramEncode.clear();
timeoutSecs); AddressXML.encode(paramEncode, funcEntry);
decompProcess.sendCommand1ParamTimeout("decompileAt", paramEncode, timeoutSecs,
decoder);
decompileMessage = decompCallback.getNativeMessage(); decompileMessage = decompCallback.getNativeMessage();
if (debug != null) {
XmlEncode xmlEncode = new XmlEncode();
options.encode(xmlEncode, this);
debug.shutdown(pcodelanguage, xmlEncode.toString());
debug = null;
}
} }
catch (Exception ex) { catch (Exception ex) {
decompileMessage = "Exception while decompiling " + func.getEntryPoint() + ": " + decompileMessage = "Exception while decompiling " + func.getEntryPoint() + ": " +
@ -742,10 +744,6 @@ public class DecompInterface {
monitor.removeCancelledListener(monitorListener); monitor.removeCancelledListener(monitorListener);
} }
} }
if (debug != null) {
debug.shutdown(pcodelanguage, xmlOptions.getXML(this));
debug = null;
}
DecompileProcess.DisposeState processState; DecompileProcess.DisposeState processState;
if (decompProcess != null) { if (decompProcess != null) {
@ -758,12 +756,8 @@ public class DecompInterface {
processState = DecompileProcess.DisposeState.DISPOSED_ON_CANCEL; processState = DecompileProcess.DisposeState.DISPOSED_ON_CANCEL;
} }
InputStream stream = null;
if (res != null) {
stream = res.getInputStream();
}
return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage, decompileMessage, return new DecompileResults(func, pcodelanguage, compilerSpec, dtmanage, decompileMessage,
stream, processState); decoder, processState);
} }
/** /**

View File

@ -38,7 +38,6 @@ import ghidra.util.Msg;
import ghidra.util.UndefinedFunction; import ghidra.util.UndefinedFunction;
import ghidra.util.exception.UsrException; import ghidra.util.exception.UsrException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import ghidra.util.xml.SpecXmlUtils;
/** /**
* *
@ -49,7 +48,6 @@ import ghidra.util.xml.SpecXmlUtils;
public class DecompileCallback { public class DecompileCallback {
public final static int MAX_SYMBOL_COUNT = 16; public final static int MAX_SYMBOL_COUNT = 16;
public final static byte[] EMPTY_BYTE_ARRAY = new byte[0];
/** /**
* Data returned for a query about strings * Data returned for a query about strings
@ -75,8 +73,6 @@ public class DecompileCallback {
private Charset utf8Charset; private Charset utf8Charset;
private String nativeMessage; private String nativeMessage;
private XmlDecodeLight lightDecoder;
private XmlEncode resultEncode;
private InstructionBlock lastPseudoInstructionBlock; private InstructionBlock lastPseudoInstructionBlock;
private Disassembler pseudoDisassembler; private Disassembler pseudoDisassembler;
@ -93,8 +89,6 @@ public class DecompileCallback {
nativeMessage = null; nativeMessage = null;
debug = null; debug = null;
utf8Charset = Charset.availableCharsets().get(CharsetInfo.UTF8); utf8Charset = Charset.availableCharsets().get(CharsetInfo.UTF8);
lightDecoder = new XmlDecodeLight(addrfactory);
resultEncode = new XmlEncode();
} }
/** /**
@ -140,21 +134,24 @@ public class DecompileCallback {
nativeMessage = msg; nativeMessage = msg;
} }
public byte[] getBytes(String addrxml) { /**
* Get bytes from the program's memory image.
* @param addr is the starting address to fetch bytes from
* @param size is the number of bytes to fetch
* @return the bytes matching the query or null if the query can't be met
*/
public byte[] getBytes(Address addr, int size) {
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
if (addr == Address.NO_ADDRESS) {
Msg.error(this, "Address does not physically map");
return null;
}
if (addr.isRegisterAddress()) {
return null;
}
try { try {
lightDecoder.ingestString(addrxml);
lightDecoder.openElement();
Address addr = AddressXML.decodeFromAttributes(lightDecoder);
int size = (int) lightDecoder.readSignedInteger(ATTRIB_SIZE);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
if (addr == Address.NO_ADDRESS) {
throw new PcodeXMLException("Address does not physically map");
}
if (addr.isRegisterAddress()) {
return null;
}
byte[] resbytes = new byte[size]; byte[] resbytes = new byte[size];
int bytesRead = program.getMemory().getBytes(addr, resbytes, 0, size); int bytesRead = program.getMemory().getBytes(addr, resbytes, 0, size);
if (debug != null) { if (debug != null) {
@ -172,9 +169,6 @@ public class DecompileCallback {
catch (MemoryAccessException e) { catch (MemoryAccessException e) {
Msg.warn(this, "Decompiling " + funcEntry + ": " + e.getMessage()); Msg.warn(this, "Decompiling " + funcEntry + ": " + e.getMessage());
} }
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
}
catch (Exception e) { catch (Exception e) {
Msg.error(this, Msg.error(this,
"Decompiling " + funcEntry + ", error while accessing bytes: " + e.getMessage(), e); "Decompiling " + funcEntry + ", error while accessing bytes: " + e.getMessage(), e);
@ -184,59 +178,42 @@ public class DecompileCallback {
/** /**
* Collect any/all comments for the function starting at the indicated * Collect any/all comments for the function starting at the indicated
* address * address. Filter based on selected comment types.
* *
* @param addrstring is the XML rep of function address * @param addr is the indicated address
* @param types is the string encoding of the comment type flags * @param types is the set of flags
* @return Encoded description of comments * @param resultEncoder will contain the collected comments
* @throws IOException for errors in the underlying stream * @throws IOException for errors in the underlying stream
*/ */
public byte[] getComments(String addrstring, String types) throws IOException { public void getComments(Address addr, int types, Encoder resultEncoder) throws IOException {
Address addr; if (overlaySpace != null) {
int flags; addr = overlaySpace.getOverlayAddress(addr);
try {
lightDecoder.ingestString(addrstring);
addr = AddressXML.decode(lightDecoder);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
} }
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
return EMPTY_BYTE_ARRAY;
}
flags = SpecXmlUtils.decodeInt(types);
Function func = getFunctionAt(addr); Function func = getFunctionAt(addr);
if (func == null) { if (func == null) {
return EMPTY_BYTE_ARRAY; return;
} }
resultEncode.clear(); encodeComments(resultEncoder, addr, func, types);
encodeComments(resultEncode, addr, func, flags);
if (debug != null) { if (debug != null) {
XmlEncode xmlEncode = new XmlEncode(); XmlEncode xmlEncode = new XmlEncode();
encodeComments(xmlEncode, addr, func, flags); encodeComments(xmlEncode, addr, func, types);
debug.getComments(xmlEncode.toString()); debug.getComments(xmlEncode.toString());
} }
return resultEncode.getBytes();
} }
public PackedBytes getPcodePacked(String addrstring) { /**
Address addr = null; * Generate p-code ops for the instruction at the given address
try { * @param addr is the given address
lightDecoder.ingestString(addrstring); * @param resultEncoder will contain the generated p-code ops
addr = AddressXML.decode(lightDecoder); */
if (overlaySpace != null) { public void getPcode(Address addr, PackedEncode resultEncoder) {
addr = overlaySpace.getOverlayAddress(addr); if (overlaySpace != null) {
} addr = overlaySpace.getOverlayAddress(addr);
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
return null;
} }
try { try {
Instruction instr = getInstruction(addr); Instruction instr = getInstruction(addr);
if (instr == null) { if (instr == null) {
return null; return;
} }
if (undefinedBody != null) { if (undefinedBody != null) {
undefinedBody.addRange(instr.getMinAddress(), instr.getMaxAddress()); undefinedBody.addRange(instr.getMinAddress(), instr.getMaxAddress());
@ -250,11 +227,10 @@ public class DecompileCallback {
} }
} }
PackedBytes pcode = instr.getPrototype() instr.getPrototype()
.getPcodePacked(instr.getInstructionContext(), .getPcodePacked(resultEncoder, instr.getInstructionContext(),
new InstructionPcodeOverride(instr)); new InstructionPcodeOverride(instr));
return;
return pcode;
} }
catch (UsrException e) { catch (UsrException e) {
Msg.warn(this, Msg.warn(this,
@ -264,23 +240,23 @@ public class DecompileCallback {
Msg.error(this, Msg.error(this,
"Decompiling " + funcEntry + ", pcode error at " + addr + ": " + e.getMessage(), e); "Decompiling " + funcEntry + ", pcode error at " + addr + ": " + e.getMessage(), e);
} }
return null; resultEncoder.clear();
} }
/** /**
* Encode a list of pcode, representing an entire Instruction, to the stream * Encode a list of pcode, representing an entire Instruction, to the stream
* *
* @param encoder is the stream encoder * @param encoder is the stream encoder
* @param ops pcode ops * @param addr is the Address to associate with the Instruction
* @param ops is the pcode ops
* @param fallthruoffset number of bytes after instruction start that pcode * @param fallthruoffset number of bytes after instruction start that pcode
* flow falls into * flow falls into
* @param paramshift special instructions for injection use * @param paramshift special instructions for injection use
* @param addrFactory is the address factory for recovering address space names * @param addrFactory is the address factory for recovering address space names
* @throws IOException for errors in the underlying stream * @throws IOException for errors in the underlying stream
*/ */
public static void encodeInstruction(Encoder encoder, PcodeOp[] ops, int fallthruoffset, public static void encodeInstruction(Encoder encoder, Address addr, PcodeOp[] ops,
int paramshift, AddressFactory addrFactory) throws IOException { int fallthruoffset, int paramshift, AddressFactory addrFactory) throws IOException {
if ((ops.length == 1) && (ops[0].getOpcode() == PcodeOp.UNIMPLEMENTED)) { if ((ops.length == 1) && (ops[0].getOpcode() == PcodeOp.UNIMPLEMENTED)) {
encoder.openElement(ELEM_UNIMPL); encoder.openElement(ELEM_UNIMPL);
encoder.writeSignedInteger(ATTRIB_OFFSET, fallthruoffset); encoder.writeSignedInteger(ATTRIB_OFFSET, fallthruoffset);
@ -292,29 +268,36 @@ public class DecompileCallback {
if (paramshift != 0) { if (paramshift != 0) {
encoder.writeSignedInteger(ATTRIB_PARAMSHIFT, paramshift); encoder.writeSignedInteger(ATTRIB_PARAMSHIFT, paramshift);
} }
AddressXML.encode(encoder, addr);
for (PcodeOp op : ops) { for (PcodeOp op : ops) {
op.encode(encoder, addrFactory); op.encodeRaw(encoder, addrFactory);
} }
encoder.closeElement(ELEM_INST); encoder.closeElement(ELEM_INST);
} }
public byte[] getPcodeInject(String nm, String context, int type) { /**
* Generate p-code ops for a named injection payload
* @param nm is the name of the payload
* @param paramDecoder contains the context
* @param type is the type of payload
* @param resultEncoder will contain the generated p-code ops
*/
public void getPcodeInject(String nm, Decoder paramDecoder, int type, Encoder resultEncoder) {
PcodeInjectLibrary snippetLibrary = pcodecompilerspec.getPcodeInjectLibrary(); PcodeInjectLibrary snippetLibrary = pcodecompilerspec.getPcodeInjectLibrary();
InjectPayload payload = snippetLibrary.getPayload(type, nm); InjectPayload payload = snippetLibrary.getPayload(type, nm);
if (payload == null) { if (payload == null) {
Msg.warn(this, "Decompiling " + funcEntry + ", no pcode inject with name: " + nm); Msg.warn(this, "Decompiling " + funcEntry + ", no pcode inject with name: " + nm);
return EMPTY_BYTE_ARRAY; // No fixup associated with this name return; // No fixup associated with this name
} }
InjectContext con = snippetLibrary.buildInjectContext(); InjectContext con = snippetLibrary.buildInjectContext();
PcodeOp[] pcode; PcodeOp[] pcode;
try { try {
lightDecoder.ingestString(context); con.decode(paramDecoder);
con.decode(lightDecoder);
} }
catch (PcodeXMLException e) { catch (DecoderException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage()); Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
return EMPTY_BYTE_ARRAY; return;
} }
try { try {
int fallThruOffset; int fallThruOffset;
@ -322,14 +305,14 @@ public class DecompileCallback {
// Executable p-code has no underlying instruction address and // Executable p-code has no underlying instruction address and
// does (should) not use the inst_start, inst_next symbols that need // does (should) not use the inst_start, inst_next symbols that need
// to know about it. // to know about it.
fallThruOffset = 4; // Provide a dummy length for the XML doc fallThruOffset = 4; // Provide a dummy length
} }
else { else {
Instruction instr = getInstruction(con.baseAddr); Instruction instr = getInstruction(con.baseAddr);
if (instr == null) { if (instr == null) {
Msg.warn(this, "Decompiling " + funcEntry + ", pcode inject error at " + Msg.warn(this, "Decompiling " + funcEntry + ", pcode inject error at " +
con.baseAddr + ": instruction not found"); con.baseAddr + ": instruction not found");
return EMPTY_BYTE_ARRAY; return;
} }
// get next inst addr for inst_next pcode variable // get next inst addr for inst_next pcode variable
@ -347,18 +330,16 @@ public class DecompileCallback {
} }
pcode = payload.getPcode(program, con); pcode = payload.getPcode(program, con);
if (pcode == null) { if (pcode == null) {
return EMPTY_BYTE_ARRAY; // Return without result, which should let the decompiler exit gracefully return; // Return without result, which should let the decompiler exit gracefully
} }
resultEncode.clear(); encodeInstruction(resultEncoder, con.baseAddr, pcode, fallThruOffset,
encodeInstruction(resultEncode, pcode, fallThruOffset, payload.getParamShift(), payload.getParamShift(), addrfactory);
addrfactory);
if (debug != null) { if (debug != null) {
XmlEncode xmlEncode = new XmlEncode(); XmlEncode xmlEncode = new XmlEncode();
encodeInstruction(xmlEncode, pcode, fallThruOffset, payload.getParamShift(), encodeInstruction(xmlEncode, con.baseAddr, pcode, fallThruOffset,
addrfactory); payload.getParamShift(), addrfactory);
debug.addInject(con.baseAddr, nm, type, xmlEncode.toString()); debug.addInject(con.baseAddr, nm, type, xmlEncode.toString());
} }
return resultEncode.getBytes();
} }
catch (UnknownInstructionException e) { catch (UnknownInstructionException e) {
Msg.warn(this, "Decompiling " + funcEntry + ", pcode inject error at " + con.baseAddr + Msg.warn(this, "Decompiling " + funcEntry + ", pcode inject error at " + con.baseAddr +
@ -368,22 +349,25 @@ public class DecompileCallback {
Msg.error(this, "Decompiling " + funcEntry + ", pcode inject error at " + con.baseAddr + Msg.error(this, "Decompiling " + funcEntry + ", pcode inject error at " + con.baseAddr +
": " + e.getMessage(), e); ": " + e.getMessage(), e);
} }
return EMPTY_BYTE_ARRAY;
} }
public byte[] getCPoolRef(long[] refs) throws IOException { /**
* Look up details of a specific constant pool reference
* @param refs is the constant id (which may consist of multiple integers)
* @param resultEncoder will contain the reference details
* @throws IOException for errors in the underlying stream while encoding results
*/
public void getCPoolRef(long[] refs, Encoder resultEncoder) throws IOException {
if (cpool == null) { if (cpool == null) {
cpool = pcodecompilerspec.getPcodeInjectLibrary().getConstantPool(program); cpool = pcodecompilerspec.getPcodeInjectLibrary().getConstantPool(program);
} }
Record record = cpool.getRecord(refs); Record record = cpool.getRecord(refs);
resultEncode.clear(); record.encode(resultEncoder, refs[0], dtmanage);
record.encode(resultEncode, refs[0], dtmanage);
if (debug != null) { if (debug != null) {
XmlEncode xmlEncode = new XmlEncode(); XmlEncode xmlEncode = new XmlEncode();
record.encode(xmlEncode, refs[0], dtmanage); record.encode(xmlEncode, refs[0], dtmanage);
debug.getCPoolRef(xmlEncode.toString(), refs); debug.getCPoolRef(xmlEncode.toString(), refs);
} }
return resultEncode.getBytes();
} }
private Instruction getInstruction(Address addr) throws UnknownInstructionException { private Instruction getInstruction(Address addr) throws UnknownInstructionException {
@ -447,18 +431,14 @@ public class DecompileCallback {
throw new UnknownInstructionException("Invalid instruction address (improperly aligned)"); throw new UnknownInstructionException("Invalid instruction address (improperly aligned)");
} }
public String getSymbol(String addrstring) { // Return first symbol name at this address /**
Address addr; * Return the first symbol name at the given address
try { * @param addr is the given address
lightDecoder.ingestString(addrstring); * @return the symbol or null if no symbol is found
addr = AddressXML.decode(lightDecoder); */
if (overlaySpace != null) { public String getCodeLabel(Address addr) {
addr = overlaySpace.getOverlayAddress(addr); if (overlaySpace != null) {
} addr = overlaySpace.getOverlayAddress(addr);
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
return null;
} }
try { try {
Symbol sym = program.getSymbolTable().getPrimarySymbol(addr); Symbol sym = program.getSymbolTable().getPrimarySymbol(addr);
@ -575,17 +555,15 @@ public class DecompileCallback {
/** /**
* Write a description of the formal namespace path to the given namespace * Write a description of the formal namespace path to the given namespace
* @param id is the ID of the given namespace * @param id is the ID of the given namespace
* @return the encoded result * @param resultEncoder is where to write the encoded result
* @throws IOException for errors in the underlying stream * @throws IOException for errors in the underlying stream
*/ */
public byte[] getNamespacePath(long id) throws IOException { public void getNamespacePath(long id, Encoder resultEncoder) throws IOException {
Namespace namespace = getNameSpaceByID(id); Namespace namespace = getNameSpaceByID(id);
resultEncode.clear(); HighFunction.encodeNamespace(resultEncoder, namespace);
HighFunction.encodeNamespace(resultEncode, namespace);
if (debug != null) { if (debug != null) {
debug.getNamespacePath(namespace); debug.getNamespacePath(namespace);
} }
return resultEncode.getBytes();
} }
private void encodeHeaderComment(Encoder encoder, Function func) throws IOException { private void encodeHeaderComment(Encoder encoder, Function func) throws IOException {
@ -683,81 +661,61 @@ public class DecompileCallback {
} }
/** /**
* Describe data or functions at addr. * Describe data or functions at the given address; either function, reference, data, or hole.
* Called by the native decompiler to query the GHIDRA database about any * Called by the native decompiler to query the GHIDRA database about any
* symbols at the given address. * symbols at the given address.
* *
* @param addrstring XML encoded address to query * @param addr is the given address
* @return an encoded description, either function, reference, datatype, or hole * @param resultEncoder is where to write encoded description
*/ */
public byte[] getMappedSymbolsXML(String addrstring) { public void getMappedSymbols(Address addr, Encoder resultEncoder) {
Address addr; if (overlaySpace != null) {
try { addr = overlaySpace.getOverlayAddress(addr);
lightDecoder.ingestString(addrstring);
addr = AddressXML.decode(lightDecoder);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
if (addr == Address.NO_ADDRESS) {
// Unknown spaces may result from "spacebase" registers defined in cspec
return EMPTY_BYTE_ARRAY;
}
} }
catch (PcodeXMLException e) { if (addr == Address.NO_ADDRESS) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage()); // Unknown spaces may result from "spacebase" registers defined in cspec
return EMPTY_BYTE_ARRAY; return;
} }
try { try {
Object obj = lookupSymbol(addr); Object obj = lookupSymbol(addr);
resultEncode.clear();
if (obj instanceof Function) { if (obj instanceof Function) {
boolean includeDefaults = addr.equals(funcEntry); boolean includeDefaults = addr.equals(funcEntry);
encodeFunction(resultEncode, (Function) obj, addr, includeDefaults); encodeFunction(resultEncoder, (Function) obj, addr, includeDefaults);
} }
else if (obj instanceof Data) { else if (obj instanceof Data) {
if (!encodeData(resultEncode, (Data) obj)) { if (!encodeData(resultEncoder, (Data) obj)) {
encodeHole(resultEncode, addr); encodeHole(resultEncoder, addr);
} }
} }
else if (obj instanceof ExternalReference) { else if (obj instanceof ExternalReference) {
encodeExternalRef(resultEncode, addr, (ExternalReference) obj); encodeExternalRef(resultEncoder, addr, (ExternalReference) obj);
} }
else if (obj instanceof Symbol) { else if (obj instanceof Symbol) {
encodeLabel(resultEncode, (Symbol) obj, addr); encodeLabel(resultEncoder, (Symbol) obj, addr);
} }
else { else {
encodeHole(resultEncode, addr); // There is a hole, describe the extent of the hole encodeHole(resultEncoder, addr); // There is a hole, describe the extent of the hole
} }
return resultEncode.getBytes(); return;
} }
catch (Exception e) { catch (Exception e) {
Msg.error(this, "Decompiling " + funcEntry + ", mapped symbol error for " + addrstring + Msg.error(this, "Decompiling " + funcEntry + ", mapped symbol error for " + addr +
": " + e.getMessage(), e); ": " + e.getMessage(), e);
} }
return EMPTY_BYTE_ARRAY; return;
} }
/** /**
* Describe an external reference at the given address * Get a description of an external reference at the given address
* @param addrstring is the description of the address * @param addr is the given address
* @return the encoded description * @param resultEncoder will contain the resulting description
*/ */
public byte[] getExternalRefXML(String addrstring) { public void getExternalRef(Address addr, Encoder resultEncoder) {
Address addr; if (overlaySpace != null) {
try { addr = overlaySpace.getOverlayAddress(addr);
lightDecoder.ingestString(addrstring);
addr = AddressXML.decode(lightDecoder);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
return EMPTY_BYTE_ARRAY;
} }
try { try {
Function func = null; Function func = null;
if (cachedFunction != null && cachedFunction.getEntryPoint().equals(addr)) { if (cachedFunction != null && cachedFunction.getEntryPoint().equals(addr)) {
func = cachedFunction; func = cachedFunction;
@ -778,9 +736,8 @@ public class DecompileCallback {
} }
HighSymbol shellSymbol = HighSymbol shellSymbol =
new HighFunctionShellSymbol(extId, extRef.getLabel(), addr, dtmanage); new HighFunctionShellSymbol(extId, extRef.getLabel(), addr, dtmanage);
resultEncode.clear(); encodeResult(resultEncoder, shellSymbol, null);
encodeResult(resultEncode, shellSymbol, null); return;
return resultEncode.getBytes();
} }
} }
else { else {
@ -789,7 +746,7 @@ public class DecompileCallback {
} }
if (func == null) { if (func == null) {
// Its conceivable we could have external data, but we aren't currently checking for it // Its conceivable we could have external data, but we aren't currently checking for it
return EMPTY_BYTE_ARRAY; return;
} }
HighFunction hfunc = new HighFunction(func, pcodelanguage, pcodecompilerspec, dtmanage); HighFunction hfunc = new HighFunction(func, pcodelanguage, pcodecompilerspec, dtmanage);
@ -803,86 +760,89 @@ public class DecompileCallback {
debug.getFNTypes(hfunc); debug.getFNTypes(hfunc);
debug.addPossiblePrototypeExtension(func); debug.addPossiblePrototypeExtension(func);
} }
resultEncode.clear(); encodeResult(resultEncoder, funcSymbol, namespc);
encodeResult(resultEncode, funcSymbol, namespc); return;
return resultEncode.getBytes();
} }
catch (Exception e) { catch (Exception e) {
Msg.error(this, Msg.error(this,
"Decompiling " + funcEntry + ", error in getExternalRefXML: " + e.getMessage(), e); "Decompiling " + funcEntry + ", error in getExternalRef: " + e.getMessage(), e);
} }
return EMPTY_BYTE_ARRAY;
} }
public byte[] getType(String name, long id) throws IOException { /**
* Get a description of a data-type given its name and type id
* @param name is the name of the data-type
* @param id is the type id
* @param resultEncoder will contain the resulting description
* @throws IOException for errors in the underlying stream while encoding
*/
public void getDataType(String name, long id, Encoder resultEncoder) throws IOException {
DataType type = dtmanage.findBaseType(name, id); DataType type = dtmanage.findBaseType(name, id);
if (type == null) { if (type == null) {
return EMPTY_BYTE_ARRAY; return;
} }
resultEncode.clear(); dtmanage.encodeType(resultEncoder, type, 0);
dtmanage.encodeType(resultEncode, type, 0);
if (debug != null) { if (debug != null) {
debug.getType(type); debug.getType(type);
} }
return resultEncode.getBytes();
} }
public byte[] getRegister(String name) throws IOException { /**
* Return a description of the register with the given name
* @param name is the given name
* @param resultEncoder is where to write the description
* @throws IOException for errors writing to the underlying stream
*/
public void getRegister(String name, Encoder resultEncoder) throws IOException {
Register reg = pcodelanguage.getRegister(name); Register reg = pcodelanguage.getRegister(name);
if (reg == null) { if (reg == null) {
throw new RuntimeException("No Register Defined: " + name); throw new RuntimeException("No Register Defined: " + name);
} }
resultEncode.clear(); encodeRegister(resultEncoder, reg);
encodeRegister(resultEncode, reg);
return resultEncode.getBytes();
} }
public String getRegisterName(String addrstring) { /**
try { * Given a storage location, return the register name for that location, or null if there
lightDecoder.ingestString(addrstring); * is no register there.
lightDecoder.openElement(); * @param addr is the starting address of the storage location
Address addr = AddressXML.decodeFromAttributes(lightDecoder); * @param size is the size of storage in bytes
int size = (int) lightDecoder.readSignedInteger(ATTRIB_SIZE); * @return the register name or null
Register reg = pcodelanguage.getRegister(addr, size); */
if (reg == null) { public String getRegisterName(Address addr, int size) {
return ""; Register reg = pcodelanguage.getRegister(addr, size);
} if (reg == null) {
return reg.getName(); return "";
} }
catch (PcodeXMLException e) { return reg.getName();
Msg.error(this, "Decompiling " + funcEntry +
", error while searching for register name: " + e.getMessage(), e);
}
return "";
} }
public byte[] getTrackedRegisters(String addrstring) throws IOException { /**
Address addr; * Get "tracked" register values, constant values associated with a specific register at
try { * a specific point in the code.
lightDecoder.ingestString(addrstring); * @param addr is the "point" in the code to look for tracked values
addr = AddressXML.decode(lightDecoder); * @param resultEncoder will hold the resulting description of registers and values
if (overlaySpace != null) { * @throws IOException for errors in the underlying stream writing the result
addr = overlaySpace.getOverlayAddress(addr); */
} public void getTrackedRegisters(Address addr, Encoder resultEncoder) throws IOException {
} if (overlaySpace != null) {
catch (PcodeXMLException e) { addr = overlaySpace.getOverlayAddress(addr);
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
return EMPTY_BYTE_ARRAY;
} }
ProgramContext context = program.getProgramContext(); ProgramContext context = program.getProgramContext();
resultEncode.clear(); encodeTrackedPointSet(resultEncoder, addr, context);
encodeTrackedPointSet(resultEncode, addr, context);
if (debug != null) { if (debug != null) {
XmlEncode xmlEncode = new XmlEncode(); XmlEncode xmlEncode = new XmlEncode();
encodeTrackedPointSet(xmlEncode, addr, context); encodeTrackedPointSet(xmlEncode, addr, context);
debug.getTrackedRegisters(xmlEncode.toString()); debug.getTrackedRegisters(xmlEncode.toString());
} }
return resultEncode.getBytes();
} }
public String getUserOpName(String indexStr) { /**
int index = Integer.parseInt(indexStr); * Get the name of a user op given its index
* @param index is the given index
* @return the userop name or null
*/
public String getUserOpName(int index) {
String name = pcodelanguage.getUserDefinedOpName(index); String name = pcodelanguage.getUserDefinedOpName(index);
return name; return name;
} }
@ -1007,7 +967,7 @@ public class DecompileCallback {
} }
/** /**
* This function deals with the vagaries of the getMappedSymbolsXML * This function deals with the vagaries of the getMappedSymbols
* interface when the queried address is in the body of a function. * interface when the queried address is in the body of a function.
* Basically, if the address is the entry point of the function, all the * Basically, if the address is the entry point of the function, all the
* function data is sent. Otherwise a hole is sent back of the biggest * function data is sent. Otherwise a hole is sent back of the biggest
@ -1268,35 +1228,25 @@ public class DecompileCallback {
} }
/** /**
* Check for a string at an address and return a UTF8 encoded byte array. * Check for a string at the given address and return a UTF8 encoded byte array.
* If there is already data present at the address, use this to determine the * If there is already data present at the address, use this to determine the
* string encoding. Otherwise use the data-type info passed in to determine the encoding. * string encoding. Otherwise use the data-type info passed in to determine the encoding.
* Check that the bytes at the address represent a valid string encoding that doesn't * Check that the bytes at the address represent a valid string encoding that doesn't
* exceed the maximum character limit passed in. Return null if the string is invalid. * exceed the maximum character limit passed in. Return null if the string is invalid.
* Return the string translated into a UTF8 byte array otherwise. A (valid) empty * Return the string translated into a UTF8 byte array otherwise. A (valid) empty
* string is returned as a zero length array. * string is returned as a zero length array.
* @param addrString is the XML encoded address and maximum byte limit * @param addr is the given address
* @param maxChars is the maximum character limit
* @param dtName is the name of a character data-type * @param dtName is the name of a character data-type
* @param dtId is the id associated with the character data-type * @param dtId is the id associated with the character data-type
* @return the UTF8 encoded byte array or null * @return the UTF8 encoded byte array or null
*/ */
public StringData getStringData(String addrString, String dtName, long dtId) { public StringData getStringData(Address addr, int maxChars, String dtName, long dtId) {
Address addr; if (overlaySpace != null) {
int maxChars; addr = overlaySpace.getOverlayAddress(addr);
try {
lightDecoder.ingestString(addrString);
lightDecoder.openElement();
addr = AddressXML.decodeFromAttributes(lightDecoder);
maxChars = (int) lightDecoder.readSignedInteger(ATTRIB_SIZE);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
if (addr == Address.NO_ADDRESS) {
throw new PcodeXMLException("Address does not physically map");
}
} }
catch (PcodeXMLException e) { if (addr == Address.NO_ADDRESS) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage()); Msg.error(this, "Address does not physically map");
return null; return null;
} }
Data data = program.getListing().getDataContaining(addr); Data data = program.getListing().getDataContaining(addr);

View File

@ -328,7 +328,7 @@ public class DecompileDebug {
encoder.closeElement(ELEM_STRING); encoder.closeElement(ELEM_STRING);
} }
encoder.closeElement(ELEM_STRINGMANAGE); encoder.closeElement(ELEM_STRINGMANAGE);
debugStream.write(encoder.getBytes()); encoder.writeTo(debugStream);
} }
private void dumpDataTypes(OutputStream debugStream) throws IOException { private void dumpDataTypes(OutputStream debugStream) throws IOException {
@ -356,7 +356,7 @@ public class DecompileDebug {
} }
} }
encoder.closeElement(ELEM_TYPEGRP); encoder.closeElement(ELEM_TYPEGRP);
debugStream.write(encoder.getBytes()); encoder.writeTo(debugStream);
} }
private void dumpTrackedContext(OutputStream debugStream) throws IOException { private void dumpTrackedContext(OutputStream debugStream) throws IOException {
@ -463,7 +463,7 @@ public class DecompileDebug {
encoder.closeElement(ELEM_SET); encoder.closeElement(ELEM_SET);
} }
encoder.closeElement(ELEM_CONTEXT_POINTSET); encoder.closeElement(ELEM_CONTEXT_POINTSET);
debugStream.write(encoder.getBytes()); encoder.writeTo(debugStream);
} }
} }
@ -616,13 +616,13 @@ public class DecompileDebug {
} }
} }
encoder.closeElement(ELEM_SPECEXTENSIONS); encoder.closeElement(ELEM_SPECEXTENSIONS);
debugStream.write(encoder.getBytes()); encoder.writeTo(debugStream);
} }
private void dumpCoretypes(OutputStream debugStream) throws IOException { private void dumpCoretypes(OutputStream debugStream) throws IOException {
XmlEncode encoder = new XmlEncode(); XmlEncode encoder = new XmlEncode();
dtmanage.encodeCoreTypes(encoder); dtmanage.encodeCoreTypes(encoder);
debugStream.write(encoder.getBytes()); encoder.writeTo(debugStream);
} }
public void getPcode(Address addr, Instruction instr) { public void getPcode(Address addr, Instruction instr) {

View File

@ -16,10 +16,13 @@
package ghidra.app.decompiler; package ghidra.app.decompiler;
import static ghidra.GhidraOptions.*; import static ghidra.GhidraOptions.*;
import static ghidra.program.model.pcode.AttributeId.*;
import static ghidra.program.model.pcode.ElementId.*;
import java.awt.Color; import java.awt.Color;
import java.awt.Font; import java.awt.Font;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.io.IOException;
import ghidra.GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES; import ghidra.GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES;
import ghidra.app.util.HelpTopics; import ghidra.app.util.HelpTopics;
@ -31,6 +34,8 @@ import ghidra.program.database.ProgramCompilerSpec;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.lang.CompilerSpec.EvaluationModelType; import ghidra.program.model.lang.CompilerSpec.EvaluationModelType;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.ElementId;
import ghidra.program.model.pcode.Encoder;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.SystemUtilities; import ghidra.util.SystemUtilities;
@ -664,128 +669,125 @@ public class DecompileOptions {
grabFromToolAndProgram(ownerPlugin, opt, program); grabFromToolAndProgram(ownerPlugin, opt, program);
} }
private static void appendOption(StringBuffer buf, String name, String p1, String p2, private static void appendOption(Encoder encoder, ElementId option, String p1, String p2,
String p3) { String p3) throws IOException {
buf.append(" <"); encoder.openElement(option);
buf.append(name);
buf.append('>');
if ((p2.length() == 0) && (p3.length() == 0)) { if ((p2.length() == 0) && (p3.length() == 0)) {
buf.append(p1); encoder.writeString(ATTRIB_CONTENT, p1);
} }
else { else {
buf.append('\n'); encoder.openElement(ELEM_PARAM1);
buf.append(" <param1>"); encoder.writeString(ATTRIB_CONTENT, p1);
buf.append(p1); encoder.closeElement(ELEM_PARAM1);
buf.append("</param1>\n"); encoder.openElement(ELEM_PARAM2);
buf.append(" <param2>"); encoder.writeString(ATTRIB_CONTENT, p2); // Print even if empty, as p3 isn't
buf.append(p2); // Print even if empty, as p3 isn't encoder.closeElement(ELEM_PARAM2);
buf.append("</param2>\n");
if (p3.length() != 0) { if (p3.length() != 0) {
buf.append(" <param3>"); encoder.openElement(ELEM_PARAM3);
buf.append(p3); encoder.writeString(ATTRIB_CONTENT, p3);
buf.append("</param3>\n"); encoder.closeElement(ELEM_PARAM3);
} }
} }
buf.append("</"); encoder.closeElement(option);
buf.append(name);
buf.append(">\n");
} }
/** /**
* Produce XML document of configuration options * Encode all the configuration options to a stream for the decompiler process.
* to be sent to decompiler process. This object * This object is global to all decompile processes so we can tailor to the specific process
* is global to all decompile processes so we can * by passing in the interface.
* tailor to the specific process by passing in the * @param encoder is the stream encoder
* interface
* @param iface specific DecompInterface being sent options * @param iface specific DecompInterface being sent options
* @return XML document as a string * @throws IOException for errors writing to the underlying stream
*/ */
public String getXML(DecompInterface iface) { public void encode(Encoder encoder, DecompInterface iface) throws IOException {
StringBuffer buf = new StringBuffer(); encoder.openElement(ELEM_OPTIONSLIST);
buf.append("<optionslist>\n"); appendOption(encoder, ELEM_CURRENTACTION, "conditionalexe", predicate ? "on" : "off", "");
appendOption(buf, "currentaction", "conditionalexe", predicate ? "on" : "off", ""); appendOption(encoder, ELEM_READONLY, readOnly ? "on" : "off", "", "");
appendOption(buf, "readonly", readOnly ? "on" : "off", "", ""); appendOption(encoder, ELEM_CURRENTACTION, iface.getSimplificationStyle(), "unreachable",
appendOption(buf, "currentaction", iface.getSimplificationStyle(), "unreachable",
eliminateUnreachable ? "on" : "off"); eliminateUnreachable ? "on" : "off");
appendOption(buf, "currentaction", iface.getSimplificationStyle(), "doubleprecis", appendOption(encoder, ELEM_CURRENTACTION, iface.getSimplificationStyle(), "doubleprecis",
simplifyDoublePrecision ? "on" : "off"); simplifyDoublePrecision ? "on" : "off");
// Must set language early so that the object is in place before other option changes // Must set language early so that the object is in place before other option changes
appendOption(buf, "setlanguage", displayLanguage.toString(), "", ""); appendOption(encoder, ELEM_SETLANGUAGE, displayLanguage.toString(), "", "");
if (ignoreunimpl != IGNOREUNIMPL_OPTIONDEFAULT) { if (ignoreunimpl != IGNOREUNIMPL_OPTIONDEFAULT) {
appendOption(buf, "ignoreunimplemented", ignoreunimpl ? "on" : "off", "", ""); appendOption(encoder, ELEM_IGNOREUNIMPLEMENTED, ignoreunimpl ? "on" : "off", "", "");
} }
if (inferconstptr != INFERCONSTPTR_OPTIONDEFAULT) { if (inferconstptr != INFERCONSTPTR_OPTIONDEFAULT) {
appendOption(buf, "inferconstptr", inferconstptr ? "on" : "off", "", ""); appendOption(encoder, ELEM_INFERCONSTPTR, inferconstptr ? "on" : "off", "", "");
} }
if (analyzeForLoops != ANALYZEFORLOOPS_OPTIONDEFAULT) { if (analyzeForLoops != ANALYZEFORLOOPS_OPTIONDEFAULT) {
appendOption(buf, "analyzeforloops", analyzeForLoops ? "on" : "off", "", ""); appendOption(encoder, ELEM_ANALYZEFORLOOPS, analyzeForLoops ? "on" : "off", "", "");
} }
if (nullToken != NULLTOKEN_OPTIONDEFAULT) { if (nullToken != NULLTOKEN_OPTIONDEFAULT) {
appendOption(buf, "nullprinting", nullToken ? "on" : "off", "", ""); appendOption(encoder, ELEM_NULLPRINTING, nullToken ? "on" : "off", "", "");
} }
if (inplaceTokens != INPLACEOP_OPTIONDEFAULT) { if (inplaceTokens != INPLACEOP_OPTIONDEFAULT) {
appendOption(buf, "inplaceops", inplaceTokens ? "on" : "off", "", ""); appendOption(encoder, ELEM_INPLACEOPS, inplaceTokens ? "on" : "off", "", "");
} }
if (aliasBlock != ALIASBLOCK_OPTIONDEFAULT) { if (aliasBlock != ALIASBLOCK_OPTIONDEFAULT) {
appendOption(buf, "aliasblock", aliasBlock.getOptionString(), "", ""); appendOption(encoder, ELEM_ALIASBLOCK, aliasBlock.getOptionString(), "", "");
} }
if (conventionPrint != CONVENTION_OPTIONDEFAULT) { if (conventionPrint != CONVENTION_OPTIONDEFAULT) {
appendOption(buf, "conventionprinting", conventionPrint ? "on" : "off", "", ""); appendOption(encoder, ELEM_CONVENTIONPRINTING, conventionPrint ? "on" : "off", "", "");
} }
if (noCastPrint != NOCAST_OPTIONDEFAULT) { if (noCastPrint != NOCAST_OPTIONDEFAULT) {
appendOption(buf, "nocastprinting", noCastPrint ? "on" : "off", "", ""); appendOption(encoder, ELEM_NOCASTPRINTING, noCastPrint ? "on" : "off", "", "");
} }
if (maxwidth != MAXWIDTH_OPTIONDEFAULT) { if (maxwidth != MAXWIDTH_OPTIONDEFAULT) {
appendOption(buf, "maxlinewidth", Integer.toString(maxwidth), "", ""); appendOption(encoder, ELEM_MAXLINEWIDTH, Integer.toString(maxwidth), "", "");
} }
if (indentwidth != INDENTWIDTH_OPTIONDEFAULT) { if (indentwidth != INDENTWIDTH_OPTIONDEFAULT) {
appendOption(buf, "indentincrement", Integer.toString(indentwidth), "", ""); appendOption(encoder, ELEM_INDENTINCREMENT, Integer.toString(indentwidth), "", "");
} }
if (commentindent != COMMENTINDENT_OPTIONDEFAULT) { if (commentindent != COMMENTINDENT_OPTIONDEFAULT) {
appendOption(buf, "commentindent", Integer.toString(commentindent), "", ""); appendOption(encoder, ELEM_COMMENTINDENT, Integer.toString(commentindent), "", "");
} }
if (commentStyle != COMMENTSTYLE_OPTIONDEFAULT) { if (commentStyle != COMMENTSTYLE_OPTIONDEFAULT) {
String curstyle = CommentStyleEnum.CPPStyle.equals(commentStyle) ? "cplusplus" : "c"; String curstyle = CommentStyleEnum.CPPStyle.equals(commentStyle) ? "cplusplus" : "c";
appendOption(buf, "commentstyle", curstyle, "", ""); appendOption(encoder, ELEM_COMMENTSTYLE, curstyle, "", "");
} }
if (commentPLATEInclude != COMMENTPLATE_OPTIONDEFAULT) { if (commentPLATEInclude != COMMENTPLATE_OPTIONDEFAULT) {
appendOption(buf, "commentinstruction", "header", commentPLATEInclude ? "on" : "off", appendOption(encoder, ELEM_COMMENTINSTRUCTION, "header",
""); commentPLATEInclude ? "on" : "off", "");
} }
if (commentPREInclude != COMMENTPRE_OPTIONDEFAULT) { if (commentPREInclude != COMMENTPRE_OPTIONDEFAULT) {
appendOption(buf, "commentinstruction", "user2", commentPREInclude ? "on" : "off", ""); appendOption(encoder, ELEM_COMMENTINSTRUCTION, "user2",
commentPREInclude ? "on" : "off", "");
} }
if (commentEOLInclude != COMMENTEOL_OPTIONDEFAULT) { if (commentEOLInclude != COMMENTEOL_OPTIONDEFAULT) {
appendOption(buf, "commentinstruction", "user1", commentEOLInclude ? "on" : "off", ""); appendOption(encoder, ELEM_COMMENTINSTRUCTION, "user1",
commentEOLInclude ? "on" : "off", "");
} }
if (commentPOSTInclude != COMMENTPOST_OPTIONDEFAULT) { if (commentPOSTInclude != COMMENTPOST_OPTIONDEFAULT) {
appendOption(buf, "commentinstruction", "user3", commentPOSTInclude ? "on" : "off", ""); appendOption(encoder, ELEM_COMMENTINSTRUCTION, "user3",
commentPOSTInclude ? "on" : "off", "");
} }
if (commentWARNInclude != COMMENTWARN_OPTIONDEFAULT) { if (commentWARNInclude != COMMENTWARN_OPTIONDEFAULT) {
appendOption(buf, "commentinstruction", "warning", commentWARNInclude ? "on" : "off", appendOption(encoder, ELEM_COMMENTINSTRUCTION, "warning",
""); commentWARNInclude ? "on" : "off", "");
} }
if (commentHeadInclude != COMMENTHEAD_OPTIONDEFAULT) { if (commentHeadInclude != COMMENTHEAD_OPTIONDEFAULT) {
appendOption(buf, "commentheader", "header", commentHeadInclude ? "on" : "off", ""); appendOption(encoder, ELEM_COMMENTHEADER, "header", commentHeadInclude ? "on" : "off",
}
if (commentWARNInclude != COMMENTWARN_OPTIONDEFAULT) {
appendOption(buf, "commentheader", "warningheader", commentWARNInclude ? "on" : "off",
""); "");
} }
if (commentWARNInclude != COMMENTWARN_OPTIONDEFAULT) {
appendOption(encoder, ELEM_COMMENTHEADER, "warningheader",
commentWARNInclude ? "on" : "off", "");
}
if (namespaceStrategy != NAMESPACE_OPTIONDEFAULT) { if (namespaceStrategy != NAMESPACE_OPTIONDEFAULT) {
appendOption(buf, "namespacestrategy", namespaceStrategy.getOptionString(), "", ""); appendOption(encoder, ELEM_NAMESPACESTRATEGY, namespaceStrategy.getOptionString(), "",
"");
} }
if (integerFormat != INTEGERFORMAT_OPTIONDEFAULT) { if (integerFormat != INTEGERFORMAT_OPTIONDEFAULT) {
appendOption(buf, "integerformat", integerFormat.getOptionString(), "", ""); appendOption(encoder, ELEM_INTEGERFORMAT, integerFormat.getOptionString(), "", "");
} }
if (maxIntructionsPer != SUGGESTED_MAX_INSTRUCTIONS) { if (maxIntructionsPer != SUGGESTED_MAX_INSTRUCTIONS) {
appendOption(buf, "maxinstruction", Integer.toString(maxIntructionsPer), "", ""); appendOption(encoder, ELEM_MAXINSTRUCTION, Integer.toString(maxIntructionsPer), "", "");
} }
appendOption(buf, "protoeval", protoEvalModel, "", ""); appendOption(encoder, ELEM_PROTOEVAL, protoEvalModel, "", "");
buf.append("</optionslist>\n"); encoder.closeElement(ELEM_OPTIONSLIST);
return buf.toString();
} }
public int getMaxWidth() { public int getMaxWidth() {

View File

@ -15,14 +15,18 @@
*/ */
package ghidra.app.decompiler; package ghidra.app.decompiler;
import static ghidra.program.model.pcode.AttributeId.*;
import static ghidra.program.model.pcode.ElementId.*;
import java.io.*; import java.io.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.InjectPayload; import ghidra.program.model.lang.InjectPayload;
import ghidra.program.model.lang.PackedBytes; import ghidra.program.model.listing.Program;
import ghidra.program.model.pcode.*;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.timer.GTimer; import ghidra.util.timer.GTimer;
import ghidra.util.timer.GTimerMonitor; import ghidra.util.timer.GTimerMonitor;
import ghidra.util.xml.SpecXmlUtils;
/** /**
* *
@ -66,8 +70,13 @@ public class DecompileProcess {
private int archId = -1; // architecture id for decomp process private int archId = -1; // architecture id for decomp process
private DecompileCallback callback; // Callback interface for decompiler private DecompileCallback callback; // Callback interface for decompiler
private String programSource; // String describing program for error reports
private int maxResultSizeMBYtes = 50; // maximum result size in MBytes to allow from decompiler private int maxResultSizeMBYtes = 50; // maximum result size in MBytes to allow from decompiler
private PackedDecode paramDecoder; // Ingest queries from the decompiler process
private StringIngest stringDecoder; // Ingest of exception and status messages
private PackedEncode resultEncoder; // Encode responses to decompile process queries
public enum DisposeState { public enum DisposeState {
NOT_DISPOSED, // Process was/is not disposed NOT_DISPOSED, // Process was/is not disposed
DISPOSED_ON_TIMEOUT, // A timeout occurred DISPOSED_ON_TIMEOUT, // A timeout occurred
@ -89,6 +98,7 @@ public class DecompileProcess {
disposestate = DisposeState.DISPOSED_ON_TIMEOUT; disposestate = DisposeState.DISPOSED_ON_TIMEOUT;
} }
}; };
stringDecoder = new StringIngest();
} }
public void dispose() { public void dispose() {
@ -186,17 +196,10 @@ public class DecompileProcess {
throw new IOException("Ghidra/decompiler alignment error"); throw new IOException("Ghidra/decompiler alignment error");
} }
private int readToBuffer(LimitedByteBuffer buf) throws IOException { private int readToBuffer(ByteIngest buf) throws IOException {
int cur; int cur;
for (;;) { for (;;) {
cur = nativeIn.read(); buf.ingestStream(nativeIn);
while (cur > 0) {
buf.append((byte) cur);
cur = nativeIn.read();
}
if (cur == -1) {
break;
}
do { do {
cur = nativeIn.read(); cur = nativeIn.read();
} }
@ -214,17 +217,17 @@ public class DecompileProcess {
throw new IOException("Decompiler process died"); throw new IOException("Decompiler process died");
} }
private String readQueryString() throws IOException { private void readQueryParam(ByteIngest ingester) throws IOException {
int type = readToBurst(); int type = readToBurst();
if (type != 14) { if (type != 14) {
throw new IOException("GHIDRA/decompiler alignment error"); throw new IOException("GHIDRA/decompiler alignment error");
} }
LimitedByteBuffer buf = new LimitedByteBuffer(16, 1 << 16); ingester.open(1 << 16, programSource);
type = readToBuffer(buf); type = readToBuffer(ingester);
if (type != 15) { if (type != 15) {
throw new IOException("GHIDRA/decompiler alignment error"); throw new IOException("GHIDRA/decompiler alignment error");
} }
return buf.toString(); ingester.endIngest();
} }
private void writeString(String msg) throws IOException { private void writeString(String msg) throws IOException {
@ -233,40 +236,20 @@ public class DecompileProcess {
write(string_end); write(string_end);
} }
private void writeBytes(byte[] msg) throws IOException { private void writeString(Encoder byteResult) throws IOException {
write(string_start); if (nativeOut == null) {
write(msg); return;
write(string_end);
}
/**
* Transfer bytes written to -out- to decompiler process
* @param out has the collected byte for this write
* @throws IOException for any problems with the output stream
*/
private void writeBytes(PackedBytes out) throws IOException {
write(string_start);
int sz = out.size();
int sz1 = (sz & 0x3f) + 0x20;
sz >>>= 6;
int sz2 = (sz & 0x3f) + 0x20;
sz >>>= 6;
int sz3 = (sz & 0x3f) + 0x20;
sz >>>= 6;
int sz4 = (sz & 0x3f) + 0x20;
write(sz1);
write(sz2);
write(sz3);
write(sz4);
if (nativeOut != null) { // null if disposed
out.writeTo(nativeOut);
} }
write(string_start);
byteResult.writeTo(nativeOut);
write(string_end); write(string_end);
} }
private void generateException() throws IOException, DecompileException { private void generateException() throws IOException, DecompileException {
String type = readQueryString(); readQueryParam(stringDecoder);
String message = readQueryString(); String type = stringDecoder.toString();
readQueryParam(stringDecoder);
String message = stringDecoder.toString();
readToBurst(); // Read exception terminator readToBurst(); // Read exception terminator
if (type.equals("alignment")) { if (type.equals("alignment")) {
throw new IOException("Alignment error: " + message); throw new IOException("Alignment error: " + message);
@ -274,89 +257,78 @@ public class DecompileProcess {
throw new DecompileException(type, message); throw new DecompileException(type, message);
} }
private LimitedByteBuffer readResponse() throws IOException, DecompileException { private void readResponse(ByteIngest mainResponse) throws IOException, DecompileException {
readToResponse(); readToResponse();
int type = readToBurst(); int type = readToBurst();
String name; int commandId;
LimitedByteBuffer retbuf = null; ByteIngest currentResponse = null;
LimitedByteBuffer buf = null;
while (type != 7) { while (type != 7) {
switch (type) { switch (type) {
case 4: case 4:
name = readQueryString(); readQueryParam(paramDecoder);
try { try {
if (name.length() < 4) { commandId = paramDecoder.openElement();
throw new Exception("Bad decompiler query: " + name); switch (commandId) {
} case COMMAND_ISNAMEUSED:
switch (name.charAt(3)) {
case 'a': // isNameUsed
isNameUsed(); isNameUsed();
break; break;
case 'B': case COMMAND_GETBYTES:
getBytes(); // getBytes getBytes(); // getBytes
break; break;
case 'C': case COMMAND_GETCOMMENTS:
if (name.equals("getComments")) { getComments();
getComments();
}
else if (name.equals("getCallFixup")) {
getPcodeInject(InjectPayload.CALLFIXUP_TYPE);
}
else if (name.equals("getCallotherFixup")) {
getPcodeInject(InjectPayload.CALLOTHERFIXUP_TYPE);
}
else if (name.equals("getCallMech")) {
getPcodeInject(InjectPayload.CALLMECHANISM_TYPE);
}
else {
getCPoolRef();
}
break; break;
case 'E': case COMMAND_GETCALLFIXUP:
getExternalRefXML(); // getExternalRefXML getPcodeInject(InjectPayload.CALLFIXUP_TYPE);
break; break;
case 'M': case COMMAND_GETCALLOTHERFIXUP:
getMappedSymbolsXML(); // getMappedSymbolsXML getPcodeInject(InjectPayload.CALLOTHERFIXUP_TYPE);
break; break;
case 'N': case COMMAND_GETCALLMECH:
getNamespacePath(); getPcodeInject(InjectPayload.CALLMECHANISM_TYPE);
break; break;
case 'P': case COMMAND_GETPCODEEXECUTABLE:
getPcodePacked(); // getPacked
break;
case 'R':
if (name.equals("getRegister")) {
getRegister();
}
else {
getRegisterName();
}
break;
case 'S':
if (name.equals("getString")) {
getStringData();
}
else {
getSymbol(); // getSymbol
}
break;
case 'T':
if (name.equals("getType")) {
getType();
}
else {
getTrackedRegisters();
}
break;
case 'U':
getUserOpName(); // getUserOpName
break;
case 'X':
getPcodeInject(InjectPayload.EXECUTABLEPCODE_TYPE); getPcodeInject(InjectPayload.EXECUTABLEPCODE_TYPE);
break; break;
case COMMAND_GETCPOOLREF:
getCPoolRef();
break;
case COMMAND_GETEXTERNALREF:
getExternalRef();
break;
case COMMAND_GETMAPPEDSYMBOLS:
getMappedSymbols();
break;
case COMMAND_GETNAMESPACEPATH:
getNamespacePath();
break;
case COMMAND_GETPCODE:
getPcode();
break;
case COMMAND_GETREGISTER:
getRegister();
break;
case COMMAND_GETREGISTERNAME:
getRegisterName();
break;
case COMMAND_GETSTRINGDATA:
getStringData();
break;
case COMMAND_GETCODELABEL:
getCodeLabel();
break;
case COMMAND_GETDATATYPE:
getDataType();
break;
case COMMAND_GETTRACKEDREGISTERS:
getTrackedRegisters();
break;
case COMMAND_GETUSEROPNAME:
getUserOpName();
break;
default: default:
throw new Exception("Unsupported decompiler query '" + name + "'"); throw new Exception("Unsupported decompiler query");
} }
} }
catch (Exception e) { // Catch ANY exception query generates catch (Exception e) { // Catch ANY exception query generates
@ -384,47 +356,45 @@ public class DecompileProcess {
generateException(); generateException();
break; break;
case 14: // Start of the main decompiler output case 14: // Start of the main decompiler output
if (buf != null) { if (currentResponse != null) {
throw new IOException("Nested decompiler output"); throw new IOException("Nested decompiler output");
} }
// Allocate storage buffer for the result, which is generally not tiny. So we // Allocate storage buffer for the result, which is generally not tiny. So we
// start with any initial allocation of 1024 bytes, also give an absolute upper bound // start with any initial allocation of 1024 bytes, also give an absolute upper bound
// determined by maxResultSizeMBYtes // determined by maxResultSizeMBYtes
buf = new LimitedByteBuffer(1024, maxResultSizeMBYtes << 20); currentResponse = mainResponse;
currentResponse.open(maxResultSizeMBYtes << 20, programSource);
break; break;
case 15: // This is the end of the main decompiler output case 15: // This is the end of the main decompiler output
if (buf == null) { if (currentResponse == null) {
throw new IOException("Mismatched string header"); throw new IOException("Mismatched string header");
} }
retbuf = buf; currentResponse.endIngest();
buf = null; // Reset the main buffer as a native message may follow currentResponse = null; // Reset current buffer as a native message may follow
break; break;
case 16: // Beginning of any native message from the decompiler case 16: // Beginning of any native message from the decompiler
// if (buf!=null) currentResponse = stringDecoder;
// throw new IOException("Nested decompiler output"); currentResponse.open(1 << 20, programSource);
// if buf is non-null, then res was interrupted
// so we just throw out the partial result
buf = new LimitedByteBuffer(64, 1 << 20);
break; break;
case 17: // End of the native message from the decompiler case 17: // End of the native message from the decompiler
if (buf == null) { if (currentResponse == null) {
throw new IOException("Mismatched message header"); throw new IOException("Mismatched message header");
} }
callback.setNativeMessage(buf.toString()); currentResponse.endIngest();
buf = null; callback.setNativeMessage(currentResponse.toString());
currentResponse = null;
break; break;
default: default:
throw new IOException("GHIDRA/decompiler alignment error"); throw new IOException("GHIDRA/decompiler alignment error");
} }
if (buf == null) { if (currentResponse == null) {
type = readToBurst(); type = readToBurst();
} }
else { else {
type = readToBuffer(buf); type = readToBuffer(currentResponse);
} }
} }
return retbuf;
} }
// Calls to the decompiler // Calls to the decompiler
@ -436,16 +406,20 @@ public class DecompileProcess {
* @param cspecxml = string containing .cspec xml * @param cspecxml = string containing .cspec xml
* @param tspecxml = XML string containing translator spec * @param tspecxml = XML string containing translator spec
* @param coretypesxml = XML description of core data-types * @param coretypesxml = XML description of core data-types
* @param program is the program being registered
* @throws IOException for problems with the pipe to the decompiler process * @throws IOException for problems with the pipe to the decompiler process
* @throws DecompileException for problems executing the command * @throws DecompileException for problems executing the command
*/ */
public synchronized void registerProgram(DecompileCallback cback, String pspecxml, public synchronized void registerProgram(DecompileCallback cback, String pspecxml,
String cspecxml, String tspecxml, String coretypesxml) String cspecxml, String tspecxml, String coretypesxml, Program program)
throws IOException, DecompileException { throws IOException, DecompileException {
callback = cback; callback = cback;
programSource = program.getName();
resultEncoder = new PackedEncode();
paramDecoder = new PackedDecode(program.getAddressFactory());
StringIngest response = new StringIngest(); // Don't use stringResponse
setup(); setup();
String restring = null;
try { try {
write(command_start); write(command_start);
writeString("registerProgram"); writeString("registerProgram");
@ -454,13 +428,13 @@ public class DecompileProcess {
writeString(tspecxml); writeString(tspecxml);
writeString(coretypesxml); writeString(coretypesxml);
write(command_end); write(command_end);
restring = readResponse().toString(); readResponse(response);
} }
catch (IOException e) { catch (IOException e) {
statusGood = false; statusGood = false;
throw e; throw e;
} }
archId = Integer.parseInt(restring); archId = Integer.parseInt(response.toString());
} }
/** /**
@ -476,42 +450,43 @@ public class DecompileProcess {
// Once a program is deregistered, the process is never // Once a program is deregistered, the process is never
// used again // used again
statusGood = false; statusGood = false;
String restring = null;
write(command_start); write(command_start);
writeString("deregisterProgram"); writeString("deregisterProgram");
writeString(Integer.toString(archId)); writeString(Integer.toString(archId));
write(command_end); write(command_end);
restring = readResponse().toString(); StringIngest response = new StringIngest(); // Don't use stringResponse
readResponse(response);
int res = Integer.parseInt(response.toString());
callback = null; callback = null;
int res = Integer.parseInt(restring); programSource = null;
paramDecoder = null;
resultEncoder = null;
return res; return res;
} }
/** /**
* Send a single command to the decompiler with no parameters and return response * Send a single command to the decompiler with no parameters and return response
* @param command is the name of the command to execute * @param command is the name of the command to execute
* @return the response String * @param response the response accumulator
* @throws IOException for any problems with the pipe to the decompiler process * @throws IOException for any problems with the pipe to the decompiler process
* @throws DecompileException for any problems executing the command * @throws DecompileException for any problems executing the command
*/ */
public synchronized LimitedByteBuffer sendCommand(String command) public synchronized void sendCommand(String command, ByteIngest response)
throws IOException, DecompileException { throws IOException, DecompileException {
if (!statusGood) { if (!statusGood) {
throw new IOException(command + " called on bad process"); throw new IOException(command + " called on bad process");
} }
LimitedByteBuffer resbuf = null;
try { try {
write(command_start); write(command_start);
writeString(command); writeString(command);
writeString(Integer.toString(archId)); writeString(Integer.toString(archId));
write(command_end); write(command_end);
resbuf = readResponse(); readResponse(response);
} }
catch (IOException e) { catch (IOException e) {
statusGood = false; statusGood = false;
throw e; throw e;
} }
return resbuf;
} }
public synchronized boolean isReady() { public synchronized boolean isReady() {
@ -520,20 +495,19 @@ public class DecompileProcess {
/** /**
* @param command the decompiler should execute * @param command the decompiler should execute
* @param param an additional parameter for the command * @param param an additional (encoded) parameter for the command
* @param timeoutSecs the number of seconds to run before timing out * @param timeoutSecs the number of seconds to run before timing out
* @return the response string * @param response the response accumulator
* @throws IOException for any problems with the pipe to the decompiler process * @throws IOException for any problems with the pipe to the decompiler process
* @throws DecompileException for any problems while executing the command * @throws DecompileException for any problems while executing the command
*/ */
public synchronized LimitedByteBuffer sendCommand1ParamTimeout(String command, String param, public synchronized void sendCommand1ParamTimeout(String command, Encoder param,
int timeoutSecs) throws IOException, DecompileException { int timeoutSecs, ByteIngest response) throws IOException, DecompileException {
if (!statusGood) { if (!statusGood) {
throw new IOException(command + " called on bad process"); throw new IOException(command + " called on bad process");
} }
LimitedByteBuffer resbuf = null;
int validatedTimeoutMs = getTimeoutMs(timeoutSecs); int validatedTimeoutMs = getTimeoutMs(timeoutSecs);
GTimerMonitor timerMonitor = GTimer.scheduleRunnable(validatedTimeoutMs, timeoutRunnable); GTimerMonitor timerMonitor = GTimer.scheduleRunnable(validatedTimeoutMs, timeoutRunnable);
@ -543,7 +517,7 @@ public class DecompileProcess {
writeString(Integer.toString(archId)); writeString(Integer.toString(archId));
writeString(param); writeString(param);
write(command_end); write(command_end);
resbuf = readResponse(); readResponse(response);
} }
catch (IOException e) { catch (IOException e) {
statusGood = false; statusGood = false;
@ -556,7 +530,6 @@ public class DecompileProcess {
finally { finally {
timerMonitor.cancel(); timerMonitor.cancel();
} }
return resbuf;
} }
private int getTimeoutMs(int timeoutSecs) { private int getTimeoutMs(int timeoutSecs) {
@ -571,16 +544,15 @@ public class DecompileProcess {
* @param command string to send * @param command string to send
* @param param1 is the first parameter string * @param param1 is the first parameter string
* @param param2 is the second parameter string * @param param2 is the second parameter string
* @return the result string * @param response the response accumulator
* @throws IOException for any problems with the pipe to the decompiler process * @throws IOException for any problems with the pipe to the decompiler process
* @throws DecompileException for problems executing the command * @throws DecompileException for problems executing the command
*/ */
public synchronized LimitedByteBuffer sendCommand2Params(String command, String param1, public synchronized void sendCommand2Params(String command, String param1, String param2,
String param2) throws IOException, DecompileException { ByteIngest response) throws IOException, DecompileException {
if (!statusGood) { if (!statusGood) {
throw new IOException(command + " called on bad process"); throw new IOException(command + " called on bad process");
} }
LimitedByteBuffer resbuf = null;
try { try {
write(command_start); write(command_start);
writeString(command); writeString(command);
@ -588,15 +560,19 @@ public class DecompileProcess {
writeString(param1); writeString(param1);
writeString(param2); writeString(param2);
write(command_end); write(command_end);
resbuf = readResponse(); readResponse(response);
} }
catch (IOException e) { catch (IOException e) {
statusGood = false; statusGood = false;
throw e; throw e;
} }
return resbuf;
} }
/**
* Set an upper limit on the amount of data that can be sent back by the decompiler in response
* to a single command.
* @param maxResultSizeMBytes is the maximum size in megabytes
*/
public void setMaxResultSize(int maxResultSizeMBytes) { public void setMaxResultSize(int maxResultSizeMBytes) {
this.maxResultSizeMBYtes = maxResultSizeMBytes; this.maxResultSizeMBYtes = maxResultSizeMBytes;
} }
@ -604,64 +580,94 @@ public class DecompileProcess {
/** /**
* Send a command to the decompiler with one parameter and return the result * Send a command to the decompiler with one parameter and return the result
* @param command is the command string * @param command is the command string
* @param param1 is the parameter as a string * @param param1 is the encoded parameter
* @return the result string * @param response is the result accumulator
* @throws IOException for problems with the pipe to the decompiler process * @throws IOException for problems with the pipe to the decompiler process
* @throws DecompileException for problems executing the command * @throws DecompileException for problems executing the command
*/ */
public synchronized LimitedByteBuffer sendCommand1Param(String command, String param1) public synchronized void sendCommand1Param(String command, Encoder param1, ByteIngest response)
throws IOException, DecompileException { throws IOException, DecompileException {
if (!statusGood) { if (!statusGood) {
throw new IOException(command + " called on bad process"); throw new IOException(command + " called on bad process");
} }
LimitedByteBuffer resbuf = null;
try { try {
write(command_start); write(command_start);
writeString(command); writeString(command);
writeString(Integer.toString(archId)); writeString(Integer.toString(archId));
writeString(param1); writeString(param1);
write(command_end); write(command_end);
resbuf = readResponse(); readResponse(response);
}
catch (IOException e) {
statusGood = false;
throw e;
}
}
/**
* Send a command to the decompiler with one parameter and return the result
* @param command is the command string
* @param param1 is the parameter encoded as a string
* @param response is the result accumulator
* @throws IOException for problems with the pipe to the decompiler process
* @throws DecompileException for problems executing the command
*/
public synchronized void sendCommand1Param(String command, String param1, ByteIngest response)
throws IOException, DecompileException {
if (!statusGood) {
throw new IOException(command + " called on bad process");
}
try {
write(command_start);
writeString(command);
writeString(Integer.toString(archId));
writeString(param1);
write(command_end);
readResponse(response);
} }
catch (IOException e) { catch (IOException e) {
statusGood = false; statusGood = false;
throw e; throw e;
} }
return resbuf;
} }
// Calls from the decompiler // Calls from the decompiler
private void getRegister() throws IOException { private void getRegister() throws IOException, DecoderException {
String name = readQueryString(); resultEncoder.clear();
byte[] res = callback.getRegister(name); String name = paramDecoder.readString(ATTRIB_NAME);
callback.getRegister(name, resultEncoder);
write(query_response_start); write(query_response_start);
if (res.length != 0) { if (!resultEncoder.isEmpty()) {
writeBytes(res); writeString(resultEncoder);
} }
write(query_response_end); write(query_response_end);
} }
private void getRegisterName() throws IOException { private void getRegisterName() throws IOException, DecoderException {
String addr = readQueryString(); int el = paramDecoder.openElement(ELEM_ADDR);
Address addr = AddressXML.decodeFromAttributes(paramDecoder);
int size = (int) paramDecoder.readSignedInteger(ATTRIB_SIZE);
paramDecoder.closeElement(el);
String res = callback.getRegisterName(addr); String res = callback.getRegisterName(addr, size);
write(query_response_start); write(query_response_start);
writeString(res); writeString(res);
write(query_response_end); write(query_response_end);
} }
private void getTrackedRegisters() throws IOException { private void getTrackedRegisters() throws IOException, DecoderException {
String addr = readQueryString(); resultEncoder.clear();
byte[] res = callback.getTrackedRegisters(addr); Address addr = AddressXML.decode(paramDecoder);
callback.getTrackedRegisters(addr, resultEncoder);
write(query_response_start); write(query_response_start);
writeBytes(res); writeString(resultEncoder);
write(query_response_end); write(query_response_end);
} }
private void getUserOpName() throws IOException { private void getUserOpName() throws IOException, DecoderException {
String indexStr = readQueryString(); int index = (int) paramDecoder.readSignedInteger(ATTRIB_INDEX);
String res = callback.getUserOpName(indexStr); String res = callback.getUserOpName(index);
if (res == null) { if (res == null) {
res = ""; res = "";
} }
@ -670,70 +676,72 @@ public class DecompileProcess {
write(query_response_end); write(query_response_end);
} }
private void getPcodePacked() throws IOException { private void getPcode() throws IOException, DecoderException {
String addr = readQueryString(); resultEncoder.clear();
PackedBytes out = callback.getPcodePacked(addr); Address addr = AddressXML.decode(paramDecoder);
callback.getPcode(addr, resultEncoder);
write(query_response_start); write(query_response_start);
if ((out != null) && (out.size() != 0)) { if (!resultEncoder.isEmpty()) {
writeBytes(out); writeString(resultEncoder);
} }
write(query_response_end); write(query_response_end);
} }
private void getPcodeInject(int type) throws IOException { private void getPcodeInject(int type) throws IOException, DecoderException {
String name = readQueryString(); resultEncoder.clear();
String context = readQueryString(); String name = paramDecoder.readString(ATTRIB_NAME);
byte[] res = callback.getPcodeInject(name, context, type); callback.getPcodeInject(name, paramDecoder, type, resultEncoder);
write(query_response_start); write(query_response_start);
if (res.length != 0) { if (!resultEncoder.isEmpty()) {
writeBytes(res); writeString(resultEncoder);
} }
write(query_response_end); write(query_response_end);
} }
private void getCPoolRef() throws IOException { private void getCPoolRef() throws IOException, DecoderException {
String liststring = readQueryString(); resultEncoder.clear();
String[] split = liststring.split(","); int size = (int) paramDecoder.readSignedInteger(ATTRIB_SIZE);
long[] refs = new long[split.length]; long refs[] = new long[size];
for (int i = 0; i < split.length; ++i) { for (int i = 0; i < size; ++i) {
refs[i] = Long.parseUnsignedLong(split[i], 16); int el = paramDecoder.openElement(ELEM_VALUE);
refs[i] = paramDecoder.readUnsignedInteger(ATTRIB_CONTENT);
paramDecoder.closeElement(el);
} }
byte[] res = callback.getCPoolRef(refs); callback.getCPoolRef(refs, resultEncoder);
write(query_response_start); write(query_response_start);
if (res.length != 0) { if (!resultEncoder.isEmpty()) {
writeBytes(res); writeString(resultEncoder);
} }
write(query_response_end); write(query_response_end);
} }
private void getMappedSymbolsXML() throws IOException { private void getMappedSymbols() throws IOException, DecoderException {
String addr = readQueryString(); resultEncoder.clear();
Address addr = AddressXML.decode(paramDecoder);
callback.getMappedSymbols(addr, resultEncoder);
byte[] res = callback.getMappedSymbolsXML(addr);
write(query_response_start); write(query_response_start);
if (res.length != 0) { if (!resultEncoder.isEmpty()) {
writeBytes(res); writeString(resultEncoder);
} }
write(query_response_end); write(query_response_end);
} }
private void getNamespacePath() throws IOException { private void getNamespacePath() throws IOException, DecoderException {
String idString = readQueryString(); resultEncoder.clear();
long id = Long.parseLong(idString, 16); long id = paramDecoder.readUnsignedInteger(ATTRIB_ID);
byte[] res = callback.getNamespacePath(id); callback.getNamespacePath(id, resultEncoder);
write(query_response_start); write(query_response_start);
if (res.length != 0) { if (!resultEncoder.isEmpty()) {
writeBytes(res); writeString(resultEncoder);
} }
write(query_response_end); write(query_response_end);
} }
private void isNameUsed() throws IOException { private void isNameUsed() throws IOException, DecoderException {
String name = readQueryString(); String name = paramDecoder.readString(ATTRIB_NAME);
String startString = readQueryString(); long startId = paramDecoder.readUnsignedInteger(ATTRIB_FIRST);
String stopString = readQueryString(); long stopId = paramDecoder.readUnsignedInteger(ATTRIB_LAST);
long startId = Long.parseLong(startString, 16);
long stopId = Long.parseLong(stopString, 16);
boolean res = callback.isNameUsed(name, startId, stopId); boolean res = callback.isNameUsed(name, startId, stopId);
write(query_response_start); write(query_response_start);
write(string_start); write(string_start);
@ -742,20 +750,20 @@ public class DecompileProcess {
write(query_response_end); write(query_response_end);
} }
private void getExternalRefXML() throws IOException { private void getExternalRef() throws IOException, DecoderException {
String refaddr = readQueryString(); resultEncoder.clear();
byte[] res = callback.getExternalRefXML(refaddr); Address addr = AddressXML.decode(paramDecoder);
callback.getExternalRef(addr, resultEncoder);
write(query_response_start); write(query_response_start);
if (res.length != 0) { if (!resultEncoder.isEmpty()) {
writeBytes(res); writeString(resultEncoder);
} }
write(query_response_end); write(query_response_end);
} }
private void getSymbol() throws IOException { private void getCodeLabel() throws IOException, DecoderException {
String addr = readQueryString(); Address addr = AddressXML.decode(paramDecoder);
String res = callback.getCodeLabel(addr);
String res = callback.getSymbol(addr);
if (res == null) { if (res == null) {
res = ""; res = "";
} }
@ -764,29 +772,35 @@ public class DecompileProcess {
write(query_response_end); write(query_response_end);
} }
private void getComments() throws IOException { private void getComments() throws IOException, DecoderException {
String addr = readQueryString(); resultEncoder.clear();
String flags = readQueryString(); int types = (int) paramDecoder.readUnsignedInteger(ATTRIB_TYPE);
byte[] res = callback.getComments(addr, flags); Address addr = AddressXML.decode(paramDecoder);
callback.getComments(addr, types, resultEncoder);
write(query_response_start); write(query_response_start);
writeBytes(res); writeString(resultEncoder);
write(query_response_end); write(query_response_end);
} }
private void getType() throws IOException { private void getDataType() throws IOException, DecoderException {
String name = readQueryString(); resultEncoder.clear();
long id = SpecXmlUtils.decodeLong(readQueryString()); String name = paramDecoder.readString(ATTRIB_NAME);
byte[] res = callback.getType(name, id); long id = paramDecoder.readSignedInteger(ATTRIB_ID);
callback.getDataType(name, id, resultEncoder);
write(query_response_start); write(query_response_start);
if (res.length != 0) { if (!resultEncoder.isEmpty()) {
writeBytes(res); writeString(resultEncoder);
} }
write(query_response_end); write(query_response_end);
} }
private void getBytes() throws IOException { private void getBytes() throws IOException, DecoderException {
String size = readQueryString(); int el = paramDecoder.openElement(ELEM_ADDR);
byte[] res = callback.getBytes(size); Address addr = AddressXML.decodeFromAttributes(paramDecoder);
int size = (int) paramDecoder.readSignedInteger(ATTRIB_SIZE);
paramDecoder.closeElement(el);
byte[] res = callback.getBytes(addr, size);
write(query_response_start); write(query_response_start);
if ((res != null) && (res.length > 0)) { if ((res != null) && (res.length > 0)) {
write(byte_start); write(byte_start);
@ -801,11 +815,13 @@ public class DecompileProcess {
write(query_response_end); write(query_response_end);
} }
private void getStringData() throws IOException { private void getStringData() throws IOException, DecoderException {
String addr = readQueryString(); int maxChars = (int) paramDecoder.readSignedInteger(ATTRIB_MAXSIZE);
String dtName = readQueryString(); String dtName = paramDecoder.readString(ATTRIB_TYPE);
long dtId = SpecXmlUtils.decodeLong(readQueryString()); long dtId = paramDecoder.readUnsignedInteger(ATTRIB_ID);
DecompileCallback.StringData stringData = callback.getStringData(addr, dtName, dtId); Address addr = AddressXML.decode(paramDecoder);
DecompileCallback.StringData stringData =
callback.getStringData(addr, maxChars, dtName, dtId);
write(query_response_start); write(query_response_start);
if (stringData != null) { if (stringData != null) {
byte[] res = stringData.byteData; byte[] res = stringData.byteData;

View File

@ -17,8 +17,6 @@ package ghidra.app.decompiler;
import static ghidra.program.model.pcode.ElementId.*; import static ghidra.program.model.pcode.ElementId.*;
import java.io.InputStream;
import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
@ -64,7 +62,7 @@ public class DecompileResults {
private DecompileProcess.DisposeState processState; private DecompileProcess.DisposeState processState;
public DecompileResults(Function f, Language language, CompilerSpec compilerSpec, public DecompileResults(Function f, Language language, CompilerSpec compilerSpec,
PcodeDataTypeManager d, String e, InputStream raw, PcodeDataTypeManager d, String e, Decoder decoder,
DecompileProcess.DisposeState processState) { DecompileProcess.DisposeState processState) {
function = f; function = f;
this.language = language; this.language = language;
@ -75,7 +73,7 @@ public class DecompileResults {
hparamid = null; hparamid = null;
docroot = null; docroot = null;
//dumpResults(raw); //dumpResults(raw);
decodeStream(raw); decodeStream(decoder);
} }
// private void dumpResults(String raw) { // private void dumpResults(String raw) {
@ -203,14 +201,11 @@ public class DecompileResults {
return printer.print(true); return printer.print(true);
} }
private void decodeStream(InputStream rawstream) { private void decodeStream(Decoder decoder) {
if (rawstream == null) { if (decoder == null || decoder.isEmpty()) {
return; return;
} }
XmlDecode decoder = new XmlDecode(function.getProgram().getAddressFactory());
try { try {
decoder.ingestStream(rawstream,
"Decompiler results for function at " + function.getEntryPoint());
hfunc = null; hfunc = null;
hparamid = null; hparamid = null;
docroot = null; docroot = null;
@ -243,13 +238,13 @@ public class DecompileResults {
} }
decoder.closeElement(docel); decoder.closeElement(docel);
} }
catch (PcodeXMLException e) { // Error while walking the DOM catch (DecoderException e) { // Error while walking the DOM
errMsg = e.getMessage(); errMsg = e.getMessage();
hfunc = null; hfunc = null;
hparamid = null; hparamid = null;
return; return;
} }
catch (RuntimeException e) { // Exception from the raw parser catch (Exception e) { // Exception with the underlying stream
errMsg = e.getMessage(); errMsg = e.getMessage();
hfunc = null; hfunc = null;
hparamid = null; hparamid = null;

View File

@ -1,82 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* 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.
*/
package ghidra.app.decompiler;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* Class for accumulating bytes into an automatically expanding buffer with an explicit upper limit to the size
*
*/
public class LimitedByteBuffer {
byte value[];
int count; // Current number of characters
int absmax; // Absolute maximum number of characters
/**
* Create the buffer specifying its initial and limiting capacity
* @param initial is the number of bytes to be initially allocated for the buffer
* @param amax is the absolute maximum number of bytes the buffer is allowed to expand to before throwing exceptions
*/
public LimitedByteBuffer(int initial,int amax) {
value = new byte[initial];
count = 0;
absmax = amax;
}
/**
* Append a byte into the buffer. The buffer's internal storage is expanded as necessary, but only up to
* the specified maximum. If this append exceeds that maximum, then an exception is thrown
* @param b is the byte to append
* @throws IOException
*/
public void append(byte b) throws IOException {
int newCount = count + 1;
if (newCount > value.length) {
if (newCount > absmax) {
int maxResultSizeMBytes = absmax >> 20;
throw new IOException("Decompiler results exceeded payload limit of " +
maxResultSizeMBytes + " MBytes");
}
int newcapacity = value.length * 2;
if (newcapacity < 0)
newcapacity = Integer.MAX_VALUE;
if (newcapacity > absmax)
newcapacity = absmax;
value = Arrays.copyOf(value, newcapacity);
}
value[count++] = b;
}
/**
* Generate an InputStream from the bytes that have been appended to the buffer
* The buffer is NOT copied
* @return the new InputStream
*/
public ByteArrayInputStream getInputStream() {
return new ByteArrayInputStream(value,0,count);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return new String(value,0,count);
}
}

View File

@ -142,7 +142,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
throw new RuntimeException("Unable to initialize: " + ifc.getLastMessage()); throw new RuntimeException("Unable to initialize: " + ifc.getLastMessage());
} }
outgraph = ifc.structureGraph(ingraph, program.getAddressFactory(), 0, monitor); outgraph = ifc.structureGraph(ingraph, 0, monitor);
} }
finally { finally {
ifc.dispose(); ifc.dispose();

View File

@ -19,6 +19,7 @@
*/ */
package ghidra.app.plugin.processors.sleigh; package ghidra.app.plugin.processors.sleigh;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.app.plugin.processors.sleigh.symbol.*; import ghidra.app.plugin.processors.sleigh.symbol.*;
@ -188,8 +189,9 @@ public abstract class PcodeEmit {
* <li>last pcode op has fall-through</li> * <li>last pcode op has fall-through</li>
* <li>internal label used to branch beyond last pcode op</li> * <li>internal label used to branch beyond last pcode op</li>
* </ul> * </ul>
* @throws IOException for stream errors emitting ops
*/ */
void resolveFinalFallthrough() { void resolveFinalFallthrough() throws IOException {
try { try {
if (fallOverride == null || fallOverride.equals(getStartAddress().add(fallOffset))) { if (fallOverride == null || fallOverride.equals(getStartAddress().add(fallOffset))) {
return; return;
@ -207,9 +209,10 @@ public abstract class PcodeEmit {
dump(startAddress, PcodeOp.BRANCH, new VarnodeData[] { dest }, 1, null); dump(startAddress, PcodeOp.BRANCH, new VarnodeData[] { dest }, 1, null);
} }
abstract void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out); abstract void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out)
throws IOException;
private boolean dumpBranchOverride(OpTpl opt) { private boolean dumpBranchOverride(OpTpl opt) throws IOException {
int opcode = opt.getOpcode(); int opcode = opt.getOpcode();
VarnodeTpl[] inputs = opt.getInput(); VarnodeTpl[] inputs = opt.getInput();
if (opcode == PcodeOp.CALL) { if (opcode == PcodeOp.CALL) {
@ -227,7 +230,7 @@ public abstract class PcodeEmit {
return false; return false;
} }
private void dumpNullReturn() { private void dumpNullReturn() throws IOException {
VarnodeTpl nullAddr = VarnodeTpl nullAddr =
new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.REAL, 0), new VarnodeTpl(new ConstTpl(const_space), new ConstTpl(ConstTpl.REAL, 0),
@ -237,7 +240,7 @@ public abstract class PcodeEmit {
dump(retOpt); dump(retOpt);
} }
private boolean dumpCallOverride(OpTpl opt, boolean returnAfterCall) { private boolean dumpCallOverride(OpTpl opt, boolean returnAfterCall) throws IOException {
int opcode = opt.getOpcode(); int opcode = opt.getOpcode();
VarnodeTpl[] inputs = opt.getInput(); VarnodeTpl[] inputs = opt.getInput();
if (opcode == PcodeOp.BRANCH) { if (opcode == PcodeOp.BRANCH) {
@ -316,7 +319,7 @@ public abstract class PcodeEmit {
return false; return false;
} }
private boolean dumpReturnOverride(OpTpl opt) { private boolean dumpReturnOverride(OpTpl opt) throws IOException {
int opcode = opt.getOpcode(); int opcode = opt.getOpcode();
VarnodeTpl[] inputs = opt.getInput(); VarnodeTpl[] inputs = opt.getInput();
@ -416,7 +419,7 @@ public abstract class PcodeEmit {
return false; return false;
} }
private boolean dumpFlowOverride(OpTpl opt) { private boolean dumpFlowOverride(OpTpl opt) throws IOException {
if (flowOverride == null || opt.getOutput() != null) { if (flowOverride == null || opt.getOutput() != null) {
return false; // only call, branch and return instructions can be affected return false; // only call, branch and return instructions can be affected
} }
@ -483,8 +486,9 @@ public abstract class PcodeEmit {
* We assume the location of the base pointer is in dyncache[1] * We assume the location of the base pointer is in dyncache[1]
* @param dyncache is the existing array * @param dyncache is the existing array
* @param vn is the V_OFFSET_PLUS VarnodeTpl to adjust for * @param vn is the V_OFFSET_PLUS VarnodeTpl to adjust for
* @throws IOException for stream errors emitting ops
*/ */
private void generatePointerAdd(VarnodeData[] dyncache, VarnodeTpl vn) { private void generatePointerAdd(VarnodeData[] dyncache, VarnodeTpl vn) throws IOException {
long offsetPlus = vn.getOffset().getReal() & 0xffff; long offsetPlus = vn.getOffset().getReal() & 0xffff;
if (offsetPlus == 0) { if (offsetPlus == 0) {
return; return;
@ -505,7 +509,7 @@ public abstract class PcodeEmit {
dyncache[1] = tmpData; dyncache[1] = tmpData;
} }
private void dump(OpTpl opt) { private void dump(OpTpl opt) throws IOException {
VarnodeData[] dyncache = null; VarnodeData[] dyncache = null;
VarnodeTpl vn, outvn; VarnodeTpl vn, outvn;
@ -581,7 +585,7 @@ public abstract class PcodeEmit {
} }
private void appendBuild(OpTpl bld, int secnum) private void appendBuild(OpTpl bld, int secnum)
throws UnknownInstructionException, MemoryAccessException { throws UnknownInstructionException, MemoryAccessException, IOException {
// Recover operand index from build statement // Recover operand index from build statement
int index = (int) bld.getInput()[0].getOffset().getReal(); int index = (int) bld.getInput()[0].getOffset().getReal();
Symbol sym = walker.getConstructor().getOperand(index).getDefiningSymbol(); Symbol sym = walker.getConstructor().getOperand(index).getDefiningSymbol();
@ -612,8 +616,10 @@ public abstract class PcodeEmit {
* @param op is the DELAYSLOT directive * @param op is the DELAYSLOT directive
* @throws UnknownInstructionException for problems finding the delay slot Instruction * @throws UnknownInstructionException for problems finding the delay slot Instruction
* @throws MemoryAccessException for problems resolving details of the delay slot Instruction * @throws MemoryAccessException for problems resolving details of the delay slot Instruction
* @throws IOException for stream errors emitting ops
*/ */
private void delaySlot(OpTpl op) throws UnknownInstructionException, MemoryAccessException { private void delaySlot(OpTpl op)
throws UnknownInstructionException, MemoryAccessException, IOException {
if (inDelaySlot) { if (inDelaySlot) {
throw new SleighException( throw new SleighException(
@ -656,9 +662,10 @@ public abstract class PcodeEmit {
* @param secnum is the section number of the section containing the CROSSBUILD directive * @param secnum is the section number of the section containing the CROSSBUILD directive
* @throws UnknownInstructionException for problems finding the referenced Instruction * @throws UnknownInstructionException for problems finding the referenced Instruction
* @throws MemoryAccessException for problems resolving details of the referenced Instruction * @throws MemoryAccessException for problems resolving details of the referenced Instruction
* @throws IOException for stream errors emitting ops
*/ */
private void appendCrossBuild(OpTpl bld, int secnum) private void appendCrossBuild(OpTpl bld, int secnum)
throws UnknownInstructionException, MemoryAccessException { throws UnknownInstructionException, MemoryAccessException, IOException {
if (secnum >= 0) { if (secnum >= 0) {
throw new SleighException( throw new SleighException(
"CROSSBUILD recursion problem for instruction at " + walker.getAddr()); "CROSSBUILD recursion problem for instruction at " + walker.getAddr());
@ -698,7 +705,7 @@ public abstract class PcodeEmit {
} }
public void build(ConstructTpl construct, int secnum) public void build(ConstructTpl construct, int secnum)
throws UnknownInstructionException, MemoryAccessException { throws UnknownInstructionException, MemoryAccessException, IOException {
if (construct == null) { if (construct == null) {
throw new NotYetImplementedException( throw new NotYetImplementedException(
"Semantics for this instruction are not implemented"); "Semantics for this instruction are not implemented");
@ -739,9 +746,10 @@ public abstract class PcodeEmit {
* @param secnum index of the section to be built * @param secnum index of the section to be built
* @throws MemoryAccessException for problems resolving details of the underlying Instruction * @throws MemoryAccessException for problems resolving details of the underlying Instruction
* @throws UnknownInstructionException for problems finding the underlying Instruction * @throws UnknownInstructionException for problems finding the underlying Instruction
* @throws IOException for stream errors emitting ops
*/ */
private void buildEmpty(Constructor ct, int secnum) private void buildEmpty(Constructor ct, int secnum)
throws UnknownInstructionException, MemoryAccessException { throws UnknownInstructionException, MemoryAccessException, IOException {
int numops = ct.getNumOperands(); int numops = ct.getNumOperands();
for (int i = 0; i < numops; ++i) { for (int i = 0; i < numops; ++i) {

View File

@ -15,22 +15,21 @@
*/ */
package ghidra.app.plugin.processors.sleigh; package ghidra.app.plugin.processors.sleigh;
import static ghidra.program.model.pcode.AttributeId.*;
import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.InstructionContext; import ghidra.program.model.lang.InstructionContext;
import ghidra.program.model.lang.PackedBytes; import ghidra.program.model.pcode.*;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.PcodeOverride;
/** /**
* *
* *
*/ */
public class PcodeEmitPacked extends PcodeEmit { public class PcodeEmitPacked extends PcodeEmit {
public final static int unimpl_tag = 0x20, inst_tag = 0x21, op_tag = 0x22, void_tag = 0x23,
spaceid_tag = 0x24, addrsz_tag = 0x25, end_tag = 0x60; // End of a number
public class LabelRef { public class LabelRef {
public int opIndex; // Index of operation referencing the label public int opIndex; // Index of operation referencing the label
@ -46,33 +45,32 @@ public class PcodeEmitPacked extends PcodeEmit {
} }
} }
private PackedBytes buf; private PatchEncoder encoder;
private ArrayList<LabelRef> labelref = null; private ArrayList<LabelRef> labelref = null;
private boolean hasRelativePatch = false;
/**
* Pcode emitter constructor for producing a packed binary representation
* for unimplemented or empty responses.
*/
public PcodeEmitPacked() {
super();
buf = new PackedBytes(64);
}
/** /**
* Pcode emitter constructor for producing a packed binary representation. * Pcode emitter constructor for producing a packed binary representation.
* @param encoder is the stream encoder to emit to
* @param walk parser walker * @param walk parser walker
* @param ictx instruction contexts * @param ictx instruction contexts
* @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions) * @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions)
* @param override required if pcode overrides are to be utilized * @param override required if pcode overrides are to be utilized
*/ */
public PcodeEmitPacked(ParserWalker walk, InstructionContext ictx, int fallOffset, public PcodeEmitPacked(PatchEncoder encoder, ParserWalker walk, InstructionContext ictx,
PcodeOverride override) { int fallOffset, PcodeOverride override) {
super(walk, ictx, fallOffset, override); super(walk, ictx, fallOffset, override);
buf = new PackedBytes(512); this.encoder = encoder;
} }
public PackedBytes getPackedBytes() { public void emitHeader() throws IOException {
return buf; encoder.openElement(ELEM_INST);
encoder.writeSignedInteger(ATTRIB_OFFSET, getFallOffset());
AddressXML.encode(encoder, getStartAddress());
}
public void emitTail() throws IOException {
encoder.closeElement(ELEM_INST);
} }
@Override @Override
@ -90,8 +88,9 @@ public class PcodeEmitPacked extends PcodeEmit {
mask >>>= (8 - ref.labelSize) * 8; mask >>>= (8 - ref.labelSize) * 8;
res &= mask; res &= mask;
} }
// We need to skip over op_tag, op_code, void_tag, addrsz_tag, and spc bytes if (!encoder.patchIntegerAttribute(ref.streampos, ATTRIB_OFFSET, res)) {
insertOffset(ref.streampos + 5, res); // Insert the final offset into the stream throw new SleighException("PcodeEmitPacked: Unable to patch relative offset");
}
} }
} }
@ -100,92 +99,60 @@ public class PcodeEmitPacked extends PcodeEmit {
*/ */
@Override @Override
void addLabelRef() { void addLabelRef() {
// We know we need to do patching on a particular input parameter
if (labelref == null) { if (labelref == null) {
labelref = new ArrayList<>(); labelref = new ArrayList<>();
} }
// Delay putting in the LabelRef until we are ready to emit the parameter
hasRelativePatch = true;
}
/**
* Create the LabelRef now that the next element written will be the parameter needing a patch
*/
private void addLabelRefDelayed() {
int labelIndex = (int) incache[0].offset; int labelIndex = (int) incache[0].offset;
int labelSize = incache[0].size; int labelSize = incache[0].size;
// Force the emitter to write out a maximum length encoding (12 bytes) of a long // Force the encoder to write out a maximum length encoding of a long
// so that we have space to insert whatever value we need to when this relative is resolved // so that we have space to insert whatever value we need to when this relative is resolved
incache[0].offset = -1; incache[0].offset = -1;
labelref.add(new LabelRef(numOps, labelIndex, labelSize, buf.size())); labelref.add(new LabelRef(numOps, labelIndex, labelSize, encoder.size()));
hasRelativePatch = false; // Mark patch as handled
} }
/* (non-Javadoc)
* @see ghidra.app.plugin.processors.sleigh.PcodeEmit#dump(ghidra.program.model.address.Address, int, ghidra.app.plugin.processors.sleigh.VarnodeData[], int, ghidra.app.plugin.processors.sleigh.VarnodeData)
*/
@Override @Override
void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out) { void dump(Address instrAddr, int opcode, VarnodeData[] in, int isize, VarnodeData out)
throws IOException {
opcode = checkOverrides(opcode, in); opcode = checkOverrides(opcode, in);
checkOverlays(opcode, in, isize, out); checkOverlays(opcode, in, isize, out);
buf.write(op_tag); encoder.openElement(ELEM_OP);
buf.write(opcode + 0x20); encoder.writeSignedInteger(ATTRIB_CODE, opcode);
encoder.writeSignedInteger(ATTRIB_SIZE, isize);
if (out == null) { if (out == null) {
buf.write(void_tag); encoder.openElement(ELEM_VOID);
encoder.closeElement(ELEM_VOID);
} }
else { else {
dumpVarnodeData(out); out.encode(encoder);
} }
int i = 0; int i = 0;
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) { if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
dumpSpaceId(in[0]); dumpSpaceId(in[0]);
i = 1; i = 1;
} }
else if (hasRelativePatch) {
addLabelRefDelayed();
}
for (; i < isize; ++i) { for (; i < isize; ++i) {
dumpVarnodeData(in[i]); in[i].encode(encoder);
} }
buf.write(end_tag); encoder.closeElement(ELEM_OP);
} }
private void dumpSpaceId(VarnodeData v) { private void dumpSpaceId(VarnodeData v) throws IOException {
buf.write(spaceid_tag); encoder.openElement(ELEM_SPACEID);
int spcindex = ((int) v.offset >> AddressSpace.ID_UNIQUE_SHIFT); encoder.writeSpaceId(ATTRIB_NAME, v.offset);
buf.write(spcindex + 0x20); encoder.closeElement(ELEM_SPACEID);
}
private void dumpVarnodeData(VarnodeData v) {
buf.write(addrsz_tag);
int spcindex = v.space.getUnique();
buf.write(spcindex + 0x20);
dumpOffset(v.offset);
buf.write(v.size + 0x20);
}
public void write(int val) {
buf.write(val);
}
/**
* Encode and dump an integer value to the packed byte stream
* @param val is the integer to write
*/
public void dumpOffset(long val) {
while (val != 0) {
int chunk = (int) (val & 0x3f);
val >>>= 6;
buf.write(chunk + 0x20);
}
buf.write(end_tag);
}
private void insertOffset(int streampos, long val) {
while (val != 0) {
if (buf.getByte(streampos) == end_tag) {
throw new SleighException("Could not properly insert relative jump offset");
}
int chunk = (int) (val & 0x3f);
val >>>= 6;
buf.insertByte(streampos, chunk + 0x20);
streampos += 1;
}
for (int i = 0; i < 11; ++i) {
if (buf.getByte(streampos) == end_tag) {
return;
}
buf.insertByte(streampos, 0x20); // Zero fill
streampos += 1;
}
throw new SleighException("Could not find terminator while inserting relative jump offset");
} }
} }

View File

@ -15,6 +15,7 @@
*/ */
package ghidra.app.plugin.processors.sleigh; package ghidra.app.plugin.processors.sleigh;
import java.io.IOException;
import java.util.*; import java.util.*;
import ghidra.app.plugin.assembler.sleigh.sem.AssemblyResolvedPatterns; import ghidra.app.plugin.assembler.sleigh.sem.AssemblyResolvedPatterns;
@ -1018,7 +1019,8 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
@Override @Override
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override) { public void getPcodePacked(PatchEncoder encoder, InstructionContext context,
PcodeOverride override) throws IOException {
int fallOffset = getLength(); int fallOffset = getLength();
try { try {
SleighParserContext protoContext = (SleighParserContext) context.getParserContext(); SleighParserContext protoContext = (SleighParserContext) context.getParserContext();
@ -1037,23 +1039,17 @@ public class SleighInstructionPrototype implements InstructionPrototype {
} }
ParserWalker walker = new ParserWalker(protoContext); ParserWalker walker = new ParserWalker(protoContext);
walker.baseState(); walker.baseState();
PcodeEmitPacked emit = new PcodeEmitPacked(walker, context, fallOffset, override); PcodeEmitPacked emit =
emit.write(PcodeEmitPacked.inst_tag); new PcodeEmitPacked(encoder, walker, context, fallOffset, override);
emit.dumpOffset(emit.getFallOffset());
// Write out the sequence number as a space and an offset
Address instrAddr = emit.getStartAddress();
int spcindex = instrAddr.getAddressSpace().getUnique();
emit.write(spcindex + 0x20);
emit.dumpOffset(instrAddr.getOffset());
emit.emitHeader();
emit.build(walker.getConstructor().getTempl(), -1); emit.build(walker.getConstructor().getTempl(), -1);
emit.resolveRelatives(); emit.resolveRelatives();
if (!isindelayslot) { if (!isindelayslot) {
emit.resolveFinalFallthrough(); emit.resolveFinalFallthrough();
} }
emit.write(PcodeEmitPacked.end_tag); // Terminate the inst_tag emit.emitTail();
return emit.getPackedBytes(); return;
} }
catch (NotYetImplementedException e) { catch (NotYetImplementedException e) {
// unimpl // unimpl
@ -1061,10 +1057,10 @@ public class SleighInstructionPrototype implements InstructionPrototype {
catch (Exception e) { catch (Exception e) {
Msg.error(this, "Pcode error at " + context.getAddress() + ": " + e.getMessage()); Msg.error(this, "Pcode error at " + context.getAddress() + ": " + e.getMessage());
} }
PcodeEmitPacked emit = new PcodeEmitPacked(); encoder.clear();
emit.write(PcodeEmitPacked.unimpl_tag); encoder.openElement(ElementId.ELEM_UNIMPL);
emit.dumpOffset(length); encoder.writeSignedInteger(AttributeId.ATTRIB_OFFSET, length);
return emit.getPackedBytes(); encoder.closeElement(ElementId.ELEM_UNIMPL);
} }
@Override @Override

View File

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,15 +19,32 @@
*/ */
package ghidra.app.plugin.processors.sleigh; package ghidra.app.plugin.processors.sleigh;
import static ghidra.program.model.pcode.AttributeId.*;
import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.pcode.Encoder;
/** /**
*
*
* All the resolved pieces of data needed to build a Varnode * All the resolved pieces of data needed to build a Varnode
*/ */
public class VarnodeData { public class VarnodeData {
public AddressSpace space; public AddressSpace space;
public long offset; public long offset;
public int size; public int size;
/**
* Encode the data to stream as an \<addr> element
* @param encoder is the stream encoder
* @throws IOException for errors writing to the underlying stream
*/
public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_ADDR);
encoder.writeSpace(ATTRIB_SPACE, space);
encoder.writeUnsignedInteger(ATTRIB_OFFSET, offset);
encoder.writeSignedInteger(ATTRIB_SIZE, size);
encoder.closeElement(ELEM_ADDR);
}
} }

View File

@ -37,7 +37,7 @@ public class InjectContext {
public InjectContext() { public InjectContext() {
} }
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_CONTEXT); int el = decoder.openElement(ELEM_CONTEXT);
baseAddr = AddressXML.decode(decoder); baseAddr = AddressXML.decode(decoder);
callAddr = AddressXML.decode(decoder); callAddr = AddressXML.decode(decoder);

View File

@ -27,7 +27,6 @@ import ghidra.app.plugin.processors.sleigh.template.*;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory; import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
import ghidra.util.xml.SpecXmlUtils; import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.*; import ghidra.xml.*;
@ -171,11 +170,7 @@ public class InjectPayloadSleigh implements InjectPayload {
setupParameters(context, walker); setupParameters(context, walker);
emit.build(pcodeTemplate, -1); emit.build(pcodeTemplate, -1);
} }
catch (UnknownInstructionException e) { // Should not be happening in a CallFixup catch (Exception e) { // Should not be happening in a CallFixup
e.printStackTrace();
return;
}
catch (MemoryAccessException e) { // Should not be happening in a CallFixup
e.printStackTrace(); e.printStackTrace();
return; return;
} }
@ -236,8 +231,7 @@ public class InjectPayloadSleigh implements InjectPayload {
public void encode(Encoder encoder) throws IOException { public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_PCODE); encoder.openElement(ELEM_PCODE);
if (type == CALLMECHANISM_TYPE && subType >= 0) { if (type == CALLMECHANISM_TYPE && subType >= 0) {
encoder.writeString(ATTRIB_INJECT, encoder.writeString(ATTRIB_INJECT, (subType == 0) ? "uponentry" : "uponreturn");
(subType == 0) ? "uponentry" : "uponreturn");
} }
if (paramShift != 0) { if (paramShift != 0) {
encoder.writeSignedInteger(ATTRIB_PARAMSHIFT, paramShift); encoder.writeSignedInteger(ATTRIB_PARAMSHIFT, paramShift);

View File

@ -15,13 +15,13 @@
*/ */
package ghidra.program.model.lang; package ghidra.program.model.lang;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.*;
import ghidra.program.model.pcode.PcodeOverride;
import ghidra.program.model.scalar.Scalar; import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.FlowType; import ghidra.program.model.symbol.FlowType;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.RefType;
@ -293,12 +293,14 @@ public interface InstructionPrototype {
public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override); public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override);
/** /**
* Same as getPcode but returns the operations in a packed format to optimize transfer to other processes * Same as getPcode but emits the operations directly to an encoder to optimize transfer to other processes
* @param encoder is the encoder receiving the operations
* @param context the instruction context * @param context the instruction context
* @param override if not null, may indicate that different elements of the pcode generation are overridden * @param override if not null, may indicate that different elements of the pcode generation are overridden
* @return the set of packed bytes encoding the p-code * @throws IOException for errors writing to any stream underlying the encoder
*/ */
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override); public void getPcodePacked(PatchEncoder encoder, InstructionContext context,
PcodeOverride override) throws IOException;
/** /**
* Get an array of PCode operations (micro code) that a particular operand * Get an array of PCode operations (micro code) that a particular operand

View File

@ -15,13 +15,13 @@
*/ */
package ghidra.program.model.lang; package ghidra.program.model.lang;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.*;
import ghidra.program.model.pcode.PcodeOverride;
import ghidra.program.model.scalar.Scalar; import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.FlowType; import ghidra.program.model.symbol.FlowType;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.RefType;
@ -155,8 +155,9 @@ public class InvalidPrototype implements InstructionPrototype, ParserContext {
} }
@Override @Override
public PackedBytes getPcodePacked(InstructionContext context, PcodeOverride override) { public void getPcodePacked(PatchEncoder encoder, InstructionContext context,
return null; PcodeOverride override) throws IOException {
// Does not emit anything
} }
@Override @Override

View File

@ -365,9 +365,9 @@ public class AddressXML {
* Create an address from "space" and "offset" attributes of the current element * Create an address from "space" and "offset" attributes of the current element
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @return the decoded Address * @return the decoded Address
* @throws PcodeXMLException for any problems decoding the stream * @throws DecoderException for any problems decoding the stream
*/ */
public static Address decodeFromAttributes(Decoder decoder) throws PcodeXMLException { public static Address decodeFromAttributes(Decoder decoder) throws DecoderException {
AddressSpace spc = null; AddressSpace spc = null;
long offset = -1; long offset = -1;
for (;;) { for (;;) {
@ -397,10 +397,10 @@ public class AddressXML {
* *
* An empty \<addr> element, with no attributes, results in Address.NO_ADDRESS being returned. * An empty \<addr> element, with no attributes, results in Address.NO_ADDRESS being returned.
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @return Address created from XML info * @return Address created from decode info
* @throws PcodeXMLException for any problems decoding the stream * @throws DecoderException for any problems decoding the stream
*/ */
public static Address decode(Decoder decoder) throws PcodeXMLException { public static Address decode(Decoder decoder) throws DecoderException {
int el = decoder.openElement(); int el = decoder.openElement();
if (el == ELEM_SPACEID.id()) { if (el == ELEM_SPACEID.id()) {
AddressSpace spc = decoder.readSpace(ATTRIB_NAME); AddressSpace spc = decoder.readSpace(ATTRIB_NAME);
@ -431,6 +431,7 @@ public class AddressXML {
} }
decoder.closeElement(el); decoder.closeElement(el);
if (spc == null) { if (spc == null) {
// EXTERNAL_SPACE is currently a placeholder for an unsupported decompiler address space
return Address.NO_ADDRESS; return Address.NO_ADDRESS;
} }
return spc.getAddress(offset); return spc.getAddress(offset);
@ -586,7 +587,9 @@ public class AddressXML {
encoder.openElement(ELEM_ADDR); encoder.openElement(ELEM_ADDR);
encoder.writeSpace(ATTRIB_SPACE, AddressSpace.VARIABLE_SPACE); encoder.writeSpace(ATTRIB_SPACE, AddressSpace.VARIABLE_SPACE);
encoder.writeString(ATTRIB_PIECE1, encodeVarnodePiece(varnodes[0])); encoder.writeString(ATTRIB_PIECE1, encodeVarnodePiece(varnodes[0]));
encoder.writeString(ATTRIB_PIECE2, encodeVarnodePiece(varnodes[1])); if (varnodes.length > 1) {
encoder.writeString(ATTRIB_PIECE2, encodeVarnodePiece(varnodes[1]));
}
if (varnodes.length > 2) { if (varnodes.length > 2) {
encoder.writeString(ATTRIB_PIECE3, encodeVarnodePiece(varnodes[2])); encoder.writeString(ATTRIB_PIECE3, encodeVarnodePiece(varnodes[2]));
} }

View File

@ -15,8 +15,6 @@
*/ */
package ghidra.program.model.pcode; package ghidra.program.model.pcode;
import java.util.HashMap;
/** /**
* An annotation for a data element being transferred to/from a stream * An annotation for a data element being transferred to/from a stream
* *
@ -36,24 +34,24 @@ import java.util.HashMap;
*/ */
public record AttributeId(String name, int id) { public record AttributeId(String name, int id) {
private static HashMap<String, AttributeId> lookupAttributeId = new HashMap<>(); // private static HashMap<String, AttributeId> lookupAttributeId = new HashMap<>();
public AttributeId { // public AttributeId {
// add new attribute to lookup map // // add new attribute to lookup map
if (null != lookupAttributeId.put(name, this)) { // if (null != lookupAttributeId.put(name, this)) {
throw new RuntimeException("Duplicate AttributeId: " + name); // throw new RuntimeException("Duplicate AttributeId: " + name);
} // }
} // }
/** // /**
* Find the id associated with a specific attribute name // * Find the id associated with a specific attribute name
* @param nm the attribute name // * @param nm the attribute name
* @return the associated id // * @return the associated id
*/ // */
public static int find(String nm) { // public static int find(String nm) {
AttributeId res = lookupAttributeId.getOrDefault(nm, ATTRIB_UNKNOWN); // AttributeId res = lookupAttributeId.getOrDefault(nm, ATTRIB_UNKNOWN);
return res.id; // return res.id;
} // }
// Common attributes. Attributes with multiple uses // Common attributes. Attributes with multiple uses
public static final AttributeId ATTRIB_CONTENT = new AttributeId("XMLcontent", 1); public static final AttributeId ATTRIB_CONTENT = new AttributeId("XMLcontent", 1);

View File

@ -49,7 +49,7 @@ public class BlockCondition extends BlockGraph {
} }
@Override @Override
protected void decodeHeader(Decoder decoder) throws PcodeXMLException { protected void decodeHeader(Decoder decoder) throws DecoderException {
super.decodeHeader(decoder); super.decodeHeader(decoder);
String opcodename = decoder.readString(AttributeId.ATTRIB_OPCODE); String opcodename = decoder.readString(AttributeId.ATTRIB_OPCODE);
try { try {

View File

@ -85,7 +85,7 @@ public class BlockCopy extends PcodeBlock {
} }
@Override @Override
protected void decodeHeader(Decoder decoder) throws PcodeXMLException { protected void decodeHeader(Decoder decoder) throws DecoderException {
super.decodeHeader(decoder); super.decodeHeader(decoder);
altindex = (int) decoder.readSignedInteger(AttributeId.ATTRIB_ALTINDEX); altindex = (int) decoder.readSignedInteger(AttributeId.ATTRIB_ALTINDEX);
} }

View File

@ -63,7 +63,7 @@ public class BlockGoto extends BlockGraph {
} }
@Override @Override
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException { protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
super.decodeBody(decoder, resolver); super.decodeBody(decoder, resolver);
int el = decoder.openElement(ELEM_TARGET); int el = decoder.openElement(ELEM_TARGET);
int target = (int) decoder.readSignedInteger(ATTRIB_INDEX); int target = (int) decoder.readSignedInteger(ATTRIB_INDEX);

View File

@ -156,7 +156,7 @@ public class BlockGraph extends PcodeBlock {
} }
@Override @Override
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException { protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
BlockMap newresolver = new BlockMap(resolver); BlockMap newresolver = new BlockMap(resolver);
super.decodeBody(decoder, newresolver); super.decodeBody(decoder, newresolver);
ArrayList<PcodeBlock> tmplist = new ArrayList<>(); ArrayList<PcodeBlock> tmplist = new ArrayList<>();
@ -182,9 +182,9 @@ public class BlockGraph extends PcodeBlock {
/** /**
* Decode all blocks and edges in this container from a stream. * Decode all blocks and edges in this container from a stream.
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @throws PcodeXMLException if there are invalid encodings * @throws DecoderException if there are invalid encodings
*/ */
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
BlockMap resolver = new BlockMap(decoder.getAddressFactory()); BlockMap resolver = new BlockMap(decoder.getAddressFactory());
decode(decoder, resolver); decode(decoder, resolver);
resolver.resolveGotoReferences(); resolver.resolveGotoReferences();

View File

@ -66,7 +66,7 @@ public class BlockIfGoto extends BlockGraph {
} }
@Override @Override
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException { protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
super.decodeBody(decoder, resolver); super.decodeBody(decoder, resolver);
int el = decoder.openElement(ELEM_TARGET); int el = decoder.openElement(ELEM_TARGET);
int target = (int) decoder.readSignedInteger(ATTRIB_INDEX); int target = (int) decoder.readSignedInteger(ATTRIB_INDEX);

View File

@ -59,7 +59,7 @@ public class BlockMultiGoto extends BlockGraph {
} }
@Override @Override
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException { protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
super.decodeBody(decoder, resolver); super.decodeBody(decoder, resolver);
for (;;) { for (;;) {
int el = decoder.peekElement(); int el = decoder.peekElement();

View File

@ -0,0 +1,59 @@
/* ###
* 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.
*/
package ghidra.program.model.pcode;
import java.io.IOException;
import java.io.InputStream;
/**
* An object that can ingest bytes from a stream in preparation for decoding
*/
public interface ByteIngest {
/**
* Clear any previous cached bytes.
*/
public void clear();
/**
* Open the ingester for receiving bytes. This establishes the description of the source of
* the bytes and maximum number of bytes that can be read
* @param max is the maximum number of bytes that can be read
* @param source is the description of the byte source
*/
public void open(int max, String source);
/**
* Ingest bytes from the stream up to (and including) the first 0 byte. This can be called
* multiple times to read in bytes in different chunks.
* An absolute limit is set on the number of bytes that can be ingested via the
* max parameter to a previous call to open(), otherwise an exception is thrown.
* @param inStream is the input stream to read from
* @throws IOException for errors reading from the stream
*/
public void ingestStream(InputStream inStream) throws IOException;
/**
* Formal indicator that ingesting of bytes is complete and processing can begin
* @throws IOException for errors processing the underlying stream
*/
public void endIngest() throws IOException;
/**
* @return true if no bytes have yet been ingested via ingestStream()
*/
public boolean isEmpty();
}

View File

@ -15,8 +15,6 @@
*/ */
package ghidra.program.model.pcode; package ghidra.program.model.pcode;
import java.io.InputStream;
import ghidra.program.model.address.AddressFactory; import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
@ -35,41 +33,27 @@ import ghidra.program.model.address.AddressSpace;
* whose data can be extracted using a read*(AttributeId) call that is passed the special ATTRIB_CONTENT id. * whose data can be extracted using a read*(AttributeId) call that is passed the special ATTRIB_CONTENT id.
* This attribute will not be traversed by getNextAttributeId(). * This attribute will not be traversed by getNextAttributeId().
*/ */
public interface Decoder { public interface Decoder extends ByteIngest {
public AddressFactory getAddressFactory(); public AddressFactory getAddressFactory();
/**
* Clear any current decoding state.
* Allows the same decoder to be reused. Object is ready for new call to ingestStream.
*/
public void clear();
/**
* Prepare to decode a given stream.
* Called once before any decoding. Currently this is assumed to make an internal copy of
* the stream data, i.e. the input stream is cleared before any decoding takes place.
* @param stream is the given input stream to be decode
* @param source is a label describing the source of the input stream
* @throws PcodeXMLException for errors reading the stream
*/
public void ingestStream(InputStream stream, String source) throws PcodeXMLException;
/** /**
* Peek at the next child element of the current parent, without traversing in (opening) it. * Peek at the next child element of the current parent, without traversing in (opening) it.
* The element id is returned, which can be compared to ElementId labels. * The element id is returned, which can be compared to ElementId labels.
* If there are no remaining child elements to traverse, 0 is returned. * If there are no remaining child elements to traverse, 0 is returned.
* @return the element id or 0 * @return the element id or 0
* @throws DecoderException for an unexpected end of stream
*/ */
public int peekElement(); public int peekElement() throws DecoderException;
/** /**
* Open (traverse into) the next child element of the current parent. * Open (traverse into) the next child element of the current parent.
* The child becomes the current parent. * The child becomes the current parent.
* The list of attributes is initialized for use with getNextAttributeId. * The list of attributes is initialized for use with getNextAttributeId.
* @return the id of the child element or 0 if there are no additional children * @return the id of the child element or 0 if there are no additional children
* @throws DecoderException for an unexpected end of stream
*/ */
public int openElement(); public int openElement() throws DecoderException;
/** /**
* Open (traverse into) the next child element, which must be of a specific type * Open (traverse into) the next child element, which must be of a specific type
@ -77,35 +61,36 @@ public interface Decoder {
* getNextAttributeId. The child must match the given element id or an exception is thrown. * getNextAttributeId. The child must match the given element id or an exception is thrown.
* @param elemId is the given element id to match * @param elemId is the given element id to match
* @return the id of the child element * @return the id of the child element
* @throws PcodeXMLException if the expected element is not the next element * @throws DecoderException if the expected element is not the next element
*/ */
public int openElement(ElementId elemId) throws PcodeXMLException; public int openElement(ElementId elemId) throws DecoderException;
/** /**
* Close the current element * Close the current element
* The data for the current element is considered fully processed. If the element has additional * The data for the current element is considered fully processed. If the element has additional
* children, an exception is thrown. The stream must indicate the end of the element in some way. * children, an exception is thrown. The stream must indicate the end of the element in some way.
* @param id is the id of the element to close (which must be the current element) * @param id is the id of the element to close (which must be the current element)
* @throws PcodeXMLException if not at end of expected element * @throws DecoderException if not at end of expected element
*/ */
public void closeElement(int id) throws PcodeXMLException; public void closeElement(int id) throws DecoderException;
/** /**
* Close the current element, skipping any child elements that have not yet been parsed. * Close the current element, skipping any child elements that have not yet been parsed.
* This closes the given element, which must be current. If there are child elements that have * This closes the given element, which must be current. If there are child elements that have
* not been parsed, this is not considered an error, and they are skipped over in the parse. * not been parsed, this is not considered an error, and they are skipped over in the parse.
* @param id is the id of the element to close (which must be the current element) * @param id is the id of the element to close (which must be the current element)
* @throws PcodeXMLException if the indicated element is not the current element * @throws DecoderException if the indicated element is not the current element
*/ */
public void closeElementSkipping(int id) throws PcodeXMLException; public void closeElementSkipping(int id) throws DecoderException;
/** /**
* Get the next attribute id for the current element * Get the next attribute id for the current element
* Attributes are automatically set up for traversal using this method, when the element is * Attributes are automatically set up for traversal using this method, when the element is
* opened. If all attributes have been traversed (or there are no attributes), 0 is returned. * opened. If all attributes have been traversed (or there are no attributes), 0 is returned.
* @return the id of the next attribute or 0 * @return the id of the next attribute or 0
* @throws DecoderException for unexpected end of stream
*/ */
public int getNextAttributeId(); public int getNextAttributeId() throws DecoderException;
/** /**
* Reset attribute traversal for the current element * Reset attribute traversal for the current element
@ -119,9 +104,9 @@ public interface Decoder {
* The last attribute, as returned by getNextAttributeId, is treated as a boolean, and its * The last attribute, as returned by getNextAttributeId, is treated as a boolean, and its
* value is returned. * value is returned.
* @return the boolean value associated with the current attribute. * @return the boolean value associated with the current attribute.
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public boolean readBool() throws PcodeXMLException; public boolean readBool() throws DecoderException;
/** /**
* Find and parse a specific attribute in the current element as a boolean value * Find and parse a specific attribute in the current element as a boolean value
@ -131,18 +116,18 @@ public interface Decoder {
* Parsing via getNextAttributeId is reset. * Parsing via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match * @param attribId is the specific attribute id to match
* @return the boolean value * @return the boolean value
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public boolean readBool(AttributeId attribId) throws PcodeXMLException; public boolean readBool(AttributeId attribId) throws DecoderException;
/** /**
* Parse the current attribute as a signed integer value * Parse the current attribute as a signed integer value
* The last attribute, as returned by getNextAttributeId, is treated as a signed integer, * The last attribute, as returned by getNextAttributeId, is treated as a signed integer,
* and its value is returned. * and its value is returned.
* @return the signed integer value associated with the current attribute. * @return the signed integer value associated with the current attribute.
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public long readSignedInteger() throws PcodeXMLException; public long readSignedInteger() throws DecoderException;
/** /**
* Find and parse a specific attribute in the current element as a signed integer * Find and parse a specific attribute in the current element as a signed integer
@ -152,18 +137,18 @@ public interface Decoder {
* Parsing via getNextAttributeId is reset. * Parsing via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match * @param attribId is the specific attribute id to match
* @return the signed integer value * @return the signed integer value
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public long readSignedInteger(AttributeId attribId) throws PcodeXMLException; public long readSignedInteger(AttributeId attribId) throws DecoderException;
/** /**
* Parse the current attribute as an unsigned integer value * Parse the current attribute as an unsigned integer value
* The last attribute, as returned by getNextAttributeId, is treated as an unsigned integer, * The last attribute, as returned by getNextAttributeId, is treated as an unsigned integer,
* and its value is returned. * and its value is returned.
* @return the unsigned integer value associated with the current attribute. * @return the unsigned integer value associated with the current attribute.
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public long readUnsignedInteger() throws PcodeXMLException; public long readUnsignedInteger() throws DecoderException;
/** /**
* Find and parse a specific attribute in the current element as an unsigned integer * Find and parse a specific attribute in the current element as an unsigned integer
@ -173,17 +158,17 @@ public interface Decoder {
* Parsing via getNextAttributeId is reset. * Parsing via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match * @param attribId is the specific attribute id to match
* @return the unsigned integer value * @return the unsigned integer value
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public long readUnsignedInteger(AttributeId attribId) throws PcodeXMLException; public long readUnsignedInteger(AttributeId attribId) throws DecoderException;
/** /**
* Parse the current attribute as a string * Parse the current attribute as a string
* The last attribute, as returned by getNextAttributeId, is returned as a string. * The last attribute, as returned by getNextAttributeId, is returned as a string.
* @return the string associated with the current attribute. * @return the string associated with the current attribute.
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public String readString() throws PcodeXMLException; public String readString() throws DecoderException;
/** /**
* Find the specific attribute in the current element and return it as a string * Find the specific attribute in the current element and return it as a string
@ -192,17 +177,17 @@ public interface Decoder {
* and exception is thrown. Parse via getNextAttributeId is reset. * and exception is thrown. Parse via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match * @param attribId is the specific attribute id to match
* @return the string associated with the attribute * @return the string associated with the attribute
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public String readString(AttributeId attribId) throws PcodeXMLException; public String readString(AttributeId attribId) throws DecoderException;
/** /**
* Parse the current attribute as an address space * Parse the current attribute as an address space
* The last attribute, as returned by getNextAttributeId, is returned as an address space. * The last attribute, as returned by getNextAttributeId, is returned as an address space.
* @return the address space associated with the current attribute. * @return the address space associated with the current attribute.
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public AddressSpace readSpace() throws PcodeXMLException; public AddressSpace readSpace() throws DecoderException;
/** /**
* Find the specific attribute in the current element and return it as an address space * Find the specific attribute in the current element and return it as an address space
@ -211,16 +196,16 @@ public interface Decoder {
* exception is thrown. Parse via getNextAttributeId is reset. * exception is thrown. Parse via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match * @param attribId is the specific attribute id to match
* @return the address space associated with the attribute * @return the address space associated with the attribute
* @throws PcodeXMLException if the expected value is not present * @throws DecoderException if the expected value is not present
*/ */
public AddressSpace readSpace(AttributeId attribId) throws PcodeXMLException; public AddressSpace readSpace(AttributeId attribId) throws DecoderException;
/** /**
* Skip parsing of the next element * Skip parsing of the next element
* The element skipped is the one that would be opened by the next call to openElement. * The element skipped is the one that would be opened by the next call to openElement.
* @throws PcodeXMLException if there is no new element * @throws DecoderException if there is no new element
*/ */
public default void skipElement() throws PcodeXMLException { public default void skipElement() throws DecoderException {
int elemId = openElement(); int elemId = openElement();
closeElementSkipping(elemId); closeElementSkipping(elemId);
} }

View File

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,15 +16,14 @@
package ghidra.program.model.pcode; package ghidra.program.model.pcode;
/** /**
* * Exception thrown for errors decoding decompiler objects from stream
*
* Exception thrown when pcode cannot be restored from XML.
*/ */
public class PcodeXMLException extends PcodeException { public class DecoderException extends PcodeException {
public PcodeXMLException(String msg) { public DecoderException(String msg) {
super("XML comms: "+msg); super("Decoding error: " + msg);
} }
public PcodeXMLException(String msg, Throwable cause) {
super("XML comms: "+msg, cause); public DecoderException(String msg, Throwable cause) {
super("Decoding error: " + msg, cause);
} }
} }

View File

@ -65,7 +65,7 @@ public class DynamicEntry extends SymbolEntry {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
int addrel = decoder.openElement(ELEM_HASH); int addrel = decoder.openElement(ELEM_HASH);
hash = decoder.readUnsignedInteger(ATTRIB_VAL); hash = decoder.readUnsignedInteger(ATTRIB_VAL);
decoder.closeElement(addrel); decoder.closeElement(addrel);

View File

@ -15,8 +15,6 @@
*/ */
package ghidra.program.model.pcode; package ghidra.program.model.pcode;
import java.util.HashMap;
/** /**
* An annotation for a specific collection of hierarchical data * An annotation for a specific collection of hierarchical data
* *
@ -28,28 +26,28 @@ import java.util.HashMap;
* as an attribute. * as an attribute.
* *
* @param name unique element name * @param name unique element name
* @param id unqiue element ID * @param id unique element ID
*/ */
public record ElementId(String name, int id) { public record ElementId(String name, int id) {
private static HashMap<String, ElementId> lookupElementId = new HashMap<>(); // private static HashMap<String, ElementId> lookupElementId = new HashMap<>();
public ElementId { // public ElementId {
// add new element to lookup map // // add new element to lookup map
if (null != lookupElementId.put(name, this)) { // if (null != lookupElementId.put(name, this)) {
throw new RuntimeException("Duplicate ElementId instance: " + name); // throw new RuntimeException("Duplicate ElementId instance: " + name);
} // }
} // }
/** // /**
* Find the id associated with a specific element name // * Find the id associated with a specific element name
* @param nm the element name // * @param nm the element name
* @return the associated id // * @return the associated id
*/ // */
public static int find(String nm) { // public static int find(String nm) {
ElementId res = lookupElementId.getOrDefault(nm, ELEM_UNKNOWN); // ElementId res = lookupElementId.getOrDefault(nm, ELEM_UNKNOWN);
return res.id; // return res.id;
} // }
public static final ElementId ELEM_DATA = new ElementId("data", 1); public static final ElementId ELEM_DATA = new ElementId("data", 1);
public static final ElementId ELEM_INPUT = new ElementId("input", 2); public static final ElementId ELEM_INPUT = new ElementId("input", 2);
@ -364,5 +362,64 @@ public record ElementId(String name, int id) {
// raw_arch // raw_arch
// public static final ElementId ELEM_RAW_SAVEFILE = new ElementId("raw_savefile", 237); // public static final ElementId ELEM_RAW_SAVEFILE = new ElementId("raw_savefile", 237);
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 251); // ghidra_arch
public static final int COMMAND_ISNAMEUSED = 239;
public static final ElementId ELEM_COMMAND_ISNAMEUSED =
new ElementId("command_isnameused", COMMAND_ISNAMEUSED);
public static final int COMMAND_GETBYTES = 240;
public static final ElementId ELEM_COMMAND_GETBYTES =
new ElementId("command_getbytes", COMMAND_GETBYTES);
public static final int COMMAND_GETCALLFIXUP = 241;
public static final ElementId ELEM_COMMAND_GETCALLFIXUP =
new ElementId("command_getcallfixup", COMMAND_GETCALLFIXUP);
public static final int COMMAND_GETCALLMECH = 242;
public static final ElementId ELEM_COMMAND_GETCALLMECH =
new ElementId("command_getcallmech", COMMAND_GETCALLMECH);
public static final int COMMAND_GETCALLOTHERFIXUP = 243;
public static final ElementId ELEM_COMMAND_GETCALLOTHERFIXUP =
new ElementId("command_getcallotherfixup", COMMAND_GETCALLOTHERFIXUP);
public static final int COMMAND_GETCODELABEL = 244;
public static final ElementId ELEM_COMMAND_GETCODELABEL =
new ElementId("command_getcodelabel", COMMAND_GETCODELABEL);
public static final int COMMAND_GETCOMMENTS = 245;
public static final ElementId ELEM_COMMAND_GETCOMMENTS =
new ElementId("command_getcomments", COMMAND_GETCOMMENTS);
public static final int COMMAND_GETCPOOLREF = 246;
public static final ElementId ELEM_COMMAND_GETCPOOLREF =
new ElementId("command_getcpoolref", COMMAND_GETCPOOLREF);
public static final int COMMAND_GETDATATYPE = 247;
public static final ElementId ELEM_COMMAND_GETDATATYPE =
new ElementId("command_getdatatype", COMMAND_GETDATATYPE);
public static final int COMMAND_GETEXTERNALREF = 248;
public static final ElementId ELEM_COMMAND_GETEXTERNALREF =
new ElementId("command_getexternalref", COMMAND_GETEXTERNALREF);
public static final int COMMAND_GETMAPPEDSYMBOLS = 249;
public static final ElementId ELEM_COMMAND_GETMAPPEDSYMBOLS =
new ElementId("command_getmappedsymbols", COMMAND_GETMAPPEDSYMBOLS);
public static final int COMMAND_GETNAMESPACEPATH = 250;
public static final ElementId ELEM_COMMAND_GETNAMESPACEPATH =
new ElementId("command_getnamespacepath", COMMAND_GETNAMESPACEPATH);
public static final int COMMAND_GETPCODE = 251;
public static final ElementId ELEM_COMMAND_GETPCODE =
new ElementId("command_getpcode", COMMAND_GETPCODE);
public static final int COMMAND_GETPCODEEXECUTABLE = 252;
public static final ElementId ELEM_COMMAND_GETPCODEEXECUTABLE =
new ElementId("command_getpcodeexecutable", COMMAND_GETPCODEEXECUTABLE);
public static final int COMMAND_GETREGISTER = 253;
public static final ElementId ELEM_COMMAND_GETREGISTER =
new ElementId("command_getregister", COMMAND_GETREGISTER);
public static final int COMMAND_GETREGISTERNAME = 254;
public static final ElementId ELEM_COMMAND_GETREGISTERNAME =
new ElementId("command_getregistername", COMMAND_GETREGISTERNAME);
public static final int COMMAND_GETSTRINGDATA = 255;
public static final ElementId ELEM_COMMAND_GETSTRINGDATA =
new ElementId("command_getstring", COMMAND_GETSTRINGDATA);
public static final int COMMAND_GETTRACKEDREGISTERS = 256;
public static final ElementId ELEM_COMMAND_GETTRACKEDREGISTERS =
new ElementId("command_gettrackedregisters", COMMAND_GETTRACKEDREGISTERS);
public static final int COMMAND_GETUSEROPNAME = 257;
public static final ElementId ELEM_COMMAND_GETUSEROPNAME =
new ElementId("command_getuseropname", COMMAND_GETUSEROPNAME);
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 270);
} }

View File

@ -16,6 +16,7 @@
package ghidra.program.model.pcode; package ghidra.program.model.pcode;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
@ -102,8 +103,15 @@ public interface Encoder {
void writeSpace(AttributeId attribId, AddressSpace spc) throws IOException; void writeSpace(AttributeId attribId, AddressSpace spc) throws IOException;
/** /**
* Return anything written to the encoder (since the last clear) as a byte array. * Dump all the accumulated bytes in this encoder to the stream.
* @return the array of bytes * @param stream is the output stream
* @throws IOException for errors during the write operation
*/ */
byte[] getBytes(); public void writeTo(OutputStream stream) throws IOException;
/**
* The encoder is considered empty if the writeTo() method would output zero bytes
* @return true if there are no bytes in the encoder
*/
public boolean isEmpty();
} }

View File

@ -68,7 +68,7 @@ public class EquateSymbol extends HighSymbol {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
int symel = decoder.openElement(ELEM_EQUATESYMBOL); int symel = decoder.openElement(ELEM_EQUATESYMBOL);
decodeHeader(decoder); decodeHeader(decoder);
type = DataType.DEFAULT; type = DataType.DEFAULT;

View File

@ -25,7 +25,6 @@ import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.SourceType;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.xml.SpecXmlUtils;
/** /**
* *
@ -418,24 +417,23 @@ public class FunctionPrototype {
* Decode the function prototype from a {@code <prototype>} element in the stream. * Decode the function prototype from a {@code <prototype>} element in the stream.
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @param dtmanage is the DataTypeManager used to parse data-type tags * @param dtmanage is the DataTypeManager used to parse data-type tags
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
public void decodePrototype(Decoder decoder, PcodeDataTypeManager dtmanage) public void decodePrototype(Decoder decoder, PcodeDataTypeManager dtmanage)
throws PcodeXMLException { throws DecoderException {
int node = decoder.openElement(ELEM_PROTOTYPE); int node = decoder.openElement(ELEM_PROTOTYPE);
modelname = decoder.readString(ATTRIB_MODEL); modelname = decoder.readString(ATTRIB_MODEL);
PrototypeModel protoModel = PrototypeModel protoModel =
dtmanage.getProgram().getCompilerSpec().getCallingConvention(modelname); dtmanage.getProgram().getCompilerSpec().getCallingConvention(modelname);
if (protoModel == null) { if (protoModel == null) {
throw new PcodeXMLException("Bad prototype model name: " + modelname); throw new DecoderException("Bad prototype model name: " + modelname);
} }
hasThis = protoModel.hasThisPointer(); hasThis = protoModel.hasThisPointer();
String val = decoder.readString(ATTRIB_EXTRAPOP); try {
if (val.equals("unknown")) { extrapop = (int) decoder.readSignedInteger(ATTRIB_EXTRAPOP);
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
} }
else { catch (DecoderException e) {
extrapop = SpecXmlUtils.decodeInt(val); extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
} }
modellock = false; modellock = false;
dotdotdot = false; dotdotdot = false;

View File

@ -148,7 +148,7 @@ public class HighCodeSymbol extends HighSymbol {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
super.decode(decoder); super.decode(decoder);
symbol = null; symbol = null;
} }

View File

@ -86,7 +86,7 @@ public class HighConstant extends HighVariable {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
//int el = decoder.openElement(ElementId.ELEM_HIGH); //int el = decoder.openElement(ElementId.ELEM_HIGH);
long symref = 0; long symref = 0;
for (;;) { for (;;) {

View File

@ -218,7 +218,7 @@ public class HighFunction extends PcodeSyntaxTree {
return super.newVarnode(sz, addr, id); return super.newVarnode(sz, addr, id);
} }
private void decodeHigh(Decoder decoder) throws PcodeXMLException { private void decodeHigh(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_HIGH); int el = decoder.openElement(ELEM_HIGH);
String classstring = decoder.readString(ATTRIB_CLASS); String classstring = decoder.readString(ATTRIB_CLASS);
HighVariable var; HighVariable var;
@ -239,13 +239,13 @@ public class HighFunction extends PcodeSyntaxTree {
var = new HighConstant(this); var = new HighConstant(this);
break; break;
default: default:
throw new PcodeXMLException("Unknown HighVariable class string: " + classstring); throw new DecoderException("Unknown HighVariable class string: " + classstring);
} }
var.decode(decoder); var.decode(decoder);
decoder.closeElement(el); decoder.closeElement(el);
} }
private void decodeHighlist(Decoder decoder) throws PcodeXMLException { private void decodeHighlist(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_HIGHLIST); int el = decoder.openElement(ELEM_HIGHLIST);
while (decoder.peekElement() != 0) { while (decoder.peekElement() != 0) {
decodeHigh(decoder); decodeHigh(decoder);
@ -254,11 +254,11 @@ public class HighFunction extends PcodeSyntaxTree {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
int start = decoder.openElement(ELEM_FUNCTION); int start = decoder.openElement(ELEM_FUNCTION);
String name = decoder.readString(ATTRIB_NAME); String name = decoder.readString(ATTRIB_NAME);
if (!func.getName().equals(name)) { if (!func.getName().equals(name)) {
throw new PcodeXMLException("Function name mismatch: " + func.getName() + " + " + name); throw new DecoderException("Function name mismatch: " + func.getName() + " + " + name);
} }
for (;;) { for (;;) {
int subel = decoder.peekElement(); int subel = decoder.peekElement();
@ -269,7 +269,7 @@ public class HighFunction extends PcodeSyntaxTree {
Address addr = AddressXML.decode(decoder); Address addr = AddressXML.decode(decoder);
addr = func.getEntryPoint().getAddressSpace().getOverlayAddress(addr); addr = func.getEntryPoint().getAddressSpace().getOverlayAddress(addr);
if (!func.getEntryPoint().equals(addr)) { if (!func.getEntryPoint().equals(addr)) {
throw new PcodeXMLException("Mismatched address in function tag"); throw new DecoderException("Mismatched address in function tag");
} }
} }
else if (subel == ELEM_PROTOTYPE.id()) { else if (subel == ELEM_PROTOTYPE.id()) {
@ -298,7 +298,7 @@ public class HighFunction extends PcodeSyntaxTree {
decoder.skipElement(); decoder.skipElement();
} }
else { else {
throw new PcodeXMLException("Unknown element in function"); throw new DecoderException("Unknown element in function");
} }
} }
decoder.closeElement(start); decoder.closeElement(start);
@ -308,9 +308,9 @@ public class HighFunction extends PcodeSyntaxTree {
* Decode the Jump Table list for this function from the stream * Decode the Jump Table list for this function from the stream
* *
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
private void decodeJumpTableList(Decoder decoder) throws PcodeXMLException { private void decodeJumpTableList(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_JUMPTABLELIST); int el = decoder.openElement(ELEM_JUMPTABLELIST);
while (decoder.peekElement() != 0) { while (decoder.peekElement() != 0) {
JumpTable table = new JumpTable(func.getEntryPoint().getAddressSpace()); JumpTable table = new JumpTable(func.getEntryPoint().getAddressSpace());
@ -422,7 +422,7 @@ public class HighFunction extends PcodeSyntaxTree {
return reslocal; return reslocal;
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
throw new PcodeXMLException("Bad storage node", e); throw new DecoderException("Bad storage node", e);
} }
} }

View File

@ -47,7 +47,7 @@ public class HighGlobal extends HighVariable {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
// int el = decoder.openElement(ElementId.ELEM_HIGH); // int el = decoder.openElement(ElementId.ELEM_HIGH);
long symref = 0; long symref = 0;
offset = -1; offset = -1;
@ -90,7 +90,7 @@ public class HighGlobal extends HighVariable {
} }
symbol = globalMap.newSymbol(symref, addr, symbolType, symbolSize); symbol = globalMap.newSymbol(symref, addr, symbolType, symbolSize);
if (symbol == null) { if (symbol == null) {
throw new PcodeXMLException("Bad global storage: " + addr.toString()); throw new DecoderException("Bad global storage: " + addr.toString());
} }
} }
} }

View File

@ -50,7 +50,7 @@ public class HighLocal extends HighVariable {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
//int el = decoder.openElement(ElementId.ELEM_HIGH); //int el = decoder.openElement(ElementId.ELEM_HIGH);
long symref = decoder.readUnsignedInteger(AttributeId.ATTRIB_SYMREF); long symref = decoder.readUnsignedInteger(AttributeId.ATTRIB_SYMREF);
offset = -1; offset = -1;
@ -60,14 +60,14 @@ public class HighLocal extends HighVariable {
break; break;
} }
if (attribId == AttributeId.ATTRIB_OFFSET.id()) { if (attribId == AttributeId.ATTRIB_OFFSET.id()) {
offset = (int) decoder.readUnsignedInteger(); offset = (int) decoder.readSignedInteger();
break; break;
} }
} }
decodeInstances(decoder); decodeInstances(decoder);
symbol = function.getLocalSymbolMap().getSymbol(symref); symbol = function.getLocalSymbolMap().getSymbol(symref);
if (symbol == null) { if (symbol == null) {
throw new PcodeXMLException("HighLocal is missing symbol"); throw new DecoderException("HighLocal is missing symbol");
} }
if (offset < 0) { if (offset < 0) {
name = symbol.getName(); name = symbol.getName();

View File

@ -63,7 +63,7 @@ public class HighOther extends HighVariable {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
// int el = decoder.openElement(ElementId.ELEM_HIGH); // int el = decoder.openElement(ElementId.ELEM_HIGH);
long symref = 0; long symref = 0;
offset = -1; offset = -1;

View File

@ -54,7 +54,7 @@ public class HighParam extends HighLocal {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
super.decode(decoder); super.decode(decoder);
HighSymbol sym = getSymbol(); HighSymbol sym = getSymbol();
slot = sym.getCategoryIndex(); slot = sym.getCategoryIndex();

View File

@ -134,11 +134,11 @@ public class HighParamID extends PcodeSyntaxTree {
* @see ghidra.program.model.pcode.PcodeSyntaxTree#readXML(org.jdom.Element) * @see ghidra.program.model.pcode.PcodeSyntaxTree#readXML(org.jdom.Element)
*/ */
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
int start = decoder.openElement(ELEM_PARAMMEASURES); int start = decoder.openElement(ELEM_PARAMMEASURES);
functionname = decoder.readString(ATTRIB_NAME); functionname = decoder.readString(ATTRIB_NAME);
if (!func.getName().equals(functionname)) { if (!func.getName().equals(functionname)) {
throw new PcodeXMLException( throw new DecoderException(
"Function name mismatch: " + func.getName() + " + " + functionname); "Function name mismatch: " + func.getName() + " + " + functionname);
} }
for (;;) { for (;;) {
@ -151,7 +151,7 @@ public class HighParamID extends PcodeSyntaxTree {
functionaddress = functionaddress =
func.getEntryPoint().getAddressSpace().getOverlayAddress(functionaddress); func.getEntryPoint().getAddressSpace().getOverlayAddress(functionaddress);
if (!func.getEntryPoint().equals(functionaddress)) { if (!func.getEntryPoint().equals(functionaddress)) {
throw new PcodeXMLException("Mismatched address in function tag"); throw new DecoderException("Mismatched address in function tag");
} }
} }
else if (subel == ELEM_PROTO.id()) { else if (subel == ELEM_PROTO.id()) {
@ -173,7 +173,7 @@ public class HighParamID extends PcodeSyntaxTree {
decodeParamMeasure(decoder, outputlist); decodeParamMeasure(decoder, outputlist);
} }
else { else {
throw new PcodeXMLException("Unknown tag in parammeasures"); throw new DecoderException("Unknown tag in parammeasures");
} }
} }
decoder.closeElement(start); decoder.closeElement(start);
@ -183,10 +183,10 @@ public class HighParamID extends PcodeSyntaxTree {
* Decode the inputs or outputs list for this function from a stream. * Decode the inputs or outputs list for this function from a stream.
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @param pmlist is populated with the resulting list * @param pmlist is populated with the resulting list
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
private void decodeParamMeasure(Decoder decoder, List<ParamMeasure> pmlist) private void decodeParamMeasure(Decoder decoder, List<ParamMeasure> pmlist)
throws PcodeXMLException { throws DecoderException {
int el = decoder.openElement(); int el = decoder.openElement();
ParamMeasure pm = new ParamMeasure(); ParamMeasure pm = new ParamMeasure();
pm.decode(decoder, this); pm.decode(decoder, this);

View File

@ -392,7 +392,7 @@ public class HighSymbol {
} }
encoder.writeSignedInteger(ATTRIB_CAT, category); encoder.writeSignedInteger(ATTRIB_CAT, category);
if (categoryIndex >= 0) { if (categoryIndex >= 0) {
encoder.writeSignedInteger(ATTRIB_INDEX, categoryIndex); encoder.writeUnsignedInteger(ATTRIB_INDEX, categoryIndex);
} }
} }
@ -408,7 +408,7 @@ public class HighSymbol {
encoder.closeElement(ELEM_SYMBOL); encoder.closeElement(ELEM_SYMBOL);
} }
protected void decodeHeader(Decoder decoder) throws PcodeXMLException { protected void decodeHeader(Decoder decoder) throws DecoderException {
name = null; name = null;
id = 0; id = 0;
typelock = false; typelock = false;
@ -449,16 +449,16 @@ public class HighSymbol {
} }
} }
if (id == 0) { if (id == 0) {
throw new PcodeXMLException("missing unique symbol id"); throw new DecoderException("missing unique symbol id");
} }
} }
/** /**
* Decode this symbol object and its associated mappings from the stream. * Decode this symbol object and its associated mappings from the stream.
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
int symel = decoder.openElement(ELEM_SYMBOL); int symel = decoder.openElement(ELEM_SYMBOL);
decodeHeader(decoder); decodeHeader(decoder);
type = dtmanage.decodeDataType(decoder); type = dtmanage.decodeDataType(decoder);
@ -498,7 +498,7 @@ public class HighSymbol {
entryList[0] = new MappedEntry(this, newStorage, entry.getPCAdress()); entryList[0] = new MappedEntry(this, newStorage, entry.getPCAdress());
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
throw new PcodeXMLException("Unable to parse auto-parameter"); throw new DecoderException("Unable to parse auto-parameter");
} }
} }
} }
@ -511,10 +511,10 @@ public class HighSymbol {
* @param isGlobal is true if this symbol is being read into a global scope * @param isGlobal is true if this symbol is being read into a global scope
* @param high is the function model that will own the new symbol * @param high is the function model that will own the new symbol
* @return the new symbol * @return the new symbol
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
public static HighSymbol decodeMapSym(Decoder decoder, boolean isGlobal, HighFunction high) public static HighSymbol decodeMapSym(Decoder decoder, boolean isGlobal, HighFunction high)
throws PcodeXMLException { throws DecoderException {
HighSymbol res = null; HighSymbol res = null;
int mapel = decoder.openElement(ELEM_MAPSYM); int mapel = decoder.openElement(ELEM_MAPSYM);
int symel = decoder.peekElement(); int symel = decoder.peekElement();

View File

@ -141,13 +141,13 @@ public abstract class HighVariable {
* Decode the data-type and the Varnode instances of this HighVariable. * Decode the data-type and the Varnode instances of this HighVariable.
* The "representative" Varnode is also populated. * The "representative" Varnode is also populated.
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
protected void decodeInstances(Decoder decoder) throws PcodeXMLException { protected void decodeInstances(Decoder decoder) throws DecoderException {
int repref = (int) decoder.readUnsignedInteger(AttributeId.ATTRIB_REPREF); int repref = (int) decoder.readUnsignedInteger(AttributeId.ATTRIB_REPREF);
Varnode rep = function.getRef(repref); Varnode rep = function.getRef(repref);
if (rep == null) { if (rep == null) {
throw new PcodeXMLException("Undefined varnode reference"); throw new DecoderException("Undefined varnode reference");
} }
type = null; type = null;
@ -188,7 +188,7 @@ public abstract class HighVariable {
/** /**
* Decode this HighVariable from a {@code <high>} element in the stream * Decode this HighVariable from a {@code <high>} element in the stream
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
public abstract void decode(Decoder decoder) throws PcodeXMLException; public abstract void decode(Decoder decoder) throws DecoderException;
} }

View File

@ -79,7 +79,7 @@ public class JumpTable {
return num; return num;
} }
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_LOADTABLE); int el = decoder.openElement(ELEM_LOADTABLE);
size = (int) decoder.readSignedInteger(ATTRIB_SIZE); size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
num = (int) decoder.readSignedInteger(ATTRIB_NUM); num = (int) decoder.readSignedInteger(ATTRIB_NUM);
@ -160,9 +160,9 @@ public class JumpTable {
/** /**
* Decode a JumpTable object from the stream. * Decode a JumpTable object from the stream.
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_JUMPTABLE); int el = decoder.openElement(ELEM_JUMPTABLE);
if (decoder.peekElement() == 0) { // Empty jumptable if (decoder.peekElement() == 0) { // Empty jumptable
decoder.closeElement(el); decoder.closeElement(el);

View File

@ -0,0 +1,154 @@
/* ###
* 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.
*/
package ghidra.program.model.pcode;
import java.io.IOException;
import java.io.InputStream;
public class LinkedByteBuffer {
public static class Position {
public ArrayIter seqIter;
public byte[] array;
public int current;
public void copy(Position pos) {
seqIter = pos.seqIter;
array = pos.array;
current = pos.current;
}
public final byte getByte() {
return array[current];
}
public final byte getBytePlus1() throws DecoderException {
int plus1 = current + 1;
if (plus1 == array.length) {
ArrayIter iter = seqIter.next;
if (iter == null) {
throw new DecoderException("Unexpected end of stream");
}
return iter.array[0];
}
return array[plus1];
}
public final byte getNextByte() throws DecoderException {
byte res = array[current];
current += 1;
if (current != array.length) {
return res;
}
seqIter = seqIter.next;
if (seqIter == null) {
throw new DecoderException("Unexpected end of stream");
}
array = seqIter.array;
current = 0;
return res;
}
public final void advancePosition(int skip) throws DecoderException {
while (array.length - current <= skip) {
skip -= (array.length - current);
seqIter = seqIter.next;
if (seqIter == null) {
throw new DecoderException("Unexpected end of stream");
}
array = seqIter.array;
current = 0;
}
current += skip;
}
}
public static class ArrayIter {
public ArrayIter next;
public byte[] array;
}
public final static int BUFFER_SIZE = 1024;
private ArrayIter initialBuffer;
private int byteCount;
private int maxCount;
private ArrayIter currentBuffer;
private int currentPos;
private String source;
public LinkedByteBuffer(int max, String src) {
initialBuffer = new ArrayIter();
currentBuffer = initialBuffer;
byteCount = 0;
currentPos = 0;
maxCount = max;
initialBuffer.array = new byte[BUFFER_SIZE];
initialBuffer.next = null;
source = src;
}
public void ingestStream(InputStream stream) throws IOException {
int tok = stream.read();
if (tok <= 0) {
return;
}
for (;;) {
if (byteCount > maxCount) {
throw new IOException("Response buffer size exceded for: " + source);
}
do {
if (currentPos == BUFFER_SIZE) {
break;
}
currentBuffer.array[currentPos++] = (byte) tok;
tok = stream.read();
}
while (tok > 0);
byteCount += currentPos;
if (tok <= 0) {
return; // Reached terminator or end of stream, ingest is finished
}
// Set up next buffer
currentBuffer.next = new ArrayIter();
currentBuffer = currentBuffer.next;
currentBuffer.array = new byte[BUFFER_SIZE];
currentPos = 0;
}
}
/**
* Add a particular byte to the buffer
* @param val is the byte value to add
*/
public void pad(int val) {
if (currentPos == BUFFER_SIZE) {
byteCount += currentPos;
currentBuffer.next = new ArrayIter();
currentBuffer = currentBuffer.next;
currentBuffer.array = new byte[1];
currentPos = 0;
}
currentBuffer.array[currentPos++] = (byte) val;
}
public void getStartPosition(Position position) {
position.array = initialBuffer.array;
position.current = 0;
position.seqIter = initialBuffer;
}
}

View File

@ -265,9 +265,9 @@ public class LocalSymbolMap {
* Decode a &lt;mapsym&gt; element from the stream. * Decode a &lt;mapsym&gt; element from the stream.
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @return the reconstructed HighSymbol * @return the reconstructed HighSymbol
* @throws PcodeXMLException for problems sub tags * @throws DecoderException for problems sub tags
*/ */
private HighSymbol decodeSymbol(Decoder decoder) throws PcodeXMLException { private HighSymbol decodeSymbol(Decoder decoder) throws DecoderException {
HighSymbol res = HighSymbol.decodeMapSym(decoder, false, func); HighSymbol res = HighSymbol.decodeMapSym(decoder, false, func);
insertSymbol(res); insertSymbol(res);
return res; return res;
@ -277,9 +277,9 @@ public class LocalSymbolMap {
* Decode a local symbol scope from the stream * Decode a local symbol scope from the stream
* *
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
public void decodeScope(Decoder decoder) throws PcodeXMLException { public void decodeScope(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_LOCALDB); int el = decoder.openElement(ELEM_LOCALDB);
localSpace = decoder.readSpace(ATTRIB_MAIN); localSpace = decoder.readSpace(ATTRIB_MAIN);
int scopeel = decoder.openElement(ELEM_SCOPE); int scopeel = decoder.openElement(ELEM_SCOPE);
@ -308,9 +308,9 @@ public class LocalSymbolMap {
/** /**
* Add mapped symbols to this LocalVariableMap, by decoding the &lt;symbollist&gt; and &lt;mapsym&gt; elements * Add mapped symbols to this LocalVariableMap, by decoding the &lt;symbollist&gt; and &lt;mapsym&gt; elements
* @param decoder is the stream decoder * @param decoder is the stream decoder
* @throws PcodeXMLException for invalid encodings * @throws DecoderException for invalid encodings
*/ */
public void decodeSymbolList(Decoder decoder) throws PcodeXMLException { public void decodeSymbolList(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_SYMBOLLIST); int el = decoder.openElement(ELEM_SYMBOLLIST);
ArrayList<HighSymbol> parms = new ArrayList<>(); ArrayList<HighSymbol> parms = new ArrayList<>();
while (decoder.peekElement() != 0) { while (decoder.peekElement() != 0) {

View File

@ -51,7 +51,7 @@ public class MappedDataEntry extends MappedEntry {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
super.decode(decoder); super.decode(decoder);
data = symbol.getProgram().getListing().getDataAt(storage.getMinAddress()); data = symbol.getProgram().getListing().getDataAt(storage.getMinAddress());
} }

View File

@ -54,14 +54,14 @@ public class MappedEntry extends SymbolEntry {
} }
@Override @Override
public void decode(Decoder decoder) throws PcodeXMLException { public void decode(Decoder decoder) throws DecoderException {
HighFunction function = symbol.function; HighFunction function = symbol.function;
Program program = function.getFunction().getProgram(); Program program = function.getFunction().getProgram();
int addrel = decoder.openElement(ElementId.ELEM_ADDR); int addrel = decoder.openElement(ElementId.ELEM_ADDR);
int sz = symbol.type.getLength(); int sz = symbol.type.getLength();
if (sz == 0) { if (sz == 0) {
throw new PcodeXMLException( throw new DecoderException(
"Invalid symbol 0-sized data-type: " + symbol.type.getName()); "Invalid symbol 0-sized data-type: " + symbol.type.getName());
} }
try { try {
@ -76,7 +76,7 @@ public class MappedEntry extends SymbolEntry {
} }
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
throw new PcodeXMLException("Invalid storage: " + e.getMessage()); throw new DecoderException("Invalid storage: " + e.getMessage());
} }
decoder.closeElement(addrel); decoder.closeElement(addrel);

Some files were not shown because too many files have changed in this diff Show More