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;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@ -81,9 +82,10 @@ public class SleighProgramCompiler {
* @return the list of p-code ops
* @throws UnknownInstructionException in case of crossbuilds, the target instruction is unknown
* @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)
throws UnknownInstructionException, MemoryAccessException {
throws UnknownInstructionException, MemoryAccessException, IOException {
Address zero = language.getDefaultSpace().getAddress(0);
SleighParserContext c = new SleighParserContext(zero, zero, zero, zero);
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.
*
* @param parser the parser to add the symbol to
* @return the nil symbol
*/
protected static VarnodeSymbol addNilSymbol(PcodeParser parser) {
SleighSymbol exists = parser.findSymbol(NIL_SYMBOL_NAME);
@ -124,9 +127,8 @@ public class SleighProgramCompiler {
return (VarnodeSymbol) exists;
}
long offset = parser.allocateTemp();
VarnodeSymbol nil =
new VarnodeSymbol(new Location("<util>", 0), NIL_SYMBOL_NAME, parser.getUniqueSpace(),
offset, 1);
VarnodeSymbol nil = new VarnodeSymbol(new Location("<util>", 0), NIL_SYMBOL_NAME,
parser.getUniqueSpace(), offset, 1);
parser.addSymbol(nil);
return nil;
}
@ -156,7 +158,7 @@ public class SleighProgramCompiler {
return ctor.construct(language, SleighProgramCompiler.buildOps(language, template),
libSyms);
}
catch (UnknownInstructionException | MemoryAccessException e) {
catch (UnknownInstructionException | MemoryAccessException | IOException e) {
throw new AssertionError(e);
}
}
@ -278,9 +280,8 @@ public class SleighProgramCompiler {
String p = params.get(i);
Varnode a = args.get(i);
if (a == null && i == 0) { // Only allow output to be omitted
parser.addSymbol(
new VarnodeSymbol(nil.getLocation(), p, nilVnData.space, nilVnData.offset,
nilVnData.size));
parser.addSymbol(new VarnodeSymbol(nil.getLocation(), p, nilVnData.space,
nilVnData.offset, nilVnData.size));
}
else {
parser.addSymbol(paramSym(language, sleigh, opName, p, a));

View File

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

View File

@ -534,22 +534,25 @@ void Architecture::nameFunction(const Address &addr,string &name) const
name = defname.str();
}
/// This process sets up a "register relative" space for this architecture
/// If the name is "stack", this space takes on the role of an "official" stack space
/// Should only be called once during initialization
/// \brief Create a new address space associated with a pointer register
///
/// 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 nm is the name of 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 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 isFormal is the indicator for the \b formal stack space
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();
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)
setReverseJustified(spc);
insertSpace(spc);
@ -1047,7 +1050,7 @@ void Architecture::decodeStackPointer(Decoder &decoder)
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,
@ -1114,7 +1117,7 @@ void Architecture::decodeSpacebase(Decoder &decoder)
AddrSpace *basespace = decoder.readSpace(ATTRIB_SPACE);
decoder.closeElement(elemId);
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

View File

@ -247,7 +247,7 @@ public:
#endif
protected:
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
// Factory routines for building this architecture

View File

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

View File

@ -71,7 +71,7 @@ void IfcLoadFile::execute(istream &s)
else
*status->optr << "Wrong tag type for experimental rules: "+root->getName() << endl;
}
catch(XmlError &err) {
catch(DecoderError &err) {
*status->optr << err.explain << endl;
*status->optr << "Skipping experimental rules" << endl;
}
@ -81,7 +81,7 @@ void IfcLoadFile::execute(istream &s)
bool iserror = false;
try {
dcp->conf->init(store);
} catch(XmlError &err) {
} catch(DecoderError &err) {
errmsg = err.explain;
iserror = true;
} catch(LowlevelError &err) {
@ -156,7 +156,7 @@ void IfcRestore::execute(istream &s)
dcp->conf->restoreXml(store);
} catch(LowlevelError &err) {
throw IfaceExecutionError(err.explain);
} catch(XmlError &err) {
} catch(DecoderError &err) {
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);
if (rec == (const CPoolRecord *)0) {
XmlDecode decoder(ghidra);
bool success;
PackedDecode decoder(ghidra);
try {
success = ghidra->getCPoolRef(refs,decoder);
}
catch(JavaError &err) {
throw LowlevelError("Error fetching constant pool record: " + err.explain);
}
catch(XmlError &err) {
throw LowlevelError("Error in constant pool record xml: "+err.explain);
catch(DecoderError &err) {
throw LowlevelError("Error in constant pool record encoding: "+err.explain);
}
if (!success) {
ostringstream s;

View File

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

View File

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

View File

@ -23,6 +23,28 @@
#include "cpool_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
/// \param sig is the OS signal (should always be SIGSEGV)
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 decoder is the given stream decoder that will hold the result
/// \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);
@ -159,38 +181,6 @@ bool ArchitectureGhidra::readStream(istream &s,Decoder &decoder)
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
/// \param s is the output stream to the client
/// \param msg is the string to send
@ -240,27 +230,13 @@ bool ArchitectureGhidra::readAll(istream &s,Decoder &decoder)
{
readToResponse(s);
if (readStream(s,decoder)) {
if (readStringStream(s,decoder)) {
readResponseEnd(s);
return true;
}
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
///
/// 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);
writeStringStream(sout,"getRegister");
writeStringStream(sout,regname);
sout.write("\000\000\001\016",4); // Beginning of string header
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.flush();
@ -429,11 +409,12 @@ string ArchitectureGhidra::getRegisterName(const VarnodeData &vndata)
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getRegisterName");
sout.write("\000\000\001\016",4); // Beginning of string header
Address addr(vndata.space,vndata.offset);
encoder.clear();
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETREGISTERNAME);
addr.encode(encoder,vndata.size);
encoder.closeElement(ELEM_COMMAND_GETREGISTERNAME);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
@ -456,10 +437,11 @@ bool ArchitectureGhidra::getTrackedRegisters(const Address &addr,Decoder &decode
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getTrackedRegisters");
sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear();
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETTRACKEDREGISTERS);
addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETTRACKEDREGISTERS);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
@ -475,9 +457,11 @@ string ArchitectureGhidra::getUserOpName(int4 index)
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getUserOpName");
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\005",4);
sout.flush();
@ -489,24 +473,24 @@ string ArchitectureGhidra::getUserOpName(int4 index)
return res;
}
/// Get a description of all the p-code ops for the instruction
/// at the given address. The information is stored in a special
/// compressed format. (See PcodeEmit::restorePackedOp)
/// Get a description of all the p-code ops for the instruction at the given address.
/// \param addr is the address of the instruction
/// \return an array of the packed data
uint1 *ArchitectureGhidra::getPcodePacked(const Address &addr)
/// \param decoder is the stream decoder for holding the result
/// \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);
writeStringStream(sout,"getPacked");
sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear();
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETPCODE);
addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETPCODE);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
return readPackedAll(sin);
return readAll(sin,decoder);
}
/// 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);
writeStringStream(sout,"getMappedSymbolsXML");
sout.write("\000\000\001\016",4); // Beginning of string
encoder.clear();
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETMAPPEDSYMBOLS);
addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETMAPPEDSYMBOLS);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
@ -540,14 +525,15 @@ bool ArchitectureGhidra::getMappedSymbolsXML(const Address &addr,Decoder &decode
/// \param addr is the given address
/// \param decoder is the stream decoder that will hold the result
/// \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);
writeStringStream(sout,"getExternalRefXML");
sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear();
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETEXTERNALREF);
addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETEXTERNALREF);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
@ -565,9 +551,11 @@ bool ArchitectureGhidra::getNamespacePath(uint8 id,Decoder &decoder)
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getNamespacePath");
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\005",4);
sout.flush();
@ -579,15 +567,13 @@ bool ArchitectureGhidra::isNameUsed(const string &nm,uint8 startId,uint8 stopId)
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"isNameUsed");
sout.write("\000\000\001\016",4); // Beginning of string header
sout << nm;
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\016",4); // Beginning of string header
sout << hex << startId;
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\016",4); // Beginning of string header
sout << hex << stopId;
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_ISNAMEUSED);
encoder.writeString(ATTRIB_NAME, nm);
encoder.writeUnsignedInteger(ATTRIB_FIRST, startId);
encoder.writeUnsignedInteger(ATTRIB_LAST, stopId);
encoder.closeElement(ELEM_COMMAND_ISNAMEUSED);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
@ -606,10 +592,11 @@ string ArchitectureGhidra::getCodeLabel(const Address &addr)
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getSymbol");
sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear();
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETCODELABEL);
addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETCODELABEL);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
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 decoder is the stream decoder that will hold the result
/// \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);
writeStringStream(sout,"getType");
writeStringStream(sout,name);
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\005",4);
sout.flush();
@ -654,13 +643,12 @@ bool ArchitectureGhidra::getComments(const Address &fad,uint4 flags,Decoder &dec
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getComments");
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);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\016",4); // Beginning of string header
sout << dec << flags;
encoder.closeElement(ELEM_COMMAND_GETCOMMENTS);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
@ -678,10 +666,11 @@ void ArchitectureGhidra::getBytes(uint1 *buf,int4 size,const Address &inaddr)
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getBytes");
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);
encoder.closeElement(ELEM_COMMAND_GETBYTES);
sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4);
sout.flush();
@ -726,14 +715,14 @@ void ArchitectureGhidra::getStringData(vector<uint1> &buffer,const Address &addr
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getString");
sout.write("\000\000\001\016",4); // Beginning of string header
encoder.clear();
addr.encode(encoder,maxBytes);
sout.write("\000\000\001\017",4);
writeStringStream(sout,ct->getName());
sout.write("\000\000\001\016",4); // Beginning of string header
sout << dec << (int8)ct->getId(); // Pass as a signed integer
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETSTRINGDATA);
encoder.writeSignedInteger(ATTRIB_MAXSIZE, maxBytes);
encoder.writeString(ATTRIB_TYPE,ct->getName());
encoder.writeUnsignedInteger(ATTRIB_ID, ct->getId());
addr.encode(encoder);
encoder.closeElement(ELEM_COMMAND_GETSTRINGDATA);
sout.write("\000\000\001\017",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);
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);
encoder.clear();
con.encode(encoder);
PackedEncode encoder(sout);
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\005",4);
sout.flush();
@ -814,12 +818,16 @@ bool ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs,Decoder &decoder)
{
sout.write("\000\000\001\004",4);
writeStringStream(sout,"getCPoolRef");
sout.write("\000\000\001\016",4); // Beginning of string header
sout << hex << refs[0];
for(int4 i=1;i<refs.size();++i) {
sout << ',' << hex << refs[i];
PackedEncode encoder(sout);
encoder.openElement(ELEM_COMMAND_GETCPOOLREF);
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\005",4);
sout.flush();
@ -827,24 +835,6 @@ bool ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs,Decoder &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
{
@ -861,7 +851,7 @@ void ArchitectureGhidra::printMessage(const string &message) const
/// \param o is the output stream to the Ghidra client
ArchitectureGhidra::ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,
const string &corespec,istream &i,ostream &o)
: Architecture(), sin(i), sout(o), encoder(sout)
: Architecture(), sin(i), sout(o)
{
print->setMarkup(true);

View File

@ -21,6 +21,26 @@
#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
///
/// 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 {
istream &sin; ///< Input 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
string pspecxml; ///< XML pspec 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
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
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 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 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
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
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);
@ -136,13 +155,11 @@ public:
static int4 readToAnyBurst(istream &s); ///< Read the next message protocol marker
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 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 readToResponse(istream &s); ///< Read the 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 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 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();
XmlDecode decoder(glb);
PackedDecode decoder(glb);
glb->getTrackedRegisters(addr,decoder);
uint4 elemId = decoder.openElement(ELEM_TRACKED_POINTSET);

View File

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

View File

@ -217,16 +217,18 @@ public:
/// 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).
/// The command expects 2 string parameters: the encoded integer id of the program,
/// and an XML document containing an \<optionslist> tag. The \<optionslist> tag
/// contains one child tag for each option to be configured.
/// and an encoded document containing an \<optionslist> element. The \<optionslist> element
/// contains one child element for each option to be configured.
/// The command returns a single character message, 't' or 'f', indicating whether the
/// configuration succeeded.
class SetOptions : public GhidraCommand {
string optionsListTag; ///< The <optionslist> XML tag
Decoder *decoder; ///< The \<optionslist> decoder
virtual void loadParameters(void);
virtual void sendResult(void);
public:
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);
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,8 +16,12 @@
#include "marshal.hh"
#include "translate.hh"
using namespace PackedFormat;
unordered_map<string,uint4> AttributeId::lookupAttributeId;
const int4 PackedDecode::BUFFER_SIZE = 1024;
/// 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.
/// \return a reference to the vector
@ -48,7 +52,7 @@ void AttributeId::initialize(void)
AttributeId *attrib = thelist[i];
#ifdef CPUI_DEBUG
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
lookupAttributeId[attrib->name] = attrib->id;
}
@ -88,7 +92,7 @@ void ElementId::initialize(void)
ElementId *elem = thelist[i];
#ifdef CPUI_DEBUG
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
lookupElementId[elem->name] = elem->id;
}
@ -103,16 +107,6 @@ XmlDecode::~XmlDecode(void)
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)
{
@ -169,7 +163,7 @@ uint4 XmlDecode::openElement(const ElementId &elemId)
const Element *el;
if (elStack.empty()) {
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;
rootElement = (const Element *)0; // Only open document once
}
@ -181,10 +175,10 @@ uint4 XmlDecode::openElement(const ElementId &elemId)
iterStack.back() = ++iter;
}
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())
throw XmlError("Expecting <" + elemId.getName() + "> but got <" + el->getName() + ">");
throw DecoderError("Expecting <" + elemId.getName() + "> but got <" + el->getName() + ">");
elStack.push_back(el);
iterStack.push_back(el->getChildren().begin());
attributeIndex = -1;
@ -197,9 +191,9 @@ void XmlDecode::closeElement(uint4 id)
#ifdef CPUI_DEBUG
const Element *el = elStack.back();
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)
throw XmlError("Trying to close <" + el->getName() + "> with mismatching id");
throw DecoderError("Trying to close <" + el->getName() + "> with mismatching id");
#endif
elStack.pop_back();
iterStack.pop_back();
@ -212,7 +206,7 @@ void XmlDecode::closeElementSkipping(uint4 id)
#ifdef CPUI_DEBUG
const Element *el = elStack.back();
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
elStack.pop_back();
iterStack.pop_back();
@ -251,7 +245,7 @@ int4 XmlDecode::findMatchingAttribute(const Element *el,const string &attribName
if (el->getAttributeName(i) == attribName)
return i;
}
throw XmlError("Attribute missing: " + attribName);
throw DecoderError("Attribute missing: " + attribName);
}
bool XmlDecode::readBool(void)
@ -355,7 +349,7 @@ AddrSpace *XmlDecode::readSpace(void)
string nm = el->getAttributeValue(attributeIndex);
AddrSpace *res = spcManager->getSpaceByName(nm);
if (res == (AddrSpace *)0)
throw XmlError("Unknown address space name: "+nm);
throw DecoderError("Unknown address space name: "+nm);
return res;
}
@ -373,7 +367,7 @@ AddrSpace *XmlDecode::readSpace(const AttributeId &attribId)
}
AddrSpace *res = spcManager->getSpaceByName(nm);
if (res == (AddrSpace *)0)
throw XmlError("Unknown address space name: "+nm);
throw DecoderError("Unknown address space name: "+nm);
return res;
}
@ -472,6 +466,543 @@ void XmlEncode::writeSpace(const AttributeId &attribId,const AddrSpace *spc)
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
AttributeId ATTRIB_CONTENT = AttributeId("XMLcontent",1);
AttributeId ATTRIB_ALIGN = AttributeId("align",2);
@ -513,4 +1044,4 @@ ElementId ELEM_VAL = ElementId("val",8);
ElementId ELEM_VALUE = ElementId("value",9);
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__
#include "xml.hh"
#include <list>
#include <unordered_map>
using namespace std;
@ -100,11 +101,6 @@ public:
const AddrSpaceManager *getAddrSpaceManager(void) const { return spcManager; } ///< Get the manager used for address space decoding
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
///
/// 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:
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
///
/// 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) {
document = (Document *)0; rootElement = (const Element *)0; attributeIndex = -1; } ///< Constructor for use with ingestStream
virtual ~XmlDecode(void);
virtual void clear(void);
virtual void ingestStream(istream &s);
virtual uint4 peekElement(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
public:
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 closeElement(const ElementId &elemId);
virtual void writeBool(const AttributeId &attribId,bool val);
@ -374,6 +363,206 @@ public:
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 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

View File

@ -230,6 +230,7 @@ public:
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 encode(Encoder &encoder) const; ///< Encode a description of \b this op to stream
/// \brief Retrieve the PcodeOp encoded as the address \e addr
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;
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
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
/// \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

View File

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

View File

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

View File

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

View File

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

View File

@ -94,12 +94,13 @@ public:
does_deadcode = 4, ///< Dead-code analysis is done on this space
programspecific = 8, ///< Space is specific to a particular loadimage
reverse_justification = 16, ///< Justification within aligned word is opposite of endianness
overlay = 32, ///< This space is an overlay of another space
overlaybase = 64, ///< This is the base space for overlay space(s)
truncated = 128, ///< Space is truncated from its original size, expect pointers larger than this size
hasphysical = 256, ///< Has physical memory associated with it
is_otherspace = 512, ///< Quick check for the OtherSpace derived class
has_nearpointers = 0x400 ///< Does there exist near pointers into this space
formal_stackspace = 0x20, ///< Space attached to the formal \b stack \b pointer
overlay = 0x40, ///< This space is an overlay of another space
overlaybase = 0x80, ///< This is the base space for overlay space(s)
truncated = 0x100, ///< Space is truncated from its original size, expect pointers larger than this size
hasphysical = 0x200, ///< Has physical memory associated with it
is_otherspace = 0x400, ///< Quick check for the OtherSpace derived class
has_nearpointers = 0x800 ///< Does there exist near pointers into this space
};
private:
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 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 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 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
@ -446,6 +448,11 @@ inline bool AddrSpace::isReverseJustified(void) const {
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 {
return ((flags&overlay)!=0);
}

View File

@ -108,7 +108,7 @@ void FunctionTestCollection::buildProgram(DocumentStorage &docStorage)
try {
dcp->conf->init(docStorage);
dcp->conf->readLoaderSymbols("::"); // Read in loader symbols
} catch(XmlError &err) {
} catch(DecoderError &err) {
errmsg = err.explain;
iserror = true;
} 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
/// 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 t is associated processor translator
/// \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 base is the containing space
/// \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,
AddrSpace *base,int4 dl)
AddrSpace *base,int4 dl,bool isFormal)
: AddrSpace(m,t,IPTR_SPACEBASE,nm,sz,base->getWordSize(),ind,0,dl)
{
contain = base;
hasbaseregister = false; // No base register assigned yet
isNegativeStack = true; // default stack growth
if (isFormal)
setFlags(formal_stackspace);
}
/// 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
/// returned to the application via the PcodeEmit::dump method.
/// \param decoder is the stream decoder
void PcodeEmit::decodeOp(Decoder &decoder)
void PcodeEmit::decodeOp(const Address &addr,Decoder &decoder)
{
int4 opcode;
int4 isize;
VarnodeData outvar;
VarnodeData invar[30];
VarnodeData invar[16];
VarnodeData *outptr;
uint4 elemId = decoder.openElement(ELEM_OP);
opcode = decoder.readSignedInteger(ATTRIB_CODE);
Address pc = Address::decode(decoder);
uint4 subId = decoder.peekElement();
if (subId == ELEM_VOID) {
decoder.openElement();
decoder.closeElement(subId);
outptr = (VarnodeData *)0;
}
isize = decoder.readSignedInteger(ATTRIB_SIZE);
outptr = &outvar;
if (isize <= 16)
opcode = PcodeOpRaw::decode(decoder, isize, invar, &outptr);
else {
outvar.decode(decoder);
outptr = &outvar;
}
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;
vector<VarnodeData> varStorage(isize,VarnodeData());
opcode = PcodeOpRaw::decode(decoder, isize, varStorage.data(), &outptr);
}
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);
return ptr;
}

