mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Candidate release of source code.
This commit is contained in:
parent
db81e6b3b0
commit
79d8f164f8
12449 changed files with 2800756 additions and 16 deletions
723
Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc
Normal file
723
Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc
Normal file
|
@ -0,0 +1,723 @@
|
|||
/* ###
|
||||
* 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 "ghidra_context.hh"
|
||||
#include "loadimage_ghidra.hh"
|
||||
#include "database_ghidra.hh"
|
||||
#include "ghidra_translate.hh"
|
||||
#include "typegrp_ghidra.hh"
|
||||
#include "comment_ghidra.hh"
|
||||
#include "cpool_ghidra.hh"
|
||||
#include "inject_ghidra.hh"
|
||||
|
||||
/// 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)
|
||||
|
||||
{
|
||||
exit(1); // Just die - prevents OS from popping-up a dialog
|
||||
}
|
||||
|
||||
/// All communications between the Ghidra client and the decompiler are surrounded
|
||||
/// by alignment bursts. A burst is 1 or more zero bytes followed by
|
||||
/// an 0x01 byte, then followed by a code byte.
|
||||
/// Open alignment (as in open paren) is even. Close alignment is odd.
|
||||
/// Code bytes are as follows:
|
||||
/// - Command open=2 close=3
|
||||
/// - Query open=4 close=5
|
||||
/// - Command response open=6 close=7
|
||||
/// - Query response open=8 close=9
|
||||
/// - Exception open=a close=b
|
||||
/// - Byte stream open=c close=d
|
||||
/// - String stream open=e close=f
|
||||
///
|
||||
/// The protocol is as follows:
|
||||
/// - ghidra sends a command
|
||||
/// - [ decompiler sends a query
|
||||
/// - ghidra sends a query response ] zero or more occurences
|
||||
/// - decompiler sends a command response
|
||||
///
|
||||
/// Commands, queries, and responses all consist of zero or more string streams or byte
|
||||
/// streams.
|
||||
///
|
||||
/// In place of any response an exception can be sent.
|
||||
/// The decompiler can interrupt a command response with a query or exception
|
||||
/// once the query is finished the response picks up where it left off
|
||||
/// an exception however permanently cancels the query.
|
||||
/// Ghidra cannot interrupt either of its responses.
|
||||
/// \param s is the input stream from the client
|
||||
/// \return the command code
|
||||
int4 ArchitectureGhidra::readToAnyBurst(istream &s)
|
||||
|
||||
{
|
||||
int4 c;
|
||||
|
||||
for(;;) {
|
||||
do {
|
||||
c = s.get();
|
||||
} while(c>0);
|
||||
while(c==0) {
|
||||
c = s.get();
|
||||
}
|
||||
if (c==1) {
|
||||
c = s.get();
|
||||
return c;
|
||||
}
|
||||
if (c<0) // If pipe closed, our parent process is probably dead
|
||||
exit(1); // So we exit to avoid a runaway process
|
||||
}
|
||||
}
|
||||
|
||||
/// Characters are read up to the next protocol marked and placed into a string.
|
||||
/// The protocol marker is consumed and must indicate the end of a string
|
||||
/// or an exception is thrown.
|
||||
/// \param s is the input stream from the client
|
||||
/// \param res will hold the string
|
||||
void ArchitectureGhidra::readStringStream(istream &s,string &res)
|
||||
|
||||
{
|
||||
int4 c;
|
||||
|
||||
int4 type = readToAnyBurst(s);
|
||||
if (type != 14) throw JavaError("alignment","Expecting string");
|
||||
c = s.get();
|
||||
while(c > 0) {
|
||||
res += (char)c;
|
||||
c = s.get();
|
||||
}
|
||||
while(c==0) {
|
||||
c = s.get();
|
||||
}
|
||||
if (c==1) {
|
||||
c = s.get();
|
||||
if (c == 15) return;
|
||||
}
|
||||
if (c<0) // If pipe closed, our parent process is probably dead
|
||||
exit(1); // So we exit to avoid a runaway process
|
||||
throw JavaError("alignment","Expecting string terminator");
|
||||
}
|
||||
|
||||
/// The method expects to see protocol markers indicating a string from the client,
|
||||
/// otherwise it throws and exception. The string is read in and then parsed as XML.
|
||||
/// \param s is the input stream from the client.
|
||||
/// \return the XML document
|
||||
Document *ArchitectureGhidra::readXMLStream(istream &s)
|
||||
|
||||
{
|
||||
int4 type = readToAnyBurst(s);
|
||||
if (type==14) {
|
||||
Document *doc = xml_tree(s);
|
||||
type = readToAnyBurst(s);
|
||||
if (type!=15)
|
||||
throw JavaError("alignment","Expecting XML string end");
|
||||
return doc;
|
||||
}
|
||||
if ((type&1)==1)
|
||||
return (Document *)0;
|
||||
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
|
||||
void ArchitectureGhidra::writeStringStream(ostream &s,const string &msg)
|
||||
|
||||
{
|
||||
s.write("\000\000\001\016",4);
|
||||
s << msg;
|
||||
s.write("\000\000\001\017",4);
|
||||
}
|
||||
|
||||
/// Consume the query response header. If it indicates an exception,
|
||||
/// read details of the exception and throw JavaError.
|
||||
/// \param s is the input stream from the client
|
||||
void ArchitectureGhidra::readToResponse(istream &s)
|
||||
|
||||
{
|
||||
int4 type = readToAnyBurst(s);
|
||||
if (type==8) return;
|
||||
if (type==10) {
|
||||
string excepttype,message;
|
||||
readStringStream(s,excepttype);
|
||||
readStringStream(s,message);
|
||||
type = readToAnyBurst(s); // This should be the exception terminator
|
||||
throw JavaError(excepttype,message);
|
||||
}
|
||||
throw JavaError("alignment","Expecting query response");
|
||||
}
|
||||
|
||||
/// Read the next protocol marker. If it does not indicate the end of
|
||||
/// a query response, throw an exception
|
||||
/// \param s is the input stream from the client
|
||||
void ArchitectureGhidra::readResponseEnd(istream &s)
|
||||
|
||||
{
|
||||
int4 type = readToAnyBurst(s);
|
||||
if (type != 9)
|
||||
throw JavaError("alignment","Expecting end of query response");
|
||||
}
|
||||
|
||||
/// Read up to the beginning of a query response, check for an
|
||||
/// exception record, otherwise read in a string as an XML document.
|
||||
/// \param s is the input stream from the client
|
||||
/// \return the XML document
|
||||
Document *ArchitectureGhidra::readXMLAll(istream &s)
|
||||
|
||||
{
|
||||
readToResponse(s);
|
||||
Document *doc = readXMLStream(s);
|
||||
if (doc != (Document *)0)
|
||||
readResponseEnd(s);
|
||||
return doc;
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// message protocol and lets the client know to abort (and hopefully resync)
|
||||
/// \param s is the output stream to the client
|
||||
/// \param tp is the type of exception
|
||||
/// \param msg is the exception message
|
||||
void ArchitectureGhidra::passJavaException(ostream &s,const string &tp,const string &msg)
|
||||
|
||||
{
|
||||
s.write("\000\000\001\012",4);
|
||||
writeStringStream(s,tp);
|
||||
writeStringStream(s,msg);
|
||||
s.write("\000\000\001\013",4);
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::buildSpecFile(DocumentStorage &store)
|
||||
|
||||
{ // Spec files are passed as XML strings from GHIDRA
|
||||
istringstream pstream(pspecxml); // Convert string to stream
|
||||
Document *doc = store.parseDocument(pstream); // parse stream
|
||||
store.registerTag(doc->getRoot());
|
||||
|
||||
istringstream cstream(cspecxml);
|
||||
doc = store.parseDocument(cstream);
|
||||
store.registerTag(doc->getRoot());
|
||||
|
||||
istringstream tstream(tspecxml);
|
||||
doc = store.parseDocument(tstream);
|
||||
store.registerTag(doc->getRoot());
|
||||
|
||||
istringstream corestream(corespecxml);
|
||||
doc = store.parseDocument(corestream);
|
||||
store.registerTag(doc->getRoot());
|
||||
|
||||
pspecxml = ""; // Strings aren't used again free memory
|
||||
cspecxml = "";
|
||||
tspecxml = "";
|
||||
corespecxml = "";
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::postSpecFile(void)
|
||||
|
||||
{
|
||||
ScopeGhidra *scopeGhidra = (ScopeGhidra *)symboltab->getGlobalScope();
|
||||
scopeGhidra->lockDefaultProperties();
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::buildLoader(DocumentStorage &store)
|
||||
|
||||
{
|
||||
loader = new LoadImageGhidra(this);
|
||||
}
|
||||
|
||||
PcodeInjectLibrary *ArchitectureGhidra::buildPcodeInjectLibrary(void)
|
||||
|
||||
{
|
||||
return new PcodeInjectLibraryGhidra(this);
|
||||
}
|
||||
|
||||
Translate *ArchitectureGhidra::buildTranslator(DocumentStorage &store)
|
||||
|
||||
{
|
||||
return new GhidraTranslate(this);
|
||||
}
|
||||
|
||||
Scope *ArchitectureGhidra::buildGlobalScope(void)
|
||||
|
||||
{
|
||||
Scope *globalscope = symboltab->getGlobalScope();
|
||||
if (globalscope == (Scope *)0) { // Make sure global scope exists
|
||||
globalscope = new ScopeGhidra(this);
|
||||
symboltab->attachScope(globalscope,(Scope *)0);
|
||||
}
|
||||
return globalscope;
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::buildTypegrp(DocumentStorage &store)
|
||||
|
||||
{
|
||||
const Element *el = store.getTag("coretypes");
|
||||
types = new TypeFactoryGhidra(this);
|
||||
if (el != (const Element *)0)
|
||||
types->restoreXmlCoreTypes(el);
|
||||
else {
|
||||
// Put in the core types
|
||||
types->setCoreType("void",1,TYPE_VOID,false);
|
||||
types->setCoreType("bool",1,TYPE_BOOL,false);
|
||||
types->setCoreType("byte",1,TYPE_UINT,false);
|
||||
types->setCoreType("word",2,TYPE_UINT,false);
|
||||
types->setCoreType("dword",4,TYPE_UINT,false);
|
||||
types->setCoreType("qword",8,TYPE_UINT,false);
|
||||
types->setCoreType("char",1,TYPE_INT,true);
|
||||
types->setCoreType("sbyte",1,TYPE_INT,false);
|
||||
types->setCoreType("sword",2,TYPE_INT,false);
|
||||
types->setCoreType("sdword",4,TYPE_INT,false);
|
||||
types->setCoreType("sqword",8,TYPE_INT,false);
|
||||
types->setCoreType("float",4,TYPE_FLOAT,false);
|
||||
types->setCoreType("float8",8,TYPE_FLOAT,false);
|
||||
types->setCoreType("float16",16,TYPE_FLOAT,false);
|
||||
types->setCoreType("undefined",1,TYPE_UNKNOWN,false);
|
||||
types->setCoreType("undefined2",2,TYPE_UNKNOWN,false);
|
||||
types->setCoreType("undefined4",4,TYPE_UNKNOWN,false);
|
||||
types->setCoreType("undefined8",8,TYPE_UNKNOWN,false);
|
||||
types->setCoreType("code",1,TYPE_CODE,false);
|
||||
types->setCoreType("wchar",2,TYPE_INT,true);
|
||||
types->cacheCoreTypes();
|
||||
}
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::buildCommentDB(DocumentStorage &store)
|
||||
|
||||
{
|
||||
commentdb = new CommentDatabaseGhidra(this);
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::buildConstantPool(DocumentStorage &store)
|
||||
|
||||
{
|
||||
cpool = new ConstantPoolGhidra(this);
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::buildContext(DocumentStorage &store)
|
||||
|
||||
{
|
||||
context = new ContextGhidra(this);
|
||||
}
|
||||
|
||||
void ArchitectureGhidra::resolveArchitecture(void)
|
||||
|
||||
{
|
||||
archid = "ghidra";
|
||||
}
|
||||
|
||||
/// Ask the Ghidra client if it knows about a specific processor register.
|
||||
/// The client responds with a \<addr> XML element describing the storage
|
||||
/// location of the register.
|
||||
/// \param regname is the name to query for
|
||||
/// \return the storage address as XML or NULL if the register is unknown
|
||||
Document *ArchitectureGhidra::getRegister(const string ®name)
|
||||
|
||||
{
|
||||
sout.write("\000\000\001\004",4);
|
||||
writeStringStream(sout,"getRegister");
|
||||
writeStringStream(sout,regname);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
/// Given a storage location and size, ask the Ghidra client if it knows of
|
||||
/// a register that occupies those bytes. The register name is passed back.
|
||||
/// The name may not exactly match the given memory range, it may contain it.
|
||||
/// \param vndata is the location and size
|
||||
/// \return the register name or ""
|
||||
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);
|
||||
addr.saveXml(sout,vndata.size);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
readToResponse(sin);
|
||||
string res;
|
||||
readStringStream(sin,res);
|
||||
readResponseEnd(sin);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// The Ghidra client will return a description of registers that have
|
||||
/// known values at the given address. The response is generally a
|
||||
/// \<tracked_pointset> which contains \<set> children which contains
|
||||
/// a storage location and value.
|
||||
/// \param addr is the given address
|
||||
/// \return the response Document
|
||||
Document *ArchitectureGhidra::getTrackedRegisters(const Address &addr)
|
||||
|
||||
{
|
||||
sout.write("\000\000\001\004",4);
|
||||
writeStringStream(sout,"getTrackedRegisters");
|
||||
sout.write("\000\000\001\016",4); // Beginning of string header
|
||||
addr.saveXml(sout);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
/// The first operand to a CALLOTHER op indicates the specific user-defined op.
|
||||
/// This method queries the Ghidra client and passes back the name of the op.
|
||||
/// \param index is the value of the CALLOTHER operand
|
||||
/// \return the recovered name or ""
|
||||
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;
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
readToResponse(sin);
|
||||
string res;
|
||||
readStringStream(sin,res);
|
||||
readResponseEnd(sin);
|
||||
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)
|
||||
/// \param addr is the address of the instruction
|
||||
/// \return an array of the packed data
|
||||
uint1 *ArchitectureGhidra::getPcodePacked(const Address &addr)
|
||||
|
||||
{
|
||||
sout.write("\000\000\001\004",4);
|
||||
writeStringStream(sout,"getPacked");
|
||||
sout.write("\000\000\001\016",4); // Beginning of string header
|
||||
addr.saveXml(sout);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readPackedAll(sin);
|
||||
}
|
||||
|
||||
/// The Ghidra client will return a \<symbol> tag, \<function> tag, or some
|
||||
/// other related Symbol information. If there no symbol at the address
|
||||
/// the client should return a \<hole> tag describing the size of the
|
||||
/// memory region that is free of symbols.
|
||||
/// \param addr is the given address
|
||||
/// \return the symbol document
|
||||
Document *ArchitectureGhidra::getMappedSymbolsXML(const Address &addr)
|
||||
|
||||
{
|
||||
sout.write("\000\000\001\004",4);
|
||||
writeStringStream(sout,"getMappedSymbolsXML");
|
||||
sout.write("\000\000\001\016",4); // Beginning of string header
|
||||
addr.saveXml(sout);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
/// This asks the Ghidra client to resolve an \e external \e reference.
|
||||
/// This is an address for which the client holds a reference to a function
|
||||
/// that is elsewhere in memory or not in memory at all. The client
|
||||
/// should unravel the reference from the given address and return either
|
||||
/// a \<function> tag describing the referred to function symbol or
|
||||
/// a \<hole> tag if the reference can't be resolved
|
||||
/// \param addr is the given address
|
||||
/// \return a description of the referred to function
|
||||
Document *ArchitectureGhidra::getExternalRefXML(const Address &addr)
|
||||
|
||||
{
|
||||
sout.write("\000\000\001\004",4);
|
||||
writeStringStream(sout,"getExternalRefXML");
|
||||
sout.write("\000\000\001\016",4); // Beginning of string header
|
||||
addr.saveXml(sout);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
/// Get the name of the primary symbol at the given address.
|
||||
/// This is used to fetch within function \e labels. Only a name is returned.
|
||||
/// \param addr is the given address
|
||||
/// \return the symbol name or ""
|
||||
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
|
||||
addr.saveXml(sout);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
readToResponse(sin);
|
||||
string res;
|
||||
readStringStream(sin,res);
|
||||
readResponseEnd(sin);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// The Ghidra client should respond with a \<type> tag giving details
|
||||
/// about the data-type.
|
||||
/// \param name is the name of the data-type
|
||||
/// \param id is a unique id associated with the data-type, pass 0 if unknown
|
||||
/// \return the data-type XML element or NULL
|
||||
Document *ArchitectureGhidra::getType(const string &name,uint8 id)
|
||||
|
||||
{
|
||||
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
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
/// Ask Ghidra client for all comments associated with one function.
|
||||
/// The caller must provide the sub-set of properties (Comment::comment_type) for
|
||||
/// the query to match. The client will return a \<commentdb> tag with
|
||||
/// a \<comment> tag child for each comment found.
|
||||
/// \param fad is the address of the function to query
|
||||
/// \param flags specifies the properties the query will match (must be non-zero)
|
||||
/// \return an XML document describing each comment
|
||||
Document *ArchitectureGhidra::getComments(const Address &fad,uint4 flags)
|
||||
|
||||
{
|
||||
sout.write("\000\000\001\004",4);
|
||||
writeStringStream(sout,"getComments");
|
||||
sout.write("\000\000\001\016",4); // Beginning of string header
|
||||
fad.saveXml(sout);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\016",4); // Beginning of string header
|
||||
sout << dec << flags;
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
/// The Ghidra client is queried for a range of bytes, which are returned
|
||||
/// in the given array. This method throws a DataUnavailError if the provided
|
||||
/// address doesn't make sense.
|
||||
/// \param buf is the preallocated array in which to store the bytes
|
||||
/// \param size is the number of bytes requested
|
||||
/// \param inaddr is the address in the LoadImage from which to grab bytes
|
||||
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
|
||||
inaddr.saveXml(sout,size);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
readToResponse(sin);
|
||||
int4 type = readToAnyBurst(sin);
|
||||
if (type == 12) {
|
||||
uint1 *dblbuf = new uint1[size * 2];
|
||||
sin.read((char *)dblbuf,size*2);
|
||||
for (int4 i=0; i < size; i++) {
|
||||
buf[i] = ((dblbuf[i*2]-'A') << 4) | (dblbuf[i*2 + 1]-'A');
|
||||
}
|
||||
delete [] dblbuf;
|
||||
}
|
||||
else if ((type&1)==1) {
|
||||
ostringstream errmsg;
|
||||
errmsg << "GHIDRA has no data in the loadimage at " << inaddr.getShortcut();
|
||||
inaddr.printRaw(errmsg);
|
||||
throw DataUnavailError(errmsg.str());
|
||||
}
|
||||
else
|
||||
throw JavaError("alignment","Expecting bytes or end of query response");
|
||||
type = readToAnyBurst(sin);
|
||||
if (type != 13)
|
||||
throw JavaError("alignment","Expecting byte alignment end");
|
||||
readResponseEnd(sin);
|
||||
}
|
||||
|
||||
/// \brief Retrieve p-code to inject for a specific context
|
||||
///
|
||||
/// The particular injection is named and is of one of the types:
|
||||
/// - CALLFIXUP_TYPE
|
||||
/// - CALLOTHERFIXUP_TYPE
|
||||
/// - CALLMECHANISM_TYPE
|
||||
/// - EXECUTABLEPCODE_TYPE
|
||||
///
|
||||
/// This and additional context is provided to the Ghidra client which returns
|
||||
/// an XML document describing the p-code. The document will be an \<inst> tag
|
||||
/// containing individual \<op> tags corresponding to individual p-code ops.
|
||||
/// \param name is the name of the injection
|
||||
/// \param type is the type of injection
|
||||
/// \param con is the context object
|
||||
/// \return an XML document describing the p-code ops to inject
|
||||
Document *ArchitectureGhidra::getPcodeInject(const string &name,int4 type,const InjectContext &con)
|
||||
|
||||
{
|
||||
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);
|
||||
con.saveXml(sout);
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
/// The Ghidra client is provided a sequence of 1 or more integer values
|
||||
/// extracted from a CPOOLREF op. It returns an XML document describing
|
||||
/// the constant pool record referenced by the integer(s) or will throw
|
||||
/// an exception if record isn't properly referenced.
|
||||
/// \param refs is an array of 1 or more integer values referencing a constant pool record
|
||||
/// \return a description of the record as a \<cpoolrec> XML document.
|
||||
Document *ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs)
|
||||
|
||||
{
|
||||
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];
|
||||
}
|
||||
sout.write("\000\000\001\017",4);
|
||||
sout.write("\000\000\001\005",4);
|
||||
sout.flush();
|
||||
|
||||
return readXMLAll(sin);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
{
|
||||
warnings += '\n'+message;
|
||||
}
|
||||
|
||||
/// \brief Construct given specification files and i/o streams
|
||||
///
|
||||
/// \param pspec is the processor specification presented as an XML string
|
||||
/// \param cspec is the compiler specification presented as an XML string
|
||||
/// \param tspec is a stripped down form of the SLEIGH specification presented as an XML string
|
||||
/// \param corespec is a list of core data-types presented as a \<coretypes> XML tag
|
||||
/// \param i is the input stream from the Ghidra client
|
||||
/// \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)
|
||||
|
||||
{
|
||||
print->setXML(true);
|
||||
print->setOutputStream(&sout);
|
||||
pspecxml = pspec;
|
||||
cspecxml = cspec;
|
||||
tspecxml = tspec;
|
||||
corespecxml = corespec;
|
||||
sendsyntaxtree = true; // Default to sending everything
|
||||
sendCcode = true;
|
||||
sendParamMeasures = false;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue