/* ### * 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 "override.hh" #include "funcdata.hh" void Override::clear(void) { map::iterator iter; for(iter=protoover.begin();iter!=protoover.end();++iter) delete (*iter).second; forcegoto.clear(); deadcodedelay.clear(); indirectover.clear(); protoover.clear(); multistagejump.clear(); flowoverride.clear(); } /// \brief Generate \e warning message related to a dead code delay /// /// This is triggered by the insertDeadcodeDelay() command on a specific address space /// \param index is the index of the address space /// \param glb is the Architecture object /// \return the generated message string Override::generateDeadcodeDelayMessage(int4 index,Architecture *glb) { AddrSpace *spc = glb->getSpace(index); string res = "Restarted to delay deadcode elimination for space: " + spc->getName(); return res; } /// \brief Force a specific branch instruction to be an unstructured \e goto /// /// The command is specified as the address of the branch instruction and /// the destination address of the branch. The decompiler will automatically /// mark this as a \e unstructured, when trying to structure the control-flow /// \param targetpc is the address of the branch instruction /// \param destpc is the destination address of the branch void Override::insertForceGoto(const Address &targetpc,const Address &destpc) { forcegoto[targetpc] = destpc; } /// \brief Override the number of passes that are executed before \e dead-code elimination starts /// /// Every address space has an assigned \e delay (which may be zero) before a PcodeOp /// involving a Varnode in that address space can be eliminated. This command allows the /// delay for a specific address space to be increased so that new Varnode accesses can be discovered. /// \param spc is the address space to modify /// \param delay is the size of the delay (in passes) void Override::insertDeadcodeDelay(AddrSpace *spc,int4 delay) { while(deadcodedelay.size() <= spc->getIndex()) deadcodedelay.push_back(-1); deadcodedelay[spc->getIndex()] = delay; } /// \brief Check if a delay override is already installed for an address space /// /// \param spc is the address space /// \return \b true if an override has already been installed bool Override::hasDeadcodeDelay(AddrSpace *spc) const { int4 index = spc->getIndex(); if (index >= deadcodedelay.size()) return false; int4 val = deadcodedelay[index]; if (val == -1) return false; return (val != spc->getDeadcodeDelay()); } /// \brief Override an indirect call turning it into a direct call /// /// The command consists of the address of the indirect call instruction and /// the target address of the direct address /// \param callpoint is the address of the indirect call /// \param directcall is the target address of the direct call void Override::insertIndirectOverride(const Address &callpoint,const Address &directcall) { indirectover[callpoint] = directcall; } /// \brief Override the assumed function prototype at a specific call site /// /// The exact input and output storage locations are overridden for a /// specific call instruction (direct or indirect). /// \param callpoint is the address of the call instruction /// \param p is the overriding function prototype void Override::insertProtoOverride(const Address &callpoint,FuncProto *p) { map::iterator iter; iter = protoover.find(callpoint); if (iter != protoover.end()) // Check for pre-existing override delete (*iter).second; // and delete it p->setOverride(true); // Mark this as an override protoover[callpoint] = p; // Take ownership of the object } /// \brief Flag an indirect jump for multistage analysis /// /// \param addr is the address of the indirect jump void Override::insertMultistageJump(const Address &addr) { multistagejump.push_back(addr); } /// \brief Mark a branch instruction with a different flow type /// /// Change the interpretation of a BRANCH, CALL, or RETURN /// \param addr is the address of the branch instruction /// \param type is the type of flow that should be forced void Override::insertFlowOverride(const Address &addr,uint4 type) { flowoverride[addr] = type; } /// \brief Look for and apply a function prototype override /// /// Given a call point, look for a prototype override and copy /// the call specification in /// \param data is the (calling) function /// \param fspecs is a reference to the call specification void Override::applyPrototype(Funcdata &data,FuncCallSpecs &fspecs) const { if (!protoover.empty()) { map::const_iterator iter = protoover.find(fspecs.getOp()->getAddr()); if (iter != protoover.end()) { fspecs.copy(*(*iter).second); } } } /// \brief Look for and apply destination overrides of indirect calls /// /// Given an indirect call, look for any overrides, then copy in /// the overriding target address of the direct call /// \param data is (calling) function /// \param fspecs is a reference to the call specification void Override::applyIndirect(Funcdata &data,FuncCallSpecs &fspecs) const { if (!indirectover.empty()) { map::const_iterator iter = indirectover.find(fspecs.getOp()->getAddr()); if (iter != indirectover.end()) fspecs.setAddress( (*iter).second ); } } /// \brief Check for a multistage marker for a specific indirect jump /// /// Given the address of an indirect jump, look for the multistate command /// \param addr is the address of the indirect jump bool Override::queryMultistageJumptable(const Address &addr) const { for(int4 i=0;i::const_iterator iter; for(iter=forcegoto.begin();iter!=forcegoto.end();++iter) data.forceGoto((*iter).first,(*iter).second); } /// \brief Apply any dead-code delay overrides /// /// Look for delays of each address space and apply them to the Heritage object /// \param data is the function void Override::applyDeadCodeDelay(Funcdata &data) const { Architecture *glb = data.getArch(); for(int4 i=0;igetSpace(i); data.setDeadCodeDelay(spc,delay); } } /// \brief Return the particular flow override at a given address /// /// \param addr is the address of a branch instruction /// \return the override type uint4 Override::getFlowOverride(const Address &addr) const { map::const_iterator iter; iter = flowoverride.find(addr); if (iter == flowoverride.end()) return Override::NONE; return (*iter).second; } /// \brief Dump a description of the overrides to stream /// /// Give a description of each override, one per line, that is suitable for debug /// \param s is the output stream /// \param glb is the Architecture void Override::printRaw(ostream &s,Architecture *glb) const { map::const_iterator iter; for(iter=forcegoto.begin();iter!=forcegoto.end();++iter) s << "force goto at " << (*iter).first << " jumping to " << (*iter).second << endl; for(int4 i=0;igetSpace(i); s << "dead code delay on " << spc->getName() << " set to " << dec << deadcodedelay[i] << endl; } for(iter=indirectover.begin();iter!=indirectover.end();++iter) s << "override indirect at " << (*iter).first << " to call directly to " << (*iter).second << endl; map::const_iterator fiter; for(fiter=protoover.begin();fiter!=protoover.end();++fiter) { s << "override prototype at " << (*fiter).first << " to "; (*fiter).second->printRaw("func",s); s << endl; } } /// \brief Create warning messages that describe current overrides /// /// Message are designed to be displayed in the function header comment /// \param messagelist will hold the generated list of messages /// \param glb is the Architecture void Override::generateOverrideMessages(vector &messagelist,Architecture *glb) const { // Generate deadcode delay messages for(int4 i=0;i= 0) messagelist.push_back( generateDeadcodeDelayMessage(i,glb)); } } /// \brief Write the override commands to an XML stream /// /// All the commands are written as sub-tags of a root \ tag. /// \param s is the output stream /// \param glb is the Architecture void Override::saveXml(ostream &s,Architecture *glb) const { if (forcegoto.empty() && deadcodedelay.empty() && indirectover.empty() && protoover.empty() && multistagejump.empty() && flowoverride.empty()) return; s << "\n"; map::const_iterator iter; for(iter=forcegoto.begin();iter!=forcegoto.end();++iter) { s << ""; (*iter).first.saveXml(s); (*iter).second.saveXml(s); s << "\n"; } for(int4 i=0;igetSpace(i); s << "getName()); a_v_i(s,"delay",deadcodedelay[i]); s << "/>\n"; } for(iter=indirectover.begin();iter!=indirectover.end();++iter) { s << ""; (*iter).first.saveXml(s); (*iter).second.saveXml(s); s << "\n"; } map::const_iterator fiter; for(fiter=protoover.begin();fiter!=protoover.end();++fiter) { s << ""; (*fiter).first.saveXml(s); (*fiter).second->saveXml(s); s << "\n"; } for(int4 i=0;i"; multistagejump[i].saveXml(s); s << ""; } map::const_iterator titer; for(titer=flowoverride.begin();titer!=flowoverride.end();++titer) { s << ""; (*titer).first.saveXml(s); s << "\n"; } s << "\n"; } /// \brief Read in override commands from XML /// /// \param el is the root \ element /// \param glb is the Architecture void Override::restoreXml(const Element *el,Architecture *glb) { const List &list(el->getChildren()); List::const_iterator iter; for(iter=list.begin();iter!=list.end();++iter) { const Element *subel = *iter; if (subel->getName() == "indirectoverride") { const List &list2(subel->getChildren()); List::const_iterator iter2 = list2.begin(); Address callpoint = Address::restoreXml(*iter2,glb); ++iter2; Address directcall = Address::restoreXml(*iter2,glb); insertIndirectOverride(callpoint,directcall); } else if (subel->getName() == "protooverride") { const List &list2(subel->getChildren()); List::const_iterator iter2 = list2.begin(); Address callpoint = Address::restoreXml(*iter2,glb); ++iter2; FuncProto *fp = new FuncProto(); fp->setInternal(glb->defaultfp,glb->types->getTypeVoid()); fp->restoreXml(*iter2,glb); insertProtoOverride(callpoint,fp); } else if (subel->getName() == "forcegoto") { const List &list2(subel->getChildren()); List::const_iterator iter2 = list2.begin(); Address targetpc = Address::restoreXml(*iter2,glb); ++iter2; Address destpc = Address::restoreXml(*iter2,glb); insertForceGoto(targetpc,destpc); } else if (subel->getName() == "deadcodedelay") { int4 delay = -1; istringstream s(subel->getAttributeValue("delay")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> delay; AddrSpace *spc = glb->getSpaceByName( subel->getAttributeValue("space")); if ((spc == (AddrSpace *)0)||(delay < 0)) throw LowlevelError("Bad deadcodedelay tag"); insertDeadcodeDelay(spc,delay); } else if (subel->getName() == "multistagejump") { const Element *tmpel = subel->getChildren().front(); Address callpoint = Address::restoreXml(tmpel,glb); insertMultistageJump(callpoint); } else if (subel->getName() == "multistagejump") { const Element *tmpel = subel->getChildren().front(); Address callpoint = Address::restoreXml(tmpel,glb); insertMultistageJump(callpoint); } else if (subel->getName() == "flow") { uint4 type = stringToType(subel->getAttributeValue("type")); const Element *tmpel = subel->getChildren().front(); Address addr = Address::restoreXml(tmpel,glb); if ((type == Override::NONE)||(addr.isInvalid())) throw LowlevelError("Bad flowoverride tag"); insertFlowOverride(addr,type); } } } /// \param tp is the override type /// \return the corresponding name string string Override::typeToString(uint4 tp) { if (tp == Override::BRANCH) return "branch"; if (tp == Override::CALL) return "call"; if (tp == Override::CALL_RETURN) return "callreturn"; if (tp == Override::RETURN) return "return"; return "none"; } /// \param nm is the override name /// \return the override enumeration type uint4 Override::stringToType(const string &nm) { if (nm == "branch") return Override::BRANCH; else if (nm == "call") return Override::CALL; else if (nm == "callreturn") return Override::CALL_RETURN; else if (nm == "return") return Override::RETURN; return Override::NONE; }