View File

@ -108,23 +108,7 @@ public:
virtual void dump(const Address &addr,OpCode opc,VarnodeData *outvar,VarnodeData *vars,int4 isize)=0;
/// Emit pcode directly from an \<op> element
void decodeOp(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);
void decodeOp(const Address &addr,Decoder &decoder);
};
/// \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
void setBaseRegister(const VarnodeData &data,int4 origSize,bool stackGrowth); ///< Set the base register at time space is created
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
virtual int4 numSpacebase(void) 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
if (ct != (Datatype *)0) return ct;
XmlDecode decoder(glb);
ArchitectureGhidra *ghidra = (ArchitectureGhidra *)glb;
PackedDecode decoder(ghidra);
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;
}
catch(XmlError &err) {
throw LowlevelError("XML error: "+err.explain);
catch(DecoderError &err) {
throw LowlevelError("Decoder error: "+err.explain);
}
ct = decodeType(decoder); // Parse ghidra's type
return ct;

View File

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

View File

@ -285,9 +285,9 @@ public:
///
/// This object holds the error message as passed to the SAX interface callback
/// and is thrown as a formal exception.
struct XmlError {
struct DecoderError {
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

View File

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

View File

@ -36,8 +36,8 @@ public class ClangBreak extends ClangToken {
}
@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);
super.decode(decoder, pfactory);
setText("");
}
}

