mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
TypePointerRel adjustments
This commit is contained in:
parent
6cc2eae322
commit
64534bc774
7 changed files with 98 additions and 12 deletions
|
@ -32,6 +32,7 @@ src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END|
|
|||
src/decompile/datatests/offsetarray.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/pointercmp.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/pointersub.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/promotecompare.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/readvolatile.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/sbyte.xml||GHIDRA||||END|
|
||||
|
|
|
@ -2923,7 +2923,7 @@ void IfcPointerSetting::execute(istream &s)
|
|||
Datatype *bt = dcp->conf->types->findByName(baseType);
|
||||
if (bt == (Datatype *)0 || bt->getMetatype() != TYPE_STRUCT)
|
||||
throw IfaceParseError("Base-type must be a structure");
|
||||
Datatype *ptrto = TypePointerRel::getPtrTo(bt, off, *dcp->conf->types);
|
||||
Datatype *ptrto = TypePointerRel::getPtrToFromParent(bt, off, *dcp->conf->types);
|
||||
AddrSpace *spc = dcp->conf->getDefaultDataSpace();
|
||||
dcp->conf->types->getTypePointerRel(spc->getAddrSize(), bt, ptrto, spc->getWordSize(), off,typeName);
|
||||
}
|
||||
|
|
|
@ -785,16 +785,18 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||
TypePointerRel *ptrel;
|
||||
Datatype *ct;
|
||||
const Varnode *in0;
|
||||
uintb in1const;
|
||||
bool valueon,flex,arrayvalue;
|
||||
uint4 m;
|
||||
|
||||
in0 = op->getIn(0);
|
||||
in1const = op->getIn(1)->getOffset();
|
||||
ptype = (TypePointer *)in0->getHigh()->getType();
|
||||
if (ptype->getMetatype() != TYPE_PTR) {
|
||||
clear();
|
||||
throw LowlevelError("PTRSUB off of non-pointer type");
|
||||
}
|
||||
if (ptype->isFormalPointerRel()) {
|
||||
if (ptype->isFormalPointerRel() && ((TypePointerRel *)ptype)->evaluateThruParent(in1const)) {
|
||||
ptrel = (TypePointerRel *)ptype;
|
||||
ct = ptrel->getParent();
|
||||
}
|
||||
|
@ -807,10 +809,19 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||
flex = isValueFlexible(in0);
|
||||
|
||||
if (ct->getMetatype() == TYPE_STRUCT) {
|
||||
uintb suboff = op->getIn(1)->getOffset(); // How far into container
|
||||
uintb suboff = in1const; // How far into container
|
||||
if (ptrel != (TypePointerRel *)0) {
|
||||
suboff += ptrel->getPointerOffset();
|
||||
suboff &= calc_mask(ptype->getSize());
|
||||
if (suboff == 0) {
|
||||
// Special case where we do not print a field
|
||||
pushTypePointerRel(op);
|
||||
if (flex)
|
||||
pushVnImplied(in0,op,m | print_load_value);
|
||||
else
|
||||
pushVnImplied(in0,op,m);
|
||||
return;
|
||||
}
|
||||
}
|
||||
suboff = AddrSpace::addressToByte(suboff,ptype->getWordSize());
|
||||
string fieldname;
|
||||
|
@ -904,7 +915,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||
}
|
||||
if (symbol == (Symbol *)0) {
|
||||
TypeSpacebase *sb = (TypeSpacebase *)ct;
|
||||
Address addr = sb->getAddress(op->getIn(1)->getOffset(),in0->getSize(),op->getAddr());
|
||||
Address addr = sb->getAddress(in1const,in0->getSize(),op->getAddr());
|
||||
pushUnnamedLocation(addr,(Varnode *)0,op);
|
||||
}
|
||||
else {
|
||||
|
@ -923,7 +934,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||
push_integer(0,4,false,(Varnode *)0,op);
|
||||
}
|
||||
else if (ct->getMetatype() == TYPE_ARRAY) {
|
||||
if (op->getIn(1)->getOffset() != 0) {
|
||||
if (in1const != 0) {
|
||||
clear();
|
||||
throw LowlevelError("PTRSUB with non-zero offset into array type");
|
||||
}
|
||||
|
|
|
@ -5977,6 +5977,13 @@ void AddTreeState::calcSubtype(void)
|
|||
}
|
||||
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); // Convert back to address units
|
||||
offset = (nonmultsum - extra) & ptrmask;
|
||||
if (pRelType != (TypePointerRel *)0 && offset == pRelType->getPointerOffset()) {
|
||||
// offset falls within basic ptrto
|
||||
if (!pRelType->evaluateThruParent(0)) { // If we are not representing offset 0 through parent
|
||||
valid = false; // Use basic (alternate) form
|
||||
return;
|
||||
}
|
||||
}
|
||||
isSubtype = true;
|
||||
}
|
||||
else if (baseType->getMetatype() == TYPE_ARRAY) {
|
||||
|
@ -6331,7 +6338,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
|
|||
if (ct->getMetatype() != TYPE_PTR) return 0;
|
||||
Datatype *baseType = ((TypePointer *)ct)->getPtrTo();
|
||||
uintb offset = 0;
|
||||
if (ct->isFormalPointerRel()) {
|
||||
if (ct->isFormalPointerRel() && ((TypePointerRel *)ct)->evaluateThruParent(0)) {
|
||||
TypePointerRel *ptRel = (TypePointerRel *)ct;
|
||||
baseType = ptRel->getParent();
|
||||
if (baseType->getMetatype() != TYPE_STRUCT)
|
||||
|
|
|
@ -1245,8 +1245,9 @@ void TypeStruct::restoreFields(const Element *el,TypeFactory &typegrp)
|
|||
void TypePointerRel::restoreXml(const Element *el,TypeFactory &typegrp)
|
||||
|
||||
{
|
||||
flags = is_ptrrel;
|
||||
flags |= is_ptrrel;
|
||||
restoreXmlBasic(el);
|
||||
metatype = TYPE_PTR; // Don't use TYPE_PTRREL internally
|
||||
for(int4 i=0;i<el->getNumAttributes();++i)
|
||||
if (el->getAttributeName(i) == "wordsize") {
|
||||
istringstream s(el->getAttributeValue(i));
|
||||
|
@ -1256,6 +1257,8 @@ void TypePointerRel::restoreXml(const Element *el,TypeFactory &typegrp)
|
|||
const List &list(el->getChildren());
|
||||
List::const_iterator iter;
|
||||
iter = list.begin();
|
||||
ptrto = typegrp.restoreXmlType( *iter );
|
||||
++iter;
|
||||
parent = typegrp.restoreXmlType( *iter );
|
||||
++iter;
|
||||
istringstream s1((*iter)->getContent());
|
||||
|
@ -1263,12 +1266,25 @@ void TypePointerRel::restoreXml(const Element *el,TypeFactory &typegrp)
|
|||
s1 >> offset;
|
||||
if (offset == 0)
|
||||
throw new LowlevelError("For metatype=\"ptrstruct\", <off> tag must not be zero");
|
||||
ptrto = getPtrTo(parent, offset, typegrp);
|
||||
submeta = (ptrto->getMetatype()==TYPE_UNKNOWN) ? SUB_PTRREL_UNK: SUB_PTRREL;
|
||||
if (name.size() == 0) // If the data-type is not named
|
||||
cacheStrippedType(typegrp); // it is considered ephemeral
|
||||
}
|
||||
|
||||
/// For a variable that is a relative pointer, constant offsets off of the variable can be
|
||||
/// displayed either as coming from the variable itself or from the parent object.
|
||||
/// \param byteOff is the given offset off of the variable
|
||||
/// \return \b true if the variable should be displayed as coming from the parent
|
||||
bool TypePointerRel::evaluateThruParent(uintb addrOff) const
|
||||
|
||||
{
|
||||
uintb byteOff = AddrSpace::addressToByte(addrOff, wordsize);
|
||||
if (ptrto->getMetatype() == TYPE_STRUCT && byteOff < ptrto->getSize())
|
||||
return false;
|
||||
byteOff = (byteOff + offset) & calc_mask(size);
|
||||
return (byteOff < parent->getSize());
|
||||
}
|
||||
|
||||
void TypePointerRel::printRaw(ostream &s) const
|
||||
|
||||
{
|
||||
|
@ -1301,15 +1317,18 @@ void TypePointerRel::saveXml(ostream &s) const
|
|||
if (wordsize != 1)
|
||||
a_v_i(s,"wordsize",wordsize);
|
||||
s << ">\n";
|
||||
ptrto->saveXml(s);
|
||||
s << '\n';
|
||||
parent->saveXmlRef(s);
|
||||
s << "<off>" << dec << offset << "</off>\n";
|
||||
s << "\n<off>" << dec << offset << "</off>\n";
|
||||
s << "</type>";
|
||||
}
|
||||
|
||||
TypePointer *TypePointerRel::downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,
|
||||
TypeFactory &typegrp)
|
||||
{
|
||||
if (off < ptrto->getSize() && stripped != (TypePointer *)0) {
|
||||
type_metatype ptrtoMeta = ptrto->getMetatype();
|
||||
if (off < ptrto->getSize() && (ptrtoMeta == TYPE_STRUCT || ptrtoMeta == TYPE_ARRAY)) {
|
||||
return TypePointer::downChain(off,par,parOff,allowArrayWrap,typegrp);
|
||||
}
|
||||
uintb relOff = (off + offset) & calc_mask(size); // Convert off to be relative to the parent container
|
||||
|
@ -1318,6 +1337,8 @@ TypePointer *TypePointerRel::downChain(uintb &off,TypePointer *&par,uintb &parOf
|
|||
|
||||
TypePointer *origPointer = typegrp.getTypePointer(size, parent, wordsize);
|
||||
off = relOff;
|
||||
if (relOff == 0 && offset != 0) // Recovering the start of the parent is still downchaining, even though the parent may be the container
|
||||
return origPointer; // So we return the pointer to the parent and don't drill down to field at offset 0
|
||||
return origPointer->downChain(off,par,parOff,allowArrayWrap,typegrp);
|
||||
}
|
||||
|
||||
|
@ -1339,7 +1360,7 @@ bool TypePointerRel::isPtrsubMatching(uintb off) const
|
|||
/// \param off is the offset relative to the start of the container
|
||||
/// \param typegrp is the factory owning the data-types
|
||||
/// \return the "pointed to" data-type
|
||||
Datatype *TypePointerRel::getPtrTo(Datatype *base,int4 off,TypeFactory &typegrp)
|
||||
Datatype *TypePointerRel::getPtrToFromParent(Datatype *base,int4 off,TypeFactory &typegrp)
|
||||
|
||||
{
|
||||
if (off > 0) {
|
||||
|
@ -2844,6 +2865,15 @@ Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore)
|
|||
ct = findAdd(tp);
|
||||
}
|
||||
break;
|
||||
case TYPE_PTRREL:
|
||||
{
|
||||
TypePointerRel tp;
|
||||
tp.restoreXml(el, *this);
|
||||
if (forcecore)
|
||||
tp.flags |= Datatype::coretype;
|
||||
ct = findAdd(tp);
|
||||
}
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
{
|
||||
TypeArray ta;
|
||||
|
|
|
@ -401,6 +401,7 @@ public:
|
|||
parent = par; offset = off; stripped = (TypePointer *)0; flags |= is_ptrrel;
|
||||
submeta = pt->getMetatype()==TYPE_UNKNOWN ? SUB_PTRREL_UNK : SUB_PTRREL; }
|
||||
Datatype *getParent(void) const { return parent; } ///< Get the parent data-type to which \b this pointer is offset
|
||||
bool evaluateThruParent(uintb addrOff) const; ///< Do we display given address offset as coming from the parent data-type
|
||||
|
||||
/// \brief Get offset of \b this pointer relative to start of the containing data-type
|
||||
///
|
||||
|
@ -413,7 +414,7 @@ public:
|
|||
virtual TypePointer *downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp);
|
||||
virtual bool isPtrsubMatching(uintb off) const;
|
||||
virtual Datatype *getStripped(void) const { return stripped; } ///< Get the plain form of the pointer
|
||||
static Datatype *getPtrTo(Datatype *base,int4 off,TypeFactory &typegrp);
|
||||
static Datatype *getPtrToFromParent(Datatype *base,int4 off,TypeFactory &typegrp);
|
||||
};
|
||||
|
||||
class FuncProto; // Forward declaration
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<decompilertest>
|
||||
<binaryimage arch="x86:LE:64:default:gcc">
|
||||
<!--
|
||||
Test that relative pointers can access
|
||||
1) a pointer to the parent structure
|
||||
2) a field of the parent using the ADJ macro
|
||||
3) a field in an inner structure, without going thru parent
|
||||
-->
|
||||
<bytechunk space="ram" offset="0x1005fa" readonly="true">
|
||||
554889e54889
|
||||
7de8488b45e84883e810488945f8488b
|
||||
45e8f20f1005ce000000f20f11400848
|
||||
8b45f848c740080a000000488b45f85d
|
||||
c3
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x1006e8" readonly="true">
|
||||
0000000000002340
|
||||
</bytechunk>
|
||||
<symbol name="getOuter" space="ram" offset="0x1005fa"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>option readonly on</com>
|
||||
<com>parse line struct InnerStruct { int8 a; float8 b; char c; };</com>
|
||||
<com>parse line struct OuterStruct { int8 outA; int8 outB; InnerStruct inner; };</com>
|
||||
<com>pointer setting outer_rel OuterStruct offset 16</com>
|
||||
<com>parse line extern OuterStruct *getOuter(outer_rel ptr);</com>
|
||||
<com>lo fu getOuter</com>
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Relative base #1" min="1" max="1">ptr->b = 9\.5;</stringmatch>
|
||||
<stringmatch name="Relative base #2" min="1" max="1">ADJ\(ptr\)->outB = 10;</stringmatch>
|
||||
<stringmatch name="Relative base #3" min="1" max="1">return ADJ\(ptr\);</stringmatch>
|
||||
<stringmatch name="Relative base #4" min="1" max="1">OuterStruct \* getOuter\(outer_rel ptr\)</stringmatch>
|
||||
</decompilertest>
|
Loading…
Add table
Add a link
Reference in a new issue