mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
178 lines
5 KiB
C++
178 lines
5 KiB
C++
/* ###
|
|
* 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_translate.hh"
|
|
#include "funcdata.hh"
|
|
|
|
namespace ghidra {
|
|
|
|
/// \brief Associate a Varnode with a register name
|
|
///
|
|
/// \param nm is the register name
|
|
/// \param data is the Varnode description
|
|
/// \return a reference to the cached VarnodeData
|
|
const VarnodeData &GhidraTranslate::cacheRegister(const string &nm,const VarnodeData &data) const
|
|
|
|
{
|
|
VarnodeData &res(nm2addr[nm]);
|
|
res = data;
|
|
addr2nm[data] = nm;
|
|
return res;
|
|
}
|
|
|
|
void GhidraTranslate::initialize(DocumentStorage &store)
|
|
|
|
{
|
|
const Element *el = store.getTag("sleigh");
|
|
if (el == (const Element *)0)
|
|
throw LowlevelError("Could not find ghidra sleigh tag");
|
|
XmlDecode decoder(this,el);
|
|
decode(decoder);
|
|
}
|
|
|
|
const VarnodeData &GhidraTranslate::getRegister(const string &nm) const
|
|
|
|
{
|
|
map<string,VarnodeData>::const_iterator iter = nm2addr.find(nm);
|
|
if (iter != nm2addr.end())
|
|
return (*iter).second;
|
|
PackedDecode decoder(glb);
|
|
try {
|
|
if (!glb->getRegister(nm,decoder)) // Ask Ghidra client about the register
|
|
throw LowlevelError("No register named "+nm);
|
|
}
|
|
catch(DecoderError &err) {
|
|
ostringstream errmsg;
|
|
errmsg << "Error decoding response for query of register: " << nm;
|
|
errmsg << " -- " << err.explain;
|
|
throw LowlevelError(errmsg.str());
|
|
}
|
|
Address regaddr;
|
|
int4 regsize;
|
|
regaddr = Address::decode( decoder, regsize);
|
|
VarnodeData vndata;
|
|
vndata.space = regaddr.getSpace();
|
|
vndata.offset = regaddr.getOffset();
|
|
vndata.size = regsize;
|
|
return cacheRegister(nm,vndata);
|
|
}
|
|
|
|
string GhidraTranslate::getRegisterName(AddrSpace *base,uintb off,int4 size) const
|
|
|
|
{
|
|
if (base->getType() != IPTR_PROCESSOR) return "";
|
|
VarnodeData vndata;
|
|
vndata.space = base;
|
|
vndata.offset = off;
|
|
vndata.size = size;
|
|
map<VarnodeData,string>::const_iterator iter = addr2nm.find(vndata);
|
|
if (iter != addr2nm.end())
|
|
return (*iter).second;
|
|
string res = glb->getRegisterName(vndata);
|
|
if (res.size()!=0) // Cause this register to be cached if not already
|
|
getRegister(res); // but make sure we get full register, vndata may be truncated
|
|
return res;
|
|
}
|
|
|
|
string GhidraTranslate::getExactRegisterName(AddrSpace *base,uintb off,int4 size) const
|
|
|
|
{
|
|
if (base->getType() != IPTR_PROCESSOR) return "";
|
|
VarnodeData vndata;
|
|
vndata.space = base;
|
|
vndata.offset = off;
|
|
vndata.size = size;
|
|
map<VarnodeData,string>::const_iterator iter = addr2nm.find(vndata);
|
|
if (iter != addr2nm.end())
|
|
return (*iter).second;
|
|
string res = glb->getRegisterName(vndata);
|
|
if (res.size()!=0) { // Cause this register to be cached if not already
|
|
if (getRegister(res).size == size)
|
|
return res;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
void GhidraTranslate::getUserOpNames(vector<string> &res) const
|
|
|
|
{
|
|
int4 i=0;
|
|
for(;;) {
|
|
string nm = glb->getUserOpName(i); // Ask for the next user-defined operator
|
|
if (nm.size()==0) break;
|
|
res.push_back(nm);
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
int4 GhidraTranslate::oneInstruction(PcodeEmit &emit,const Address &baseaddr) const
|
|
|
|
{
|
|
int4 offset;
|
|
PackedDecode decoder(glb);
|
|
bool success;
|
|
try {
|
|
success = glb->getPcode(baseaddr,decoder); // Request p-code for one instruction
|
|
}
|
|
catch(JavaError &err) {
|
|
ostringstream s;
|
|
s << "Error generating pcode at address: " << baseaddr.getShortcut();
|
|
baseaddr.printRaw(s);
|
|
throw LowlevelError(s.str());
|
|
}
|
|
if (!success) {
|
|
ostringstream s;
|
|
s << "No pcode could be generated at address: " << baseaddr.getShortcut();
|
|
baseaddr.printRaw(s);
|
|
throw BadDataError(s.str());
|
|
}
|
|
|
|
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);
|
|
throw UnimplError(s.str(),offset);
|
|
}
|
|
|
|
Address pc = Address::decode(decoder);
|
|
|
|
while(decoder.peekElement() != 0)
|
|
emit.decodeOp(pc,decoder);
|
|
return offset;
|
|
}
|
|
|
|
/// Parse the \<sleigh> element passed back by the Ghidra client, describing address spaces
|
|
/// and other information that needs to be cached by the decompiler.
|
|
/// \param decoder is the stream decoder
|
|
void GhidraTranslate::decode(Decoder &decoder)
|
|
|
|
{
|
|
uint4 elemId = decoder.openElement(ELEM_SLEIGH);
|
|
setBigEndian(decoder.readBool(ATTRIB_BIGENDIAN));
|
|
setUniqueBase(decoder.readUnsignedInteger(ATTRIB_UNIQBASE));
|
|
decodeSpaces(decoder,this);
|
|
for(;;) {
|
|
uint4 subId = decoder.peekElement();
|
|
if (subId != ELEM_TRUNCATE_SPACE) break;
|
|
TruncationTag tag;
|
|
tag.decode(decoder);
|
|
truncateSpace(tag);
|
|
}
|
|
decoder.closeElement(elemId);
|
|
}
|
|
|
|
} // End namespace ghidra
|