View File

@ -56,7 +56,7 @@ public class ClangCommentToken extends ClangToken {
}
@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);
long offset = decoder.readUnsignedInteger(AttributeId.ATTRIB_OFF);
srcaddr = spc.getAddress(offset);

View File

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

View File

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

View File

@ -43,7 +43,7 @@ public class ClangLabelToken extends ClangToken {
}
@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);
long offset = decoder.readUnsignedInteger(AttributeId.ATTRIB_OFF);
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 ClangTokenGroup buildClangTree(Decoder decoder, HighFunction hfunc)
throws PcodeXMLException {
throws DecoderException {
ClangTokenGroup docroot;
int el = decoder.openElement();
if (el == ElementId.ELEM_FUNCTION.id()) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -51,7 +51,7 @@ public class ClangVariableDecl extends ClangTokenGroup {
}
@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);
super.decode(decoder, pfactory);
HighSymbol sym = pfactory.getSymbol(symref);

View File

@ -86,7 +86,7 @@ public class ClangVariableToken extends ClangToken {
}
@Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws PcodeXMLException {
public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) {
int attribId = decoder.getNextAttributeId();
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.UniqueLayout;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
@ -49,7 +48,7 @@ import ghidra.util.task.TaskMonitor;
* DecompInterface ifc = new DecompInterface();
*
* // 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.toggleCCode(false); // Don't produce C code
* // ifc.setSimplificationStyle("normalize"); // Alternate analysis style
@ -88,7 +87,9 @@ public class DecompInterface {
protected CompilerSpec compilerSpec;
protected DecompileProcess decompProcess;
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;
protected CancelledListener monitorListener = new CancelledListener() {
@Override
@ -99,7 +100,7 @@ public class DecompInterface {
// Initialization state
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 printCCode; // Whether C code is returned
private boolean sendParamMeasures; // Whether Parameter Measures are returned
@ -110,8 +111,9 @@ public class DecompInterface {
pcodelanguage = null;
dtmanage = null;
decompCallback = null;
xmlOptions = null;
encoder = null;
options = null;
paramEncode = null;
decoder = null;
debug = null;
decompileMessage = "";
compilerSpec = null;
@ -215,31 +217,33 @@ public class DecompInterface {
decompProcess = DecompileProcessFactory.get();
}
long uniqueBase = UniqueLayout.SLEIGH_BASE.getOffset(pcodelanguage);
encoder.clear();
pcodelanguage.encodeTranslator(encoder, program.getAddressFactory(), uniqueBase);
String tspec = encoder.toString();
encoder.clear();
dtmanage.encodeCoreTypes(encoder);
String coretypes = encoder.toString();
XmlEncode xmlEncode = new XmlEncode();
pcodelanguage.encodeTranslator(xmlEncode, program.getAddressFactory(), uniqueBase);
String tspec = xmlEncode.toString();
xmlEncode.clear();
dtmanage.encodeCoreTypes(xmlEncode);
String coretypes = xmlEncode.toString();
SleighLanguageDescription sleighdescription =
(SleighLanguageDescription) pcodelanguage.getLanguageDescription();
ResourceFile pspecfile = sleighdescription.getSpecFile();
String pspecxml = fileToString(pspecfile);
XmlEncode xmlEncode = new XmlEncode();
xmlEncode.clear();
compilerSpec.encode(xmlEncode);
String cspecxml = xmlEncode.toString();
decompCallback.setNativeMessage(null);
decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes);
decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes,
program);
String nativeMessage = decompCallback.getNativeMessage();
if ((nativeMessage != null) && (nativeMessage.length() != 0)) {
throw new IOException("Could not register program: " + nativeMessage);
}
if (xmlOptions != null) {
decompProcess.setMaxResultSize(xmlOptions.getMaxPayloadMBytes());
if (!decompProcess.sendCommand1Param("setOptions", xmlOptions.getXML(this))
.toString()
.equals("t")) {
if (options != null) {
paramEncode.clear();
options.encode(paramEncode, this);
decompProcess.setMaxResultSize(options.getMaxPayloadMBytes());
decompProcess.sendCommand1Param("setOptions", paramEncode, stringResponse);
if (!stringResponse.toString().equals("t")) {
throw new IOException("Did not accept decompiler options");
}
}
@ -247,35 +251,32 @@ public class DecompInterface {
throw new IOException("Decompile action not specified");
}
if (!actionname.equals("decompile")) {
if (!decompProcess.sendCommand2Params("setAction", actionname, "")
.toString()
.equals("t")) {
decompProcess.sendCommand2Params("setAction", actionname, "", stringResponse);
if (!stringResponse.toString().equals("t")) {
throw new IOException("Could not set decompile action");
}
}
if (!printSyntaxTree) {
if (!decompProcess.sendCommand2Params("setAction", "", "notree")
.toString()
.equals("t")) {
decompProcess.sendCommand2Params("setAction", "", "notree", stringResponse);
if (!stringResponse.toString().equals("t")) {
throw new IOException("Could not turn off syntax tree");
}
}
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");
}
}
if (sendParamMeasures) {
if (!decompProcess.sendCommand2Params("setAction", "", "parammeasures")
.toString()
.equals("t")) {
decompProcess.sendCommand2Params("setAction", "", "parammeasures", stringResponse);
if (!stringResponse.toString().equals("t")) {
throw new IOException("Could not turn on sending of parameter measures");
}
}
if (jumpLoad) {
if (!decompProcess.sendCommand2Params("setAction", "", "jumpload")
.toString()
.equals("t")) {
decompProcess.sendCommand2Params("setAction", "", "jumpload", stringResponse);
if (!stringResponse.toString().equals("t")) {
throw new IOException("Could not turn on jumptable loads");
}
}
@ -322,7 +323,8 @@ public class DecompInterface {
compilerSpec = spec;
dtmanage = new PcodeDataTypeManager(prog);
encoder = new XmlEncode();
paramEncode = new PackedEncode();
decoder = new PackedDecode(prog.getAddressFactory());
try {
decompCallback =
new DecompileCallback(prog, pcodelanguage, program.getCompilerSpec(), dtmanage);
@ -344,7 +346,8 @@ public class DecompInterface {
}
program = null;
decompCallback = null;
encoder = null;
paramEncode = null;
decoder = null;
return false;
}
@ -360,7 +363,8 @@ public class DecompInterface {
if (program != null) {
program = null;
decompCallback = null;
encoder = null;
paramEncode = null;
decoder = null;
try {
if ((decompProcess != null) && decompProcess.isReady()) {
decompProcess.deregisterProgram();
@ -422,9 +426,8 @@ public class DecompInterface {
}
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", actionstring, "")
.toString()
.equals("t");
decompProcess.sendCommand2Params("setAction", actionstring, "", stringResponse);
return stringResponse.toString().equals("t");
}
catch (IOException e) {
// don't care
@ -460,9 +463,8 @@ public class DecompInterface {
String printstring = val ? "tree" : "notree";
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring)
.toString()
.equals("t");
decompProcess.sendCommand2Params("setAction", "", printstring, stringResponse);
return stringResponse.toString().equals("t");
}
catch (IOException e) {
// don't care
@ -499,9 +501,8 @@ public class DecompInterface {
String printstring = val ? "c" : "noc";
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring)
.toString()
.equals("t");
decompProcess.sendCommand2Params("setAction", "", printstring, stringResponse);
return stringResponse.toString().equals("t");
}
catch (IOException e) {
// don't care
@ -537,9 +538,8 @@ public class DecompInterface {
String printstring = val ? "parammeasures" : "noparammeasures";
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", printstring)
.toString()
.equals("t");
decompProcess.sendCommand2Params("setAction", "", printstring, stringResponse);
return stringResponse.toString().equals("t");
}
catch (IOException e) {
// don't care
@ -568,9 +568,8 @@ public class DecompInterface {
String jumpstring = val ? "jumpload" : "nojumpload";
try {
verifyProcess();
return decompProcess.sendCommand2Params("setAction", "", jumpstring)
.toString()
.equals("t");
decompProcess.sendCommand2Params("setAction", "", jumpstring, stringResponse);
return stringResponse.toString().equals("t");
}
catch (IOException e) {
// don't care
@ -593,11 +592,11 @@ public class DecompInterface {
* recovering from decompiler process crash, the interface
* keeps the options object around and automatically
* 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
*/
public synchronized boolean setOptions(DecompileOptions xmloptions) {
this.xmlOptions = xmloptions;
public synchronized boolean setOptions(DecompileOptions options) {
this.options = options;
decompileMessage = "";
// Property can be set before process exists
if (decompProcess == null) {
@ -605,10 +604,11 @@ public class DecompInterface {
}
try {
verifyProcess();
decompProcess.setMaxResultSize(xmlOptions.getMaxPayloadMBytes());
return decompProcess.sendCommand1Param("setOptions", xmloptions.getXML(this))
.toString()
.equals("t");
paramEncode.clear();
options.encode(paramEncode, this);
decompProcess.setMaxResultSize(options.getMaxPayloadMBytes());
decompProcess.sendCommand1Param("setOptions", paramEncode, stringResponse);
return stringResponse.toString().equals("t");
}
catch (IOException e) {
// don't care
@ -626,7 +626,7 @@ public class DecompInterface {
* @return options that will be passed to the decompiler
*/
public synchronized DecompileOptions getOptions() {
return this.xmlOptions;
return this.options;
}
/**
@ -643,8 +643,8 @@ public class DecompInterface {
int res = -1;
try {
if ((decompProcess != null) && decompProcess.isReady()) {
String retval = decompProcess.sendCommand("flushNative").toString();
return Integer.parseInt(retval);
decompProcess.sendCommand("flushNative", stringResponse);
return Integer.parseInt(stringResponse.toString());
}
}
catch (IOException e) {
@ -657,8 +657,8 @@ public class DecompInterface {
return res;
}
public synchronized BlockGraph structureGraph(BlockGraph ingraph, AddressFactory factory,
int timeoutSecs, TaskMonitor monitor) {
public synchronized BlockGraph structureGraph(BlockGraph ingraph, int timeoutSecs,
TaskMonitor monitor) {
decompileMessage = "";
if (monitor != null && monitor.isCancelled()) {
return null;
@ -666,18 +666,15 @@ public class DecompInterface {
if (monitor != null) {
monitor.addCancelledListener(monitorListener);
}
LimitedByteBuffer res = null;
BlockGraph resgraph = null;
try {
encoder.clear();
ingraph.encode(encoder);
verifyProcess();
res = decompProcess.sendCommand1ParamTimeout("structureGraph", encoder.toString(),
timeoutSecs);
paramEncode.clear();
ingraph.encode(paramEncode);
decompProcess.sendCommand1ParamTimeout("structureGraph", paramEncode, timeoutSecs,
decoder);
decompileMessage = decompCallback.getNativeMessage();
if (res != null) {
XmlDecode decoder = new XmlDecode(factory);
decoder.ingestStream(res.getInputStream(), "structureGraph results");
if (!decoder.isEmpty()) {
resgraph = new BlockGraph();
resgraph.decode(decoder);
resgraph.transferObjectRef(ingraph);
@ -710,7 +707,6 @@ public class DecompInterface {
return null;
}
LimitedByteBuffer res = null;
if (monitor != null) {
monitor.addCancelledListener(monitorListener);
}
@ -726,12 +722,18 @@ public class DecompInterface {
debug.setFunction(func);
}
decompCallback.setFunction(func, funcEntry, debug);
encoder.clear();
AddressXML.encode(encoder, funcEntry);
verifyProcess();
res = decompProcess.sendCommand1ParamTimeout("decompileAt", encoder.toString(),
timeoutSecs);
paramEncode.clear();
AddressXML.encode(paramEncode, funcEntry);
decompProcess.sendCommand1ParamTimeout("decompileAt", paramEncode, timeoutSecs,
decoder);
decompileMessage = decompCallback.getNativeMessage();
if (debug != null) {
XmlEncode xmlEncode = new XmlEncode();
options.encode(xmlEncode, this);
debug.shutdown(pcodelanguage, xmlEncode.toString());
debug = null;
}
}
catch (Exception ex) {
decompileMessage = "Exception while decompiling " + func.getEntryPoint() + ": " +
@ -742,10 +744,6 @@ public class DecompInterface {
monitor.removeCancelledListener(monitorListener);
}
}
if (debug != null) {
debug.shutdown(pcodelanguage, xmlOptions.getXML(this));
debug = null;
}
DecompileProcess.DisposeState processState;
if (decompProcess != null) {
@ -758,12 +756,8 @@ public class DecompInterface {
processState = DecompileProcess.DisposeState.DISPOSED_ON_CANCEL;
}
InputStream stream = null;
if (res != null) {
stream = res.getInputStream();
}
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.exception.UsrException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.xml.SpecXmlUtils;
/**
*
@ -49,7 +48,6 @@ import ghidra.util.xml.SpecXmlUtils;
public class DecompileCallback {
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
@ -75,8 +73,6 @@ public class DecompileCallback {
private Charset utf8Charset;
private String nativeMessage;
private XmlDecodeLight lightDecoder;
private XmlEncode resultEncode;
private InstructionBlock lastPseudoInstructionBlock;
private Disassembler pseudoDisassembler;
@ -93,8 +89,6 @@ public class DecompileCallback {
nativeMessage = null;
debug = null;
utf8Charset = Charset.availableCharsets().get(CharsetInfo.UTF8);
lightDecoder = new XmlDecodeLight(addrfactory);
resultEncode = new XmlEncode();
}
/**
@ -140,21 +134,24 @@ public class DecompileCallback {
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 {
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];
int bytesRead = program.getMemory().getBytes(addr, resbytes, 0, size);
if (debug != null) {
@ -172,9 +169,6 @@ public class DecompileCallback {
catch (MemoryAccessException e) {
Msg.warn(this, "Decompiling " + funcEntry + ": " + e.getMessage());
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
}
catch (Exception e) {
Msg.error(this,
"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
* address
* address. Filter based on selected comment types.
*
* @param addrstring is the XML rep of function address
* @param types is the string encoding of the comment type flags
* @return Encoded description of comments
* @param addr is the indicated address
* @param types is the set of flags
* @param resultEncoder will contain the collected comments
* @throws IOException for errors in the underlying stream
*/
public byte[] getComments(String addrstring, String types) throws IOException {
Address addr;
int flags;
try {
lightDecoder.ingestString(addrstring);
addr = AddressXML.decode(lightDecoder);
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
public void getComments(Address addr, int types, Encoder resultEncoder) throws IOException {
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);
if (func == null) {
return EMPTY_BYTE_ARRAY;
return;
}
resultEncode.clear();
encodeComments(resultEncode, addr, func, flags);
encodeComments(resultEncoder, addr, func, types);
if (debug != null) {
XmlEncode xmlEncode = new XmlEncode();
encodeComments(xmlEncode, addr, func, flags);
encodeComments(xmlEncode, addr, func, types);
debug.getComments(xmlEncode.toString());
}
return resultEncode.getBytes();
}
public PackedBytes getPcodePacked(String addrstring) {
Address addr = null;
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 null;
/**
* Generate p-code ops for the instruction at the given address
* @param addr is the given address
* @param resultEncoder will contain the generated p-code ops
*/
public void getPcode(Address addr, PackedEncode resultEncoder) {
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
try {
Instruction instr = getInstruction(addr);
if (instr == null) {
return null;
return;
}
if (undefinedBody != null) {
undefinedBody.addRange(instr.getMinAddress(), instr.getMaxAddress());
@ -250,11 +227,10 @@ public class DecompileCallback {
}
}
PackedBytes pcode = instr.getPrototype()
.getPcodePacked(instr.getInstructionContext(),
instr.getPrototype()
.getPcodePacked(resultEncoder, instr.getInstructionContext(),
new InstructionPcodeOverride(instr));
return pcode;
return;
}
catch (UsrException e) {
Msg.warn(this,
@ -264,23 +240,23 @@ public class DecompileCallback {
Msg.error(this,
"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
*
* @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
* flow falls into
* @param paramshift special instructions for injection use
* @param addrFactory is the address factory for recovering address space names
* @throws IOException for errors in the underlying stream
*/
public static void encodeInstruction(Encoder encoder, PcodeOp[] ops, int fallthruoffset,
int paramshift, AddressFactory addrFactory) throws IOException {
public static void encodeInstruction(Encoder encoder, Address addr, PcodeOp[] ops,
int fallthruoffset, int paramshift, AddressFactory addrFactory) throws IOException {
if ((ops.length == 1) && (ops[0].getOpcode() == PcodeOp.UNIMPLEMENTED)) {
encoder.openElement(ELEM_UNIMPL);
encoder.writeSignedInteger(ATTRIB_OFFSET, fallthruoffset);
@ -292,29 +268,36 @@ public class DecompileCallback {
if (paramshift != 0) {
encoder.writeSignedInteger(ATTRIB_PARAMSHIFT, paramshift);
}
AddressXML.encode(encoder, addr);
for (PcodeOp op : ops) {
op.encode(encoder, addrFactory);
op.encodeRaw(encoder, addrFactory);
}
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();
InjectPayload payload = snippetLibrary.getPayload(type, nm);
if (payload == null) {
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();
PcodeOp[] pcode;
try {
lightDecoder.ingestString(context);
con.decode(lightDecoder);
con.decode(paramDecoder);
}
catch (PcodeXMLException e) {
catch (DecoderException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
return EMPTY_BYTE_ARRAY;
return;
}
try {
int fallThruOffset;
@ -322,14 +305,14 @@ public class DecompileCallback {
// Executable p-code has no underlying instruction address and
// does (should) not use the inst_start, inst_next symbols that need
// to know about it.
fallThruOffset = 4; // Provide a dummy length for the XML doc
fallThruOffset = 4; // Provide a dummy length
}
else {
Instruction instr = getInstruction(con.baseAddr);
if (instr == null) {
Msg.warn(this, "Decompiling " + funcEntry + ", pcode inject error at " +
con.baseAddr + ": instruction not found");
return EMPTY_BYTE_ARRAY;
return;
}
// get next inst addr for inst_next pcode variable
@ -347,18 +330,16 @@ public class DecompileCallback {
}
pcode = payload.getPcode(program, con);
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(resultEncode, pcode, fallThruOffset, payload.getParamShift(),
addrfactory);
encodeInstruction(resultEncoder, con.baseAddr, pcode, fallThruOffset,
payload.getParamShift(), addrfactory);
if (debug != null) {
XmlEncode xmlEncode = new XmlEncode();
encodeInstruction(xmlEncode, pcode, fallThruOffset, payload.getParamShift(),
addrfactory);
encodeInstruction(xmlEncode, con.baseAddr, pcode, fallThruOffset,
payload.getParamShift(), addrfactory);
debug.addInject(con.baseAddr, nm, type, xmlEncode.toString());
}
return resultEncode.getBytes();
}
catch (UnknownInstructionException e) {
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 +
": " + 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) {
cpool = pcodecompilerspec.getPcodeInjectLibrary().getConstantPool(program);
}
Record record = cpool.getRecord(refs);
resultEncode.clear();
record.encode(resultEncode, refs[0], dtmanage);
record.encode(resultEncoder, refs[0], dtmanage);
if (debug != null) {
XmlEncode xmlEncode = new XmlEncode();
record.encode(xmlEncode, refs[0], dtmanage);
debug.getCPoolRef(xmlEncode.toString(), refs);
}
return resultEncode.getBytes();
}
private Instruction getInstruction(Address addr) throws UnknownInstructionException {
@ -447,18 +431,14 @@ public class DecompileCallback {
throw new UnknownInstructionException("Invalid instruction address (improperly aligned)");
}
public String getSymbol(String addrstring) { // Return first symbol name at this address
Address 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 null;
/**
* Return the first symbol name at the given address
* @param addr is the given address
* @return the symbol or null if no symbol is found
*/
public String getCodeLabel(Address addr) {
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
try {
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
* @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
*/
public byte[] getNamespacePath(long id) throws IOException {
public void getNamespacePath(long id, Encoder resultEncoder) throws IOException {
Namespace namespace = getNameSpaceByID(id);
resultEncode.clear();
HighFunction.encodeNamespace(resultEncode, namespace);
HighFunction.encodeNamespace(resultEncoder, namespace);
if (debug != null) {
debug.getNamespacePath(namespace);
}
return resultEncode.getBytes();
}
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
* symbols at the given address.
*
* @param addrstring XML encoded address to query
* @return an encoded description, either function, reference, datatype, or hole
* @param addr is the given address
* @param resultEncoder is where to write encoded description
*/
public byte[] getMappedSymbolsXML(String addrstring) {
Address addr;
try {
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;
}
public void getMappedSymbols(Address addr, Encoder resultEncoder) {
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
return EMPTY_BYTE_ARRAY;
if (addr == Address.NO_ADDRESS) {
// Unknown spaces may result from "spacebase" registers defined in cspec
return;
}
try {
Object obj = lookupSymbol(addr);
resultEncode.clear();
if (obj instanceof Function) {
boolean includeDefaults = addr.equals(funcEntry);
encodeFunction(resultEncode, (Function) obj, addr, includeDefaults);
encodeFunction(resultEncoder, (Function) obj, addr, includeDefaults);
}
else if (obj instanceof Data) {
if (!encodeData(resultEncode, (Data) obj)) {
encodeHole(resultEncode, addr);
if (!encodeData(resultEncoder, (Data) obj)) {
encodeHole(resultEncoder, addr);
}
}
else if (obj instanceof ExternalReference) {
encodeExternalRef(resultEncode, addr, (ExternalReference) obj);
encodeExternalRef(resultEncoder, addr, (ExternalReference) obj);
}
else if (obj instanceof Symbol) {
encodeLabel(resultEncode, (Symbol) obj, addr);
encodeLabel(resultEncoder, (Symbol) obj, addr);
}
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) {
Msg.error(this, "Decompiling " + funcEntry + ", mapped symbol error for " + addrstring +
Msg.error(this, "Decompiling " + funcEntry + ", mapped symbol error for " + addr +
": " + e.getMessage(), e);
}
return EMPTY_BYTE_ARRAY;
return;
}
/**
* Describe an external reference at the given address
* @param addrstring is the description of the address
* @return the encoded description
* Get a description of an external reference at the given address
* @param addr is the given address
* @param resultEncoder will contain the resulting description
*/
public byte[] getExternalRefXML(String addrstring) {
Address 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;
public void getExternalRef(Address addr, Encoder resultEncoder) {
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
try {
Function func = null;
if (cachedFunction != null && cachedFunction.getEntryPoint().equals(addr)) {
func = cachedFunction;
@ -778,9 +736,8 @@ public class DecompileCallback {
}
HighSymbol shellSymbol =
new HighFunctionShellSymbol(extId, extRef.getLabel(), addr, dtmanage);
resultEncode.clear();
encodeResult(resultEncode, shellSymbol, null);
return resultEncode.getBytes();
encodeResult(resultEncoder, shellSymbol, null);
return;
}
}
else {
@ -789,7 +746,7 @@ public class DecompileCallback {
}
if (func == null) {
// 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);
@ -803,86 +760,89 @@ public class DecompileCallback {
debug.getFNTypes(hfunc);
debug.addPossiblePrototypeExtension(func);
}
resultEncode.clear();
encodeResult(resultEncode, funcSymbol, namespc);
return resultEncode.getBytes();
encodeResult(resultEncoder, funcSymbol, namespc);
return;
}
catch (Exception e) {
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);
if (type == null) {
return EMPTY_BYTE_ARRAY;
return;
}
resultEncode.clear();
dtmanage.encodeType(resultEncode, type, 0);
dtmanage.encodeType(resultEncoder, type, 0);
if (debug != null) {
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);
if (reg == null) {
throw new RuntimeException("No Register Defined: " + name);
}
resultEncode.clear();
encodeRegister(resultEncode, reg);
return resultEncode.getBytes();
encodeRegister(resultEncoder, reg);
}
public String getRegisterName(String addrstring) {
try {
lightDecoder.ingestString(addrstring);
lightDecoder.openElement();
Address addr = AddressXML.decodeFromAttributes(lightDecoder);
int size = (int) lightDecoder.readSignedInteger(ATTRIB_SIZE);
Register reg = pcodelanguage.getRegister(addr, size);
if (reg == null) {
return "";
}
return reg.getName();
/**
* Given a storage location, return the register name for that location, or null if there
* is no register there.
* @param addr is the starting address of the storage location
* @param size is the size of storage in bytes
* @return the register name or null
*/
public String getRegisterName(Address addr, int size) {
Register reg = pcodelanguage.getRegister(addr, size);
if (reg == null) {
return "";
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry +
", error while searching for register name: " + e.getMessage(), e);
}
return "";
return reg.getName();
}
public byte[] getTrackedRegisters(String addrstring) throws IOException {
Address 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;
/**
* Get "tracked" register values, constant values associated with a specific register at
* a specific point in the code.
* @param addr is the "point" in the code to look for tracked values
* @param resultEncoder will hold the resulting description of registers and values
* @throws IOException for errors in the underlying stream writing the result
*/
public void getTrackedRegisters(Address addr, Encoder resultEncoder) throws IOException {
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
ProgramContext context = program.getProgramContext();
resultEncode.clear();
encodeTrackedPointSet(resultEncode, addr, context);
encodeTrackedPointSet(resultEncoder, addr, context);
if (debug != null) {
XmlEncode xmlEncode = new XmlEncode();
encodeTrackedPointSet(xmlEncode, addr, context);
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);
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.
* 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
@ -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
* 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
* 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
* 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 dtId is the id associated with the character data-type
* @return the UTF8 encoded byte array or null
*/
public StringData getStringData(String addrString, String dtName, long dtId) {
Address addr;
int maxChars;
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");
}
public StringData getStringData(Address addr, int maxChars, String dtName, long dtId) {
if (overlaySpace != null) {
addr = overlaySpace.getOverlayAddress(addr);
}
catch (PcodeXMLException e) {
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
if (addr == Address.NO_ADDRESS) {
Msg.error(this, "Address does not physically map");
return null;
}
Data data = program.getListing().getDataContaining(addr);

View File

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

View File

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

View File

@ -15,14 +15,18 @@
*/
package ghidra.app.decompiler;
import static ghidra.program.model.pcode.AttributeId.*;
import static ghidra.program.model.pcode.ElementId.*;
import java.io.*;
import ghidra.program.model.address.Address;
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.timer.GTimer;
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 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 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 {
NOT_DISPOSED, // Process was/is not disposed
DISPOSED_ON_TIMEOUT, // A timeout occurred
@ -89,6 +98,7 @@ public class DecompileProcess {
disposestate = DisposeState.DISPOSED_ON_TIMEOUT;
}
};
stringDecoder = new StringIngest();
}
public void dispose() {
@ -186,17 +196,10 @@ public class DecompileProcess {
throw new IOException("Ghidra/decompiler alignment error");
}
private int readToBuffer(LimitedByteBuffer buf) throws IOException {
private int readToBuffer(ByteIngest buf) throws IOException {
int cur;
for (;;) {
cur = nativeIn.read();
while (cur > 0) {
buf.append((byte) cur);
cur = nativeIn.read();
}
if (cur == -1) {
break;
}
buf.ingestStream(nativeIn);
do {
cur = nativeIn.read();
}
@ -214,17 +217,17 @@ public class DecompileProcess {
throw new IOException("Decompiler process died");
}
private String readQueryString() throws IOException {
private void readQueryParam(ByteIngest ingester) throws IOException {
int type = readToBurst();
if (type != 14) {
throw new IOException("GHIDRA/decompiler alignment error");
}
LimitedByteBuffer buf = new LimitedByteBuffer(16, 1 << 16);
type = readToBuffer(buf);
ingester.open(1 << 16, programSource);
type = readToBuffer(ingester);
if (type != 15) {
throw new IOException("GHIDRA/decompiler alignment error");
}
return buf.toString();
ingester.endIngest();
}
private void writeString(String msg) throws IOException {
@ -233,40 +236,20 @@ public class DecompileProcess {
write(string_end);
}
private void writeBytes(byte[] msg) throws IOException {
write(string_start);
write(msg);
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);
private void writeString(Encoder byteResult) throws IOException {
if (nativeOut == null) {
return;
}
write(string_start);
byteResult.writeTo(nativeOut);
write(string_end);
}
private void generateException() throws IOException, DecompileException {
String type = readQueryString();
String message = readQueryString();
readQueryParam(stringDecoder);
String type = stringDecoder.toString();
readQueryParam(stringDecoder);
String message = stringDecoder.toString();
readToBurst(); // Read exception terminator
if (type.equals("alignment")) {
throw new IOException("Alignment error: " + message);
@ -274,89 +257,78 @@ public class DecompileProcess {
throw new DecompileException(type, message);
}
private LimitedByteBuffer readResponse() throws IOException, DecompileException {
private void readResponse(ByteIngest mainResponse) throws IOException, DecompileException {
readToResponse();
int type = readToBurst();
String name;
LimitedByteBuffer retbuf = null;
LimitedByteBuffer buf = null;
int commandId;
ByteIngest currentResponse = null;
while (type != 7) {
switch (type) {
case 4:
name = readQueryString();
readQueryParam(paramDecoder);
try {
if (name.length() < 4) {
throw new Exception("Bad decompiler query: " + name);
}
switch (name.charAt(3)) {
case 'a': // isNameUsed
commandId = paramDecoder.openElement();
switch (commandId) {
case COMMAND_ISNAMEUSED:
isNameUsed();
break;
case 'B':
case COMMAND_GETBYTES:
getBytes(); // getBytes
break;
case 'C':
if (name.equals("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();
}
case COMMAND_GETCOMMENTS:
getComments();
break;
case 'E':
getExternalRefXML(); // getExternalRefXML
case COMMAND_GETCALLFIXUP:
getPcodeInject(InjectPayload.CALLFIXUP_TYPE);
break;
case 'M':
getMappedSymbolsXML(); // getMappedSymbolsXML
case COMMAND_GETCALLOTHERFIXUP:
getPcodeInject(InjectPayload.CALLOTHERFIXUP_TYPE);
break;
case 'N':
getNamespacePath();
case COMMAND_GETCALLMECH:
getPcodeInject(InjectPayload.CALLMECHANISM_TYPE);
break;
case 'P':
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':
case COMMAND_GETPCODEEXECUTABLE:
getPcodeInject(InjectPayload.EXECUTABLEPCODE_TYPE);
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:
throw new Exception("Unsupported decompiler query '" + name + "'");
throw new Exception("Unsupported decompiler query");
}
}
catch (Exception e) { // Catch ANY exception query generates
@ -384,47 +356,45 @@ public class DecompileProcess {
generateException();
break;
case 14: // Start of the main decompiler output
if (buf != null) {
if (currentResponse != null) {
throw new IOException("Nested decompiler output");
}
// 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
// determined by maxResultSizeMBYtes
buf = new LimitedByteBuffer(1024, maxResultSizeMBYtes << 20);
currentResponse = mainResponse;
currentResponse.open(maxResultSizeMBYtes << 20, programSource);
break;
case 15: // This is the end of the main decompiler output
if (buf == null) {
if (currentResponse == null) {
throw new IOException("Mismatched string header");
}
retbuf = buf;
buf = null; // Reset the main buffer as a native message may follow
currentResponse.endIngest();
currentResponse = null; // Reset current buffer as a native message may follow
break;
case 16: // Beginning of any native message from the decompiler
// if (buf!=null)
// throw new IOException("Nested decompiler output");
// if buf is non-null, then res was interrupted
// so we just throw out the partial result
buf = new LimitedByteBuffer(64, 1 << 20);
currentResponse = stringDecoder;
currentResponse.open(1 << 20, programSource);
break;
case 17: // End of the native message from the decompiler
if (buf == null) {
if (currentResponse == null) {
throw new IOException("Mismatched message header");
}
callback.setNativeMessage(buf.toString());
buf = null;
currentResponse.endIngest();
callback.setNativeMessage(currentResponse.toString());
currentResponse = null;
break;
default:
throw new IOException("GHIDRA/decompiler alignment error");
}
if (buf == null) {
if (currentResponse == null) {
type = readToBurst();
}
else {
type = readToBuffer(buf);
type = readToBuffer(currentResponse);
}
}
return retbuf;
}
// Calls to the decompiler
@ -436,16 +406,20 @@ public class DecompileProcess {
* @param cspecxml = string containing .cspec xml
* @param tspecxml = XML string containing translator spec
* @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 DecompileException for problems executing the command
*/
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 {
callback = cback;
programSource = program.getName();
resultEncoder = new PackedEncode();
paramDecoder = new PackedDecode(program.getAddressFactory());
StringIngest response = new StringIngest(); // Don't use stringResponse
setup();
String restring = null;
try {
write(command_start);
writeString("registerProgram");
@ -454,13 +428,13 @@ public class DecompileProcess {
writeString(tspecxml);
writeString(coretypesxml);
write(command_end);
restring = readResponse().toString();
readResponse(response);
}
catch (IOException e) {
statusGood = false;
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
// used again
statusGood = false;
String restring = null;
write(command_start);
writeString("deregisterProgram");
writeString(Integer.toString(archId));
write(command_end);
restring = readResponse().toString();
StringIngest response = new StringIngest(); // Don't use stringResponse
readResponse(response);
int res = Integer.parseInt(response.toString());
callback = null;
int res = Integer.parseInt(restring);
programSource = null;
paramDecoder = null;
resultEncoder = null;
return res;
}
/**
* Send a single command to the decompiler with no parameters and return response
* @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 DecompileException for any problems executing the command
*/
public synchronized LimitedByteBuffer sendCommand(String command)
public synchronized void sendCommand(String command, ByteIngest response)
throws IOException, DecompileException {
if (!statusGood) {
throw new IOException(command + " called on bad process");
}
LimitedByteBuffer resbuf = null;
try {
write(command_start);
writeString(command);
writeString(Integer.toString(archId));
write(command_end);
resbuf = readResponse();
readResponse(response);
}
catch (IOException e) {
statusGood = false;
throw e;
}
return resbuf;
}
public synchronized boolean isReady() {
@ -520,20 +495,19 @@ public class DecompileProcess {
/**
* @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
* @return the response string
* @param response the response accumulator
* @throws IOException for any problems with the pipe to the decompiler process
* @throws DecompileException for any problems while executing the command
*/
public synchronized LimitedByteBuffer sendCommand1ParamTimeout(String command, String param,
int timeoutSecs) throws IOException, DecompileException {
public synchronized void sendCommand1ParamTimeout(String command, Encoder param,
int timeoutSecs, ByteIngest response) throws IOException, DecompileException {
if (!statusGood) {
throw new IOException(command + " called on bad process");
}
LimitedByteBuffer resbuf = null;
int validatedTimeoutMs = getTimeoutMs(timeoutSecs);
GTimerMonitor timerMonitor = GTimer.scheduleRunnable(validatedTimeoutMs, timeoutRunnable);
@ -543,7 +517,7 @@ public class DecompileProcess {
writeString(Integer.toString(archId));
writeString(param);
write(command_end);
resbuf = readResponse();
readResponse(response);
}
catch (IOException e) {
statusGood = false;
@ -556,7 +530,6 @@ public class DecompileProcess {
finally {
timerMonitor.cancel();
}
return resbuf;
}
private int getTimeoutMs(int timeoutSecs) {
@ -571,16 +544,15 @@ public class DecompileProcess {
* @param command string to send
* @param param1 is the first 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 DecompileException for problems executing the command
*/
public synchronized LimitedByteBuffer sendCommand2Params(String command, String param1,
String param2) throws IOException, DecompileException {
public synchronized void sendCommand2Params(String command, String param1, String param2,
ByteIngest response) throws IOException, DecompileException {
if (!statusGood) {
throw new IOException(command + " called on bad process");
}
LimitedByteBuffer resbuf = null;
try {
write(command_start);
writeString(command);
@ -588,15 +560,19 @@ public class DecompileProcess {
writeString(param1);
writeString(param2);
write(command_end);
resbuf = readResponse();
readResponse(response);
}
catch (IOException e) {
statusGood = false;
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) {
this.maxResultSizeMBYtes = maxResultSizeMBytes;
}
@ -604,64 +580,94 @@ public class DecompileProcess {
/**
* Send a command to the decompiler with one parameter and return the result
* @param command is the command string
* @param param1 is the parameter as a string
* @return the result string
* @param param1 is the encoded parameter
* @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 LimitedByteBuffer sendCommand1Param(String command, String param1)
public synchronized void sendCommand1Param(String command, Encoder param1, ByteIngest response)
throws IOException, DecompileException {
if (!statusGood) {
throw new IOException(command + " called on bad process");
}
LimitedByteBuffer resbuf = null;
try {
write(command_start);
writeString(command);
writeString(Integer.toString(archId));
writeString(param1);
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) {
statusGood = false;
throw e;
}
return resbuf;
}
// Calls from the decompiler
private void getRegister() throws IOException {
String name = readQueryString();
byte[] res = callback.getRegister(name);
private void getRegister() throws IOException, DecoderException {
resultEncoder.clear();
String name = paramDecoder.readString(ATTRIB_NAME);
callback.getRegister(name, resultEncoder);
write(query_response_start);
if (res.length != 0) {
writeBytes(res);
if (!resultEncoder.isEmpty()) {
writeString(resultEncoder);
}
write(query_response_end);
}
private void getRegisterName() throws IOException {
String addr = readQueryString();
private void getRegisterName() throws IOException, DecoderException {
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);
writeString(res);
write(query_response_end);
}
private void getTrackedRegisters() throws IOException {
String addr = readQueryString();
byte[] res = callback.getTrackedRegisters(addr);
private void getTrackedRegisters() throws IOException, DecoderException {
resultEncoder.clear();
Address addr = AddressXML.decode(paramDecoder);
callback.getTrackedRegisters(addr, resultEncoder);
write(query_response_start);
writeBytes(res);
writeString(resultEncoder);
write(query_response_end);
}
private void getUserOpName() throws IOException {
String indexStr = readQueryString();
String res = callback.getUserOpName(indexStr);
private void getUserOpName() throws IOException, DecoderException {
int index = (int) paramDecoder.readSignedInteger(ATTRIB_INDEX);
String res = callback.getUserOpName(index);
if (res == null) {
res = "";
}
@ -670,70 +676,72 @@ public class DecompileProcess {
write(query_response_end);
}
private void getPcodePacked() throws IOException {
String addr = readQueryString();
PackedBytes out = callback.getPcodePacked(addr);
private void getPcode() throws IOException, DecoderException {
resultEncoder.clear();
Address addr = AddressXML.decode(paramDecoder);
callback.getPcode(addr, resultEncoder);
write(query_response_start);
if ((out != null) && (out.size() != 0)) {
writeBytes(out);
if (!resultEncoder.isEmpty()) {
writeString(resultEncoder);
}
write(query_response_end);
}
private void getPcodeInject(int type) throws IOException {
String name = readQueryString();
String context = readQueryString();
byte[] res = callback.getPcodeInject(name, context, type);
private void getPcodeInject(int type) throws IOException, DecoderException {
resultEncoder.clear();
String name = paramDecoder.readString(ATTRIB_NAME);
callback.getPcodeInject(name, paramDecoder, type, resultEncoder);
write(query_response_start);
if (res.length != 0) {
writeBytes(res);
if (!resultEncoder.isEmpty()) {
writeString(resultEncoder);
}
write(query_response_end);
}
private void getCPoolRef() throws IOException {
String liststring = readQueryString();
String[] split = liststring.split(",");
long[] refs = new long[split.length];
for (int i = 0; i < split.length; ++i) {
refs[i] = Long.parseUnsignedLong(split[i], 16);
private void getCPoolRef() throws IOException, DecoderException {
resultEncoder.clear();
int size = (int) paramDecoder.readSignedInteger(ATTRIB_SIZE);
long refs[] = new long[size];
for (int i = 0; i < size; ++i) {
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);
if (res.length != 0) {
writeBytes(res);
if (!resultEncoder.isEmpty()) {
writeString(resultEncoder);
}
write(query_response_end);
}
private void getMappedSymbolsXML() throws IOException {
String addr = readQueryString();
private void getMappedSymbols() throws IOException, DecoderException {
resultEncoder.clear();
Address addr = AddressXML.decode(paramDecoder);
callback.getMappedSymbols(addr, resultEncoder);
byte[] res = callback.getMappedSymbolsXML(addr);
write(query_response_start);
if (res.length != 0) {
writeBytes(res);
if (!resultEncoder.isEmpty()) {
writeString(resultEncoder);
}
write(query_response_end);
}
private void getNamespacePath() throws IOException {
String idString = readQueryString();
long id = Long.parseLong(idString, 16);
byte[] res = callback.getNamespacePath(id);
private void getNamespacePath() throws IOException, DecoderException {
resultEncoder.clear();
long id = paramDecoder.readUnsignedInteger(ATTRIB_ID);
callback.getNamespacePath(id, resultEncoder);
write(query_response_start);
if (res.length != 0) {
writeBytes(res);
if (!resultEncoder.isEmpty()) {
writeString(resultEncoder);
}
write(query_response_end);
}
private void isNameUsed() throws IOException {
String name = readQueryString();
String startString = readQueryString();
String stopString = readQueryString();
long startId = Long.parseLong(startString, 16);
long stopId = Long.parseLong(stopString, 16);
private void isNameUsed() throws IOException, DecoderException {
String name = paramDecoder.readString(ATTRIB_NAME);
long startId = paramDecoder.readUnsignedInteger(ATTRIB_FIRST);
long stopId = paramDecoder.readUnsignedInteger(ATTRIB_LAST);
boolean res = callback.isNameUsed(name, startId, stopId);
write(query_response_start);
write(string_start);
@ -742,20 +750,20 @@ public class DecompileProcess {
write(query_response_end);
}
private void getExternalRefXML() throws IOException {
String refaddr = readQueryString();
byte[] res = callback.getExternalRefXML(refaddr);
private void getExternalRef() throws IOException, DecoderException {
resultEncoder.clear();
Address addr = AddressXML.decode(paramDecoder);
callback.getExternalRef(addr, resultEncoder);
write(query_response_start);
if (res.length != 0) {
writeBytes(res);
if (!resultEncoder.isEmpty()) {
writeString(resultEncoder);
}
write(query_response_end);
}
private void getSymbol() throws IOException {
String addr = readQueryString();
String res = callback.getSymbol(addr);
private void getCodeLabel() throws IOException, DecoderException {
Address addr = AddressXML.decode(paramDecoder);
String res = callback.getCodeLabel(addr);
if (res == null) {
res = "";
}
@ -764,29 +772,35 @@ public class DecompileProcess {
write(query_response_end);
}
private void getComments() throws IOException {
String addr = readQueryString();
String flags = readQueryString();
byte[] res = callback.getComments(addr, flags);
private void getComments() throws IOException, DecoderException {
resultEncoder.clear();
int types = (int) paramDecoder.readUnsignedInteger(ATTRIB_TYPE);
Address addr = AddressXML.decode(paramDecoder);
callback.getComments(addr, types, resultEncoder);
write(query_response_start);
writeBytes(res);
writeString(resultEncoder);
write(query_response_end);
}
private void getType() throws IOException {
String name = readQueryString();
long id = SpecXmlUtils.decodeLong(readQueryString());
byte[] res = callback.getType(name, id);
private void getDataType() throws IOException, DecoderException {
resultEncoder.clear();
String name = paramDecoder.readString(ATTRIB_NAME);
long id = paramDecoder.readSignedInteger(ATTRIB_ID);
callback.getDataType(name, id, resultEncoder);
write(query_response_start);
if (res.length != 0) {
writeBytes(res);
if (!resultEncoder.isEmpty()) {
writeString(resultEncoder);
}
write(query_response_end);
}
private void getBytes() throws IOException {
String size = readQueryString();
byte[] res = callback.getBytes(size);
private void getBytes() throws IOException, DecoderException {
int el = paramDecoder.openElement(ELEM_ADDR);
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);
if ((res != null) && (res.length > 0)) {
write(byte_start);
@ -801,11 +815,13 @@ public class DecompileProcess {
write(query_response_end);
}
private void getStringData() throws IOException {
String addr = readQueryString();
String dtName = readQueryString();
long dtId = SpecXmlUtils.decodeLong(readQueryString());
DecompileCallback.StringData stringData = callback.getStringData(addr, dtName, dtId);
private void getStringData() throws IOException, DecoderException {
int maxChars = (int) paramDecoder.readSignedInteger(ATTRIB_MAXSIZE);
String dtName = paramDecoder.readString(ATTRIB_TYPE);
long dtId = paramDecoder.readUnsignedInteger(ATTRIB_ID);
Address addr = AddressXML.decode(paramDecoder);
DecompileCallback.StringData stringData =
callback.getStringData(addr, maxChars, dtName, dtId);
write(query_response_start);
if (stringData != null) {
byte[] res = stringData.byteData;

View File

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

View File

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

View File

@ -15,22 +15,21 @@
*/
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 ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.InstructionContext;
import ghidra.program.model.lang.PackedBytes;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.PcodeOverride;
import ghidra.program.model.pcode.*;
/**
*
*
*/
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 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;
/**
* Pcode emitter constructor for producing a packed binary representation
* for unimplemented or empty responses.
*/
public PcodeEmitPacked() {
super();
buf = new PackedBytes(64);
}
private boolean hasRelativePatch = false;
/**
* Pcode emitter constructor for producing a packed binary representation.
* @param encoder is the stream encoder to emit to
* @param walk parser walker
* @param ictx instruction contexts
* @param fallOffset default instruction fall offset (i.e., instruction length including delay slotted instructions)
* @param override required if pcode overrides are to be utilized
*/
public PcodeEmitPacked(ParserWalker walk, InstructionContext ictx, int fallOffset,
PcodeOverride override) {
public PcodeEmitPacked(PatchEncoder encoder, ParserWalker walk, InstructionContext ictx,
int fallOffset, PcodeOverride override) {
super(walk, ictx, fallOffset, override);
buf = new PackedBytes(512);
this.encoder = encoder;
}
public PackedBytes getPackedBytes() {
return buf;
public void emitHeader() throws IOException {
encoder.openElement(ELEM_INST);
encoder.writeSignedInteger(ATTRIB_OFFSET, getFallOffset());
AddressXML.encode(encoder, getStartAddress());
}
public void emitTail() throws IOException {
encoder.closeElement(ELEM_INST);
}
@Override
@ -90,8 +88,9 @@ public class PcodeEmitPacked extends PcodeEmit {
mask >>>= (8 - ref.labelSize) * 8;
res &= mask;
}
// We need to skip over op_tag, op_code, void_tag, addrsz_tag, and spc bytes
insertOffset(ref.streampos + 5, res); // Insert the final offset into the stream
if (!encoder.patchIntegerAttribute(ref.streampos, ATTRIB_OFFSET, res)) {
throw new SleighException("PcodeEmitPacked: Unable to patch relative offset");
}
}
}
@ -100,92 +99,60 @@ public class PcodeEmitPacked extends PcodeEmit {
*/
@Override
void addLabelRef() {
// We know we need to do patching on a particular input parameter
if (labelref == null) {
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 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
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
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);
checkOverlays(opcode, in, isize, out);
buf.write(op_tag);
buf.write(opcode + 0x20);
encoder.openElement(ELEM_OP);
encoder.writeSignedInteger(ATTRIB_CODE, opcode);
encoder.writeSignedInteger(ATTRIB_SIZE, isize);
if (out == null) {
buf.write(void_tag);
encoder.openElement(ELEM_VOID);
encoder.closeElement(ELEM_VOID);
}
else {
dumpVarnodeData(out);
out.encode(encoder);
}
int i = 0;
if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) {
dumpSpaceId(in[0]);
i = 1;
}
else if (hasRelativePatch) {
addLabelRefDelayed();
}
for (; i < isize; ++i) {
dumpVarnodeData(in[i]);
in[i].encode(encoder);
}
buf.write(end_tag);
encoder.closeElement(ELEM_OP);
}
private void dumpSpaceId(VarnodeData v) {
buf.write(spaceid_tag);
int spcindex = ((int) v.offset >> AddressSpace.ID_UNIQUE_SHIFT);
buf.write(spcindex + 0x20);
}
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");
private void dumpSpaceId(VarnodeData v) throws IOException {
encoder.openElement(ELEM_SPACEID);
encoder.writeSpaceId(ATTRIB_NAME, v.offset);
encoder.closeElement(ELEM_SPACEID);
}
}

View File

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

View File

@ -1,6 +1,5 @@
/* ###
* 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.
@ -20,15 +19,32 @@
*/
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.pcode.Encoder;
/**
*
*
* All the resolved pieces of data needed to build a Varnode
*/
public class VarnodeData {
public AddressSpace space;
public long offset;
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 void decode(Decoder decoder) throws PcodeXMLException {
public void decode(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_CONTEXT);
baseAddr = 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.AddressFactory;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.*;
import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.*;
@ -171,11 +170,7 @@ public class InjectPayloadSleigh implements InjectPayload {
setupParameters(context, walker);
emit.build(pcodeTemplate, -1);
}
catch (UnknownInstructionException e) { // Should not be happening in a CallFixup
e.printStackTrace();
return;
}
catch (MemoryAccessException e) { // Should not be happening in a CallFixup
catch (Exception e) { // Should not be happening in a CallFixup
e.printStackTrace();
return;
}
@ -236,8 +231,7 @@ public class InjectPayloadSleigh implements InjectPayload {
public void encode(Encoder encoder) throws IOException {
encoder.openElement(ELEM_PCODE);
if (type == CALLMECHANISM_TYPE && subType >= 0) {
encoder.writeString(ATTRIB_INJECT,
(subType == 0) ? "uponentry" : "uponreturn");
encoder.writeString(ATTRIB_INJECT, (subType == 0) ? "uponentry" : "uponreturn");
}
if (paramShift != 0) {
encoder.writeSignedInteger(ATTRIB_PARAMSHIFT, paramShift);

View File

@ -15,13 +15,13 @@
*/
package ghidra.program.model.lang;
import java.io.IOException;
import java.util.ArrayList;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.PcodeOverride;
import ghidra.program.model.pcode.*;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.FlowType;
import ghidra.program.model.symbol.RefType;
@ -293,12 +293,14 @@ public interface InstructionPrototype {
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 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -156,7 +156,7 @@ public class BlockGraph extends PcodeBlock {
}
@Override
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
BlockMap newresolver = new BlockMap(resolver);
super.decodeBody(decoder, newresolver);
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.
* @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());
decode(decoder, resolver);
resolver.resolveGotoReferences();

View File

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

View File

@ -59,7 +59,7 @@ public class BlockMultiGoto extends BlockGraph {
}
@Override
protected void decodeBody(Decoder decoder, BlockMap resolver) throws PcodeXMLException {
protected void decodeBody(Decoder decoder, BlockMap resolver) throws DecoderException {
super.decodeBody(decoder, resolver);
for (;;) {
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;
import java.io.InputStream;
import ghidra.program.model.address.AddressFactory;
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.
* This attribute will not be traversed by getNextAttributeId().
*/
public interface Decoder {
public interface Decoder extends ByteIngest {
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.
* The element id is returned, which can be compared to ElementId labels.
* If there are no remaining child elements to traverse, 0 is returned.
* @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.
* The child becomes the current parent.
* 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
* @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
@ -77,35 +61,36 @@ public interface Decoder {
* getNextAttributeId. The child must match the given element id or an exception is thrown.
* @param elemId is the given element id to match
* @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
* 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.
* @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.
* 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.
* @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
* 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.
* @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
@ -119,9 +104,9 @@ public interface Decoder {
* The last attribute, as returned by getNextAttributeId, is treated as a boolean, and its
* value is returned.
* @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
@ -131,18 +116,18 @@ public interface Decoder {
* Parsing via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match
* @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
* The last attribute, as returned by getNextAttributeId, is treated as a signed integer,
* and its value is returned.
* @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
@ -152,18 +137,18 @@ public interface Decoder {
* Parsing via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match
* @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
* The last attribute, as returned by getNextAttributeId, is treated as an unsigned integer,
* and its value is returned.
* @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
@ -173,17 +158,17 @@ public interface Decoder {
* Parsing via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match
* @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
* The last attribute, as returned by getNextAttributeId, is returned as a string.
* @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
@ -192,17 +177,17 @@ public interface Decoder {
* and exception is thrown. Parse via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match
* @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
* The last attribute, as returned by getNextAttributeId, is returned as an address space.
* @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
@ -211,16 +196,16 @@ public interface Decoder {
* exception is thrown. Parse via getNextAttributeId is reset.
* @param attribId is the specific attribute id to match
* @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
* 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();
closeElementSkipping(elemId);
}

View File

@ -1,6 +1,5 @@
/* ###
* 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.
@ -17,15 +16,14 @@
package ghidra.program.model.pcode;
/**
*
*
* Exception thrown when pcode cannot be restored from XML.
* Exception thrown for errors decoding decompiler objects from stream
*/
public class PcodeXMLException extends PcodeException {
public PcodeXMLException(String msg) {
super("XML comms: "+msg);
public class DecoderException extends PcodeException {
public DecoderException(String 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
public void decode(Decoder decoder) throws PcodeXMLException {
public void decode(Decoder decoder) throws DecoderException {
int addrel = decoder.openElement(ELEM_HASH);
hash = decoder.readUnsignedInteger(ATTRIB_VAL);
decoder.closeElement(addrel);

View File

@ -15,8 +15,6 @@
*/
package ghidra.program.model.pcode;
import java.util.HashMap;
/**
* An annotation for a specific collection of hierarchical data
*
@ -28,28 +26,28 @@ import java.util.HashMap;
* as an attribute.
*
* @param name unique element name
* @param id unqiue element ID
* @param id unique element 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 {
// add new element to lookup map
if (null != lookupElementId.put(name, this)) {
throw new RuntimeException("Duplicate ElementId instance: " + name);
}
}
// public ElementId {
// // add new element to lookup map
// if (null != lookupElementId.put(name, this)) {
// throw new RuntimeException("Duplicate ElementId instance: " + name);
// }
// }
/**
* Find the id associated with a specific element name
* @param nm the element name
* @return the associated id
*/
public static int find(String nm) {
ElementId res = lookupElementId.getOrDefault(nm, ELEM_UNKNOWN);
return res.id;
}
// /**
// * Find the id associated with a specific element name
// * @param nm the element name
// * @return the associated id
// */
// public static int find(String nm) {
// ElementId res = lookupElementId.getOrDefault(nm, ELEM_UNKNOWN);
// return res.id;
// }
public static final ElementId ELEM_DATA = new ElementId("data", 1);
public static final ElementId ELEM_INPUT = new ElementId("input", 2);
@ -364,5 +362,64 @@ public record ElementId(String name, int id) {
// raw_arch
// 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;
import java.io.IOException;
import java.io.OutputStream;
import ghidra.program.model.address.AddressSpace;
@ -102,8 +103,15 @@ public interface Encoder {
void writeSpace(AttributeId attribId, AddressSpace spc) throws IOException;
/**
* Return anything written to the encoder (since the last clear) as a byte array.
* @return the array of bytes
* Dump all the accumulated bytes in this encoder to the stream.
* @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
public void decode(Decoder decoder) throws PcodeXMLException {
public void decode(Decoder decoder) throws DecoderException {
int symel = decoder.openElement(ELEM_EQUATESYMBOL);
decodeHeader(decoder);
type = DataType.DEFAULT;

View File

@ -25,7 +25,6 @@ import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType;
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.
* @param decoder is the stream decoder
* @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)
throws PcodeXMLException {
throws DecoderException {
int node = decoder.openElement(ELEM_PROTOTYPE);
modelname = decoder.readString(ATTRIB_MODEL);
PrototypeModel protoModel =
dtmanage.getProgram().getCompilerSpec().getCallingConvention(modelname);
if (protoModel == null) {
throw new PcodeXMLException("Bad prototype model name: " + modelname);
throw new DecoderException("Bad prototype model name: " + modelname);
}
hasThis = protoModel.hasThisPointer();
String val = decoder.readString(ATTRIB_EXTRAPOP);
if (val.equals("unknown")) {
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
try {
extrapop = (int) decoder.readSignedInteger(ATTRIB_EXTRAPOP);
}
else {
extrapop = SpecXmlUtils.decodeInt(val);
catch (DecoderException e) {
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
}
modellock = false;
dotdotdot = false;

View File

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

View File

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

View File

@ -218,7 +218,7 @@ public class HighFunction extends PcodeSyntaxTree {
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);
String classstring = decoder.readString(ATTRIB_CLASS);
HighVariable var;
@ -239,13 +239,13 @@ public class HighFunction extends PcodeSyntaxTree {
var = new HighConstant(this);
break;
default:
throw new PcodeXMLException("Unknown HighVariable class string: " + classstring);
throw new DecoderException("Unknown HighVariable class string: " + classstring);
}
var.decode(decoder);
decoder.closeElement(el);
}
private void decodeHighlist(Decoder decoder) throws PcodeXMLException {
private void decodeHighlist(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_HIGHLIST);
while (decoder.peekElement() != 0) {
decodeHigh(decoder);
@ -254,11 +254,11 @@ public class HighFunction extends PcodeSyntaxTree {
}
@Override
public void decode(Decoder decoder) throws PcodeXMLException {
public void decode(Decoder decoder) throws DecoderException {
int start = decoder.openElement(ELEM_FUNCTION);
String name = decoder.readString(ATTRIB_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 (;;) {
int subel = decoder.peekElement();
@ -269,7 +269,7 @@ public class HighFunction extends PcodeSyntaxTree {
Address addr = AddressXML.decode(decoder);
addr = func.getEntryPoint().getAddressSpace().getOverlayAddress(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()) {
@ -298,7 +298,7 @@ public class HighFunction extends PcodeSyntaxTree {
decoder.skipElement();
}
else {
throw new PcodeXMLException("Unknown element in function");
throw new DecoderException("Unknown element in function");
}
}
decoder.closeElement(start);
@ -308,9 +308,9 @@ public class HighFunction extends PcodeSyntaxTree {
* Decode the Jump Table list for this function from the stream
*
* @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);
while (decoder.peekElement() != 0) {
JumpTable table = new JumpTable(func.getEntryPoint().getAddressSpace());
@ -422,7 +422,7 @@ public class HighFunction extends PcodeSyntaxTree {
return reslocal;
}
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
public void decode(Decoder decoder) throws PcodeXMLException {
public void decode(Decoder decoder) throws DecoderException {
// int el = decoder.openElement(ElementId.ELEM_HIGH);
long symref = 0;
offset = -1;
@ -90,7 +90,7 @@ public class HighGlobal extends HighVariable {
}
symbol = globalMap.newSymbol(symref, addr, symbolType, symbolSize);
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
public void decode(Decoder decoder) throws PcodeXMLException {
public void decode(Decoder decoder) throws DecoderException {
//int el = decoder.openElement(ElementId.ELEM_HIGH);
long symref = decoder.readUnsignedInteger(AttributeId.ATTRIB_SYMREF);
offset = -1;
@ -60,14 +60,14 @@ public class HighLocal extends HighVariable {
break;
}
if (attribId == AttributeId.ATTRIB_OFFSET.id()) {
offset = (int) decoder.readUnsignedInteger();
offset = (int) decoder.readSignedInteger();
break;
}
}
decodeInstances(decoder);
symbol = function.getLocalSymbolMap().getSymbol(symref);
if (symbol == null) {
throw new PcodeXMLException("HighLocal is missing symbol");
throw new DecoderException("HighLocal is missing symbol");
}
if (offset < 0) {
name = symbol.getName();

View File

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

View File

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

View File

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

View File

@ -392,7 +392,7 @@ public class HighSymbol {
}
encoder.writeSignedInteger(ATTRIB_CAT, category);
if (categoryIndex >= 0) {
encoder.writeSignedInteger(ATTRIB_INDEX, categoryIndex);
encoder.writeUnsignedInteger(ATTRIB_INDEX, categoryIndex);
}
}
@ -408,7 +408,7 @@ public class HighSymbol {
encoder.closeElement(ELEM_SYMBOL);
}
protected void decodeHeader(Decoder decoder) throws PcodeXMLException {
protected void decodeHeader(Decoder decoder) throws DecoderException {
name = null;
id = 0;
typelock = false;
@ -449,16 +449,16 @@ public class HighSymbol {
}
}
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.
* @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);
decodeHeader(decoder);
type = dtmanage.decodeDataType(decoder);
@ -498,7 +498,7 @@ public class HighSymbol {
entryList[0] = new MappedEntry(this, newStorage, entry.getPCAdress());
}
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 high is the function model that will own 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)
throws PcodeXMLException {
throws DecoderException {
HighSymbol res = null;
int mapel = decoder.openElement(ELEM_MAPSYM);
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.
* The "representative" Varnode is also populated.
* @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);
Varnode rep = function.getRef(repref);
if (rep == null) {
throw new PcodeXMLException("Undefined varnode reference");
throw new DecoderException("Undefined varnode reference");
}
type = null;
@ -188,7 +188,7 @@ public abstract class HighVariable {
/**
* Decode this HighVariable from a {@code <high>} element in the stream
* @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;
}
public void decode(Decoder decoder) throws PcodeXMLException {
public void decode(Decoder decoder) throws DecoderException {
int el = decoder.openElement(ELEM_LOADTABLE);
size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
num = (int) decoder.readSignedInteger(ATTRIB_NUM);
@ -160,9 +160,9 @@ public class JumpTable {
/**
* Decode a JumpTable object from the stream.
* @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);
if (decoder.peekElement() == 0) { // Empty jumptable
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.
* @param decoder is the stream decoder
* @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);
insertSymbol(res);
return res;
@ -277,9 +277,9 @@ public class LocalSymbolMap {
* Decode a local symbol scope from the stream
*
* @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);
localSpace = decoder.readSpace(ATTRIB_MAIN);
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
* @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);
ArrayList<HighSymbol> parms = new ArrayList<>();
while (decoder.peekElement() != 0) {

View File

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

View File

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

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