ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc
caheckman 612c0d6f3e name to address space map
shortcut to address space map
more adjustments to shortcuts
allow null AddrSpace pointer in raw baselist
holes in the space indices
almost working
GT-2873 decompiler, other, and overlays
GT-2873 added OTHER space to java sleigh compiler, fixed decompiler
exception
isOtherSpace method
isOtherSpace java, addressing code review comments
GT-2873 added null check in decompiler reset
GT-2873 code review changes
Read and write space_other tag in SLA files
Version number for .sla file
GT-2873 fixups after merge
GT-2873 renamed Sparc registers: OTHER->OTHERWIN, WINWSTATE->WSTATE
GT-2873 added option in AddressInput to control OTHER space visibility
GT-2873 OTHER space now global
GT-2873 fixing comments refering to decompiler code in BasicCompilerSpec
2019-08-22 12:30:18 -04:00

243 lines
7.3 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 "sleighbase.hh"
const int4 SleighBase::SLA_FORMAT_VERSION = 2;
SleighBase::SleighBase(void)
{
root = (SubtableSymbol *)0;
maxdelayslotbytes = 0;
unique_allocatemask = 0;
numSections = 0;
}
/// Assuming the symbol table is populated, iterate through the table collecting
/// registers (for the map), user-op names, and context fields.
void SleighBase::buildXrefs(void)
{
SymbolScope *glb = symtab.getGlobalScope();
SymbolTree::const_iterator iter;
SleighSymbol *sym;
int4 errors = 0;
ostringstream s;
for(iter=glb->begin();iter!=glb->end();++iter) {
sym = *iter;
if (sym->getType() == SleighSymbol::varnode_symbol) {
pair<VarnodeData,string> ins(((VarnodeSymbol *)sym)->getFixedVarnode(),sym->getName());
pair<map<VarnodeData,string>::iterator,bool> res = varnode_xref.insert(ins);
if (!res.second) {
s << "Duplicate (offset,size) pair for registers: ";
s << sym->getName() << " and " << (*(res.first)).second << '\n';
errors += 1;
}
}
else if (sym->getType() == SleighSymbol::userop_symbol) {
int4 index = ((UserOpSymbol *)sym)->getIndex();
while(userop.size() <= index)
userop.push_back("");
userop[index] = sym->getName();
}
else if (sym->getType() == SleighSymbol::context_symbol) {
ContextSymbol *csym = (ContextSymbol *)sym;
ContextField *field = (ContextField *)csym->getPatternValue();
int4 startbit = field->getStartBit();
int4 endbit = field->getEndBit();
registerContext(csym->getName(),startbit,endbit);
}
}
if (errors > 0)
throw SleighError(s.str());
}
/// If \b this SleighBase is being reused with a new program, the context
/// variables need to be registered with the new program's database
void SleighBase::reregisterContext(void)
{
SymbolScope *glb = symtab.getGlobalScope();
SymbolTree::const_iterator iter;
SleighSymbol *sym;
for(iter=glb->begin();iter!=glb->end();++iter) {
sym = *iter;
if (sym->getType() == SleighSymbol::context_symbol) {
ContextSymbol *csym = (ContextSymbol *)sym;
ContextField *field = (ContextField *)csym->getPatternValue();
int4 startbit = field->getStartBit();
int4 endbit = field->getEndBit();
registerContext(csym->getName(),startbit,endbit);
}
}
}
void SleighBase::addRegister(const string &nm,AddrSpace *base,uintb offset,int4 size)
{
VarnodeSymbol *sym = new VarnodeSymbol(nm,base,offset,size);
symtab.addSymbol(sym);
}
const VarnodeData &SleighBase::getRegister(const string &nm) const
{
VarnodeSymbol *sym = (VarnodeSymbol *)findSymbol(nm);
if (sym == (VarnodeSymbol *)0)
throw SleighError("Unknown register name: "+nm);
if (sym->getType() != SleighSymbol::varnode_symbol)
throw SleighError("Symbol is not a register: "+nm);
return sym->getFixedVarnode();
}
string SleighBase::getRegisterName(AddrSpace *base,uintb off,int4 size) const
{
VarnodeData sym;
sym.space = base;
sym.offset = off;
sym.size = size;
map<VarnodeData,string>::const_iterator iter = varnode_xref.upper_bound(sym); // First point greater than offset
if (iter == varnode_xref.begin()) return "";
iter--;
const VarnodeData &point((*iter).first);
if (point.space != base) return "";
uintb offbase = point.offset;
if (point.offset+point.size >= off+size)
return (*iter).second;
while(iter != varnode_xref.begin()) {
--iter;
const VarnodeData &point((*iter).first);
if ((point.space != base)||(point.offset != offbase)) return "";
if (point.offset+point.size >= off+size)
return (*iter).second;
}
return "";
}
void SleighBase::getAllRegisters(map<VarnodeData,string> &reglist) const
{
reglist = varnode_xref;
}
void SleighBase::getUserOpNames(vector<string> &res) const
{
res = userop; // Return list of all language defined user ops (with index)
}
/// This does the bulk of the work of creating a .sla file
/// \param s is the output stream
void SleighBase::saveXml(ostream &s) const
{
s << "<sleigh";
a_v_i(s,"version",SLA_FORMAT_VERSION);
a_v_b(s,"bigendian",isBigEndian());
a_v_i(s,"align",alignment);
a_v_u(s,"uniqbase",getUniqueBase());
if (maxdelayslotbytes > 0)
a_v_u(s,"maxdelay",maxdelayslotbytes);
if (unique_allocatemask != 0)
a_v_u(s,"uniqmask",unique_allocatemask);
if (numSections != 0)
a_v_u(s,"numsections",numSections);
s << ">\n";
s << "<spaces";
a_v(s,"defaultspace",getDefaultSpace()->getName());
s << ">\n";
for(int4 i=0;i<numSpaces();++i) {
AddrSpace *spc = getSpace(i);
if (spc == (AddrSpace *)0) continue;
if ((spc->getType()==IPTR_CONSTANT) ||
(spc->getType()==IPTR_FSPEC)||
(spc->getType()==IPTR_IOP)||
(spc->getType()==IPTR_JOIN))
continue;
spc->saveXml(s);
}
s << "</spaces>\n";
symtab.saveXml(s);
s << "</sleigh>\n";
}
/// This parses the main \<sleigh> tag (from a .sla file), which includes the description
/// of address spaces and the symbol table, with its associated decoding tables
/// \param el is the root XML element
void SleighBase::restoreXml(const Element *el)
{
maxdelayslotbytes = 0;
unique_allocatemask = 0;
numSections = 0;
int4 version = 0;
setBigEndian(xml_readbool(el->getAttributeValue("bigendian")));
{
istringstream s(el->getAttributeValue("align"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> alignment;
}
{
istringstream s(el->getAttributeValue("uniqbase"));
s.unsetf(ios::dec | ios::hex | ios::oct);
uintm ubase;
s >> ubase;
setUniqueBase(ubase);
}
int4 numattr = el->getNumAttributes();
for(int4 i=0;i<numattr;++i) {
const string &attrname( el->getAttributeName(i) );
if (attrname == "maxdelay") {
istringstream s1(el->getAttributeValue(i));
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> maxdelayslotbytes;
}
else if (attrname == "uniqmask") {
istringstream s2(el->getAttributeValue(i));
s2.unsetf(ios::dec | ios::hex | ios::oct);
s2 >> unique_allocatemask;
}
else if (attrname == "numsections") {
istringstream s3(el->getAttributeValue(i));
s3.unsetf(ios::dec | ios::hex | ios::oct);
s3 >> numSections;
}
else if (attrname == "version") {
istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> version;
}
}
if (version != SLA_FORMAT_VERSION)
throw LowlevelError(".sla file has wrong format");
const List &list(el->getChildren());
List::const_iterator iter;
iter = list.begin();
while((*iter)->getName() == "floatformat") {
floatformats.push_back(FloatFormat());
floatformats.back().restoreXml(*iter);
++iter;
}
restoreXmlSpaces(*iter,this);
iter++;
symtab.restoreXml(*iter,this);
root = (SubtableSymbol *)symtab.getGlobalScope()->findSymbol("instruction");
buildXrefs();
}