/* ###
* 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 "pcodeinject.hh"
#include "architecture.hh"
/// \brief Read in an \ or \ XML tag describing an injection parameter
///
/// \param el is the XML element
/// \param name is used to pass back the parameter name
/// \param size is used to pass back the parameter size
void InjectPayload::readParameter(const Element *el,string &name,uint4 &size)
{
name = "";
size = 0;
int4 num = el->getNumAttributes();
for(int4 i=0;igetAttributeName(i) == "name")
name = el->getAttributeValue(i);
else if (el->getAttributeName(i) == "size") {
istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> size;
}
}
if (name.size()==0)
throw LowlevelError("Missing inject parameter name");
}
/// Input and output parameters are assigned a unique index
void InjectPayload::orderParameters(void)
{
int4 id = 0;
for(int4 i=0;i tag.
/// Derived classes may restore from a parent tag and then invoke the
/// base class method.
/// \param el is the XML element
void InjectPayload::restoreXml(const Element *el)
{
paramshift = 0;
dynamic = false;
int4 num = el->getNumAttributes();
for(int4 i=0;igetAttributeName(i));
if (elname == "paramshift") {
istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> paramshift;
}
else if (elname == "dynamic")
dynamic = xml_readbool(el->getAttributeValue(i));
else if (elname == "incidentalcopy")
incidentalCopy = xml_readbool(el->getAttributeValue(i));
}
const List &list(el->getChildren());
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter) {
const Element *subel = *iter;
if (subel->getName() == "input") {
string paramName;
uint4 size;
readParameter(subel,paramName,size);
inputlist.push_back(InjectParameter(paramName,size));
}
else if (subel->getName() == "output") {
string paramName;
uint4 size;
readParameter(subel,paramName,size);
output.push_back(InjectParameter(paramName,size));
}
}
orderParameters();
}
/// \param g is the Architecture owning \b snippet
/// \param src is a string describing the \e source of the snippet
/// \param nm is the formal name of the snippet
ExecutablePcode::ExecutablePcode(Architecture *g,const string &src,const string &nm)
: InjectPayload(nm,EXECUTABLEPCODE_TYPE), emulator(g)
{
glb = g;
emitter = (PcodeEmit *)0;
source = src;
built = false;
}
void ExecutablePcode::build(void)
{
if (built) return;
InjectContext &icontext(glb->pcodeinjectlib->getCachedContext());
icontext.clear();
uintb uniqReserve = 0x10; // Temporary register space reserved for inputs and output
AddrSpace *codeSpace = glb->getDefaultCodeSpace();
AddrSpace *uniqSpace = glb->getUniqueSpace();
icontext.baseaddr = Address(codeSpace,0x1000); // Fake address
icontext.nextaddr = icontext.baseaddr;
for(int4 i=0;ipcodeinjectlib->getBehaviors(),uniqReserve);
inject(icontext,*emitter);
delete emitter;
emitter = (PcodeEmit *)0;
if (!emulator.checkForLegalCode())
throw LowlevelError("Illegal p-code in executable snippet");
built = true;
}
/// The caller provides a list of concrete values that are assigned to the
/// input parameters. The number of values and input parameters must match,
/// and values are assigned in order. Input parameter order is determined either
/// by the order of tags in the defining XML. This method assumes there is
/// exactly 1 relevant output parameter. Once the snippet is executed the
/// value of this parameter is read from the emulator state and returned.
/// \param input is the ordered list of input values to feed to \b this script
/// \return the value of the output parameter after script execution
uintb ExecutablePcode::evaluate(const vector &input)
{
build(); // Build the PcodeOpRaws (if we haven't before)
emulator.resetMemory();
if (input.size() != inputList.size())
throw LowlevelError("Wrong number of input parameters to executable snippet");
if (outputList.size() == 0)
throw LowlevelError("No registered outputs to executable snippet");
for(int4 i=0;i::iterator iter;
for(iter=injection.begin();iter!=injection.end();++iter)
delete *iter;
}
/// \brief Map a \e call-fixup name to a payload id
///
/// \param fixupName is the formal name of the call-fixup
/// \param injectid is the integer id
void PcodeInjectLibrary::registerCallFixup(const string &fixupName,int4 injectid/* , vector targets */)
{
pair::iterator,bool> check;
check = callFixupMap.insert( pair(fixupName,injectid) );
if (!check.second) // This symbol is already mapped
throw LowlevelError("Duplicate : "+fixupName);
while(callFixupNames.size() <= injectid)
callFixupNames.push_back("");
callFixupNames[injectid] = fixupName;
}
/// \brief Map a \e callother-fixup name to a payload id
///
/// \param fixupName is the formal name of the callother-fixup
/// \param injectid is the integer id
void PcodeInjectLibrary::registerCallOtherFixup(const string &fixupName,int4 injectid)
{
pair::iterator,bool> check;
check = callOtherFixupMap.insert( pair(fixupName,injectid) );
if (!check.second) // This symbol is already mapped
throw LowlevelError("Duplicate : "+fixupName);
while(callOtherTarget.size() <= injectid)
callOtherTarget.push_back("");
callOtherTarget[injectid] = fixupName;
}
/// \brief Map a \e call \e mechanism name to a payload id
///
/// \param fixupName is the formal name of the call mechanism
/// \param injectid is the integer id
void PcodeInjectLibrary::registerCallMechanism(const string &fixupName,int4 injectid)
{
pair::iterator,bool> check;
check = callMechFixupMap.insert( pair(fixupName,injectid) );
if (!check.second) // This symbol is already mapped
throw LowlevelError("Duplicate : "+fixupName);
while(callMechTarget.size() <= injectid)
callMechTarget.push_back("");
callMechTarget[injectid] = fixupName;
}
/// \brief Map a \e p-code \e script name to a payload id
///
/// \param scriptName is the formal name of the p-code script
/// \param injectid is the integer id
void PcodeInjectLibrary::registerExeScript(const string &scriptName,int4 injectid)
{
pair::iterator,bool> check;
check = scriptMap.insert( pair(scriptName,injectid) );
if (!check.second) // This symbol is already mapped
throw LowlevelError("Duplicate