mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-12-04 10:01:52 +00:00
GP-2358 Packed protocol for decompiler marshaling
This commit is contained in:
parent
6a1a649213
commit
79c3508f54
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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) {
|
||||
|
@ -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 ®name,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);
|
||||
|
@ -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_..
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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(); }
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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> ®list) 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);
|
||||
}
|
@ -31,7 +31,7 @@ public:
|
||||
static void build(void);
|
||||
};
|
||||
|
||||
TypeTestEnvironment theEnviron;
|
||||
static TypeTestEnvironment theEnviron;
|
||||
|
||||
TypeTestEnvironment::TypeTestEnvironment(void)
|
||||
|
||||
|
@ -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("");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 (;;) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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()) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 (;;) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -265,9 +265,9 @@ public class LocalSymbolMap {
|
||||
* Decode a <mapsym> 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 <symbollist> and <mapsym> 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) {
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user