GP-1518 Decompiler support for unions

This commit is contained in:
caheckman 2021-11-19 14:39:42 -05:00
parent 53e2c4dc4f
commit 3fdbbbb231
65 changed files with 5119 additions and 1068 deletions

View file

@ -360,7 +360,7 @@ void PrintC::opFunc(const PcodeOp *op)
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=0;--i)
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
else // Push empty token for void
pushAtom(Atom("",blanktoken,EmitXml::no_color));
@ -375,9 +375,9 @@ void PrintC::opTypeCast(const PcodeOp *op)
{
if (!option_nocasts) {
pushOp(&typecast,op);
pushType(op->getOut()->getHigh()->getType());
pushType(op->getOut()->getHighTypeDefFacing());
}
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
/// The syntax represents the given op using a function with one input,
@ -392,13 +392,13 @@ void PrintC::opHiddenFunc(const PcodeOp *op)
{
pushOp(&hidden,op);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
void PrintC::opCopy(const PcodeOp *op)
{
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
void PrintC::opLoad(const PcodeOp *op)
@ -411,7 +411,7 @@ void PrintC::opLoad(const PcodeOp *op)
else {
pushOp(&dereference,op);
}
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(1),op,m);
}
void PrintC::opStore(const PcodeOp *op)
@ -430,8 +430,8 @@ void PrintC::opStore(const PcodeOp *op)
}
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
pushVnImplied(op->getIn(2),op,mods);
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(2),op,mods);
pushVn(op->getIn(1),op,m);
}
void PrintC::opBranch(const PcodeOp *op)
@ -441,7 +441,7 @@ void PrintC::opBranch(const PcodeOp *op)
// Assume the BRANCH is a statement
emit->tagOp("goto",EmitXml::keyword_color,op);
emit->spaces(1);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
}
@ -480,7 +480,7 @@ void PrintC::opCbranch(const PcodeOp *op)
}
if (booleanflip)
pushOp(&boolean_not,op);
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(1),op,m);
// Make sure stack is clear before emitting more
recurse();
if (yesparen)
@ -492,7 +492,7 @@ void PrintC::opCbranch(const PcodeOp *op)
emit->spaces(1);
emit->print("goto",EmitXml::keyword_color);
emit->spaces(1);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
}
@ -502,7 +502,7 @@ void PrintC::opBranchind(const PcodeOp *op)
// FIXME: This routine shouldn't emit directly
emit->tagOp("switch",EmitXml::keyword_color,op); // Print header for switch
int4 id = emit->openParen('(');
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
recurse();
emit->closeParen(')',id);
}
@ -544,7 +544,7 @@ void PrintC::opCall(const PcodeOp *op)
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i) {
if (i == skip) continue;
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
}
else // Push empty token for void
@ -564,25 +564,25 @@ void PrintC::opCallind(const PcodeOp *op)
int4 count = op->numInput() - 1;
count -= (skip < 0) ? 0 : 1;
if (count > 1) { // Multiple parameters
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
for(int4 i=0;i<count-1;++i)
pushOp(&comma,op);
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i) {
if (i == skip) continue;
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
}
else if (count == 1) { // One parameter
if (skip == 1)
pushVnImplied(op->getIn(2),op,mods);
pushVn(op->getIn(2),op,mods);
else
pushVnImplied(op->getIn(1),op,mods);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(1),op,mods);
pushVn(op->getIn(0),op,mods);
}
else { // A void function
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
pushAtom(Atom("",blanktoken,EmitXml::no_color));
}
}
@ -599,7 +599,7 @@ void PrintC::opCallother(const PcodeOp *op)
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i)
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
else // Push empty token for void
pushAtom(Atom("",blanktoken,EmitXml::no_color));
@ -614,7 +614,7 @@ void PrintC::opConstructor(const PcodeOp *op,bool withNew)
const Varnode *outvn = newop->getOut();
pushOp(&new_op,newop);
pushAtom(Atom("new",optoken,EmitXml::keyword_color,newop,outvn));
dt = outvn->getType();
dt = outvn->getTypeDefFacing();
}
else {
const Varnode *thisvn = op->getIn(1);
@ -632,10 +632,10 @@ void PrintC::opConstructor(const PcodeOp *op,bool withNew)
for(int4 i=2;i<op->numInput()-1;++i)
pushOp(&comma,op);
for(int4 i=op->numInput()-1;i>=2;--i)
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
else if (op->numInput()==3) { // One parameter
pushVnImplied(op->getIn(2),op,mods);
pushVn(op->getIn(2),op,mods);
}
else { // A void function
pushAtom(Atom("",blanktoken,EmitXml::no_color));
@ -652,7 +652,7 @@ void PrintC::opReturn(const PcodeOp *op)
emit->tagOp("return",EmitXml::keyword_color,op);
if (op->numInput()>1) {
emit->spaces(1);
pushVnImplied(op->getIn(1),op,mods);
pushVn(op->getIn(1),op,mods);
}
return;
case PcodeOp::noreturn: // Previous instruction does not exit
@ -677,7 +677,7 @@ void PrintC::opReturn(const PcodeOp *op)
void PrintC::opIntZext(const PcodeOp *op,const PcodeOp *readOp)
{
if (castStrategy->isZextCast(op->getOut()->getHigh()->getType(),op->getIn(0)->getHigh()->getType())) {
if (castStrategy->isZextCast(op->getOut()->getHighTypeDefFacing(),op->getIn(0)->getHighTypeReadFacing(op))) {
if (option_hide_exts && castStrategy->isExtensionCastImplied(op,readOp))
opHiddenFunc(op);
else
@ -690,7 +690,7 @@ void PrintC::opIntZext(const PcodeOp *op,const PcodeOp *readOp)
void PrintC::opIntSext(const PcodeOp *op,const PcodeOp *readOp)
{
if (castStrategy->isSextCast(op->getOut()->getHigh()->getType(),op->getIn(0)->getHigh()->getType())) {
if (castStrategy->isSextCast(op->getOut()->getHighTypeDefFacing(),op->getIn(0)->getHighTypeReadFacing(op))) {
if (option_hide_exts && castStrategy->isExtensionCastImplied(op,readOp))
opHiddenFunc(op);
else
@ -707,22 +707,33 @@ void PrintC::opBoolNegate(const PcodeOp *op)
{
if (isSet(negatetoken)) { // Check if we are negated by a previous BOOL_NEGATE
unsetMod(negatetoken); // If so, mark that negatetoken is consumed
pushVnImplied(op->getIn(0),op,mods); // Don't print ourselves, but print our input unmodified
pushVn(op->getIn(0),op,mods); // Don't print ourselves, but print our input unmodified
}
else if (checkPrintNegation(op->getIn(0))) { // If the next operator can be flipped
pushVnImplied(op->getIn(0),op,mods|negatetoken); // Don't print ourselves, but print a modified input
pushVn(op->getIn(0),op,mods|negatetoken); // Don't print ourselves, but print a modified input
}
else {
pushOp(&boolean_not,op); // Otherwise print ourselves
pushVnImplied(op->getIn(0),op,mods); // And print our input
pushVn(op->getIn(0),op,mods); // And print our input
}
}
void PrintC::opSubpiece(const PcodeOp *op)
{
if (castStrategy->isSubpieceCast(op->getOut()->getHigh()->getType(),
op->getIn(0)->getHigh()->getType(),
if (op->doesSpecialPrinting()) { // Special printing means it is a field extraction
int4 offset;
Datatype *ct;
const TypeField *field = TypeOpSubpiece::testExtraction(true, op, ct, offset);
if (field != (const TypeField *)0 && offset == 0) {
pushOp(&object_member,op);
pushVn(op->getIn(0), op, mods);
pushAtom(Atom(field->name,fieldtoken,EmitXml::no_color,ct,field->ident,op));
return;
}
}
if (castStrategy->isSubpieceCast(op->getOut()->getHighTypeDefFacing(),
op->getIn(0)->getHighTypeReadFacing(op),
(uint4)op->getIn(1)->getOffset()))
opTypeCast(op);
else
@ -735,7 +746,7 @@ void PrintC::opPtradd(const PcodeOp *op)
bool printval = isSet(print_load_value|print_store_value);
uint4 m = mods & ~(print_load_value|print_store_value);
if (!printval) {
TypePointer *tp = (TypePointer *)op->getIn(0)->getHigh()->getType();
TypePointer *tp = (TypePointer *)op->getIn(0)->getHighTypeReadFacing(op);
if (tp->getMetatype() == TYPE_PTR) {
if (tp->getPtrTo()->getMetatype() == TYPE_ARRAY)
printval = true;
@ -747,8 +758,8 @@ void PrintC::opPtradd(const PcodeOp *op)
pushOp(&binary_plus,op);
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
pushVnImplied(op->getIn(1),op,m);
pushVnImplied(op->getIn(0),op,m);
pushVn(op->getIn(1),op,m);
pushVn(op->getIn(0),op,m);
}
static bool isValueFlexible(const Varnode *vn)
@ -791,7 +802,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
in0 = op->getIn(0);
in1const = op->getIn(1)->getOffset();
ptype = (TypePointer *)in0->getHigh()->getType();
ptype = (TypePointer *)in0->getHighTypeReadFacing(op);
if (ptype->getMetatype() != TYPE_PTR) {
clear();
throw LowlevelError("PTRSUB off of non-pointer type");
@ -808,7 +819,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
valueon = (mods & (print_load_value|print_store_value)) != 0;
flex = isValueFlexible(in0);
if (ct->getMetatype() == TYPE_STRUCT) {
if (ct->getMetatype() == TYPE_STRUCT || ct->getMetatype() == TYPE_UNION) {
uintb suboff = in1const; // How far into container
if (ptrel != (TypePointerRel *)0) {
suboff += ptrel->getPointerOffset();
@ -817,34 +828,48 @@ void PrintC::opPtrsub(const PcodeOp *op)
// Special case where we do not print a field
pushTypePointerRel(op);
if (flex)
pushVnImplied(in0,op,m | print_load_value);
pushVn(in0,op,m | print_load_value);
else
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
return;
}
}
suboff = AddrSpace::addressToByte(suboff,ptype->getWordSize());
string fieldname;
Datatype *fieldtype;
int4 fieldoffset;
int4 fieldid;
int4 newoff;
const TypeField *fld = ((TypeStruct *)ct)->getField((int4)suboff,0,&newoff);
if (fld == (const TypeField *)0) {
if (ct->getSize() <= suboff) {
clear();
throw LowlevelError("PTRSUB out of bounds into struct");
}
// Try to match the Ghidra's default field name from DataTypeComponent.getDefaultFieldName
ostringstream s;
s << "field_0x" << hex << suboff;
fieldname = s.str();
fieldtype = (Datatype *)0;
fieldoffset = suboff;
}
else {
if (ct->getMetatype() == TYPE_UNION) {
if (suboff != 0)
throw LowlevelError("PTRSUB accesses union with non-zero offset");
const Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *resUnion = fd->getUnionField(ptype, op, -1);
if (resUnion == (const ResolvedUnion *)0 || resUnion->getFieldNum() < 0)
throw LowlevelError("PTRSUB for union that does not resolve to a field");
const TypeField *fld = ((TypeUnion *)ct)->getField(resUnion->getFieldNum());
fieldid = fld->ident;
fieldname = fld->name;
fieldtype = fld->type;
fieldoffset = fld->offset;
}
else { // TYPE_STRUCT
const TypeField *fld = ((TypeStruct*)ct)->resolveTruncation((int4)suboff,0,&newoff);
if (fld == (const TypeField*)0) {
if (ct->getSize() <= suboff) {
clear();
throw LowlevelError("PTRSUB out of bounds into struct");
}
// Try to match the Ghidra's default field name from DataTypeComponent.getDefaultFieldName
ostringstream s;
s << "field_0x" << hex << suboff;
fieldname = s.str();
fieldtype = (Datatype*)0;
fieldid = suboff;
}
else {
fieldname = fld->name;
fieldtype = fld->type;
fieldid = fld->ident;
}
}
arrayvalue = false;
// The '&' is dropped if the output type is an array
@ -859,16 +884,16 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&object_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
pushVn(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldid,op));
}
else { // EMIT &( )->name
pushOp(&addressof,op);
pushOp(&pointer_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
pushVn(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldid,op));
}
}
else { // Not printing an ampersand
@ -878,15 +903,15 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&object_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
pushVn(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldid,op));
}
else { // EMIT ( )->name
pushOp(&pointer_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
pushVn(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldid,op));
}
if (arrayvalue)
push_integer(0,4,false,(Varnode *)0,op);
@ -927,7 +952,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
// we can't use a cast in its description, so turn off
// casting when printing the partial symbol
// Datatype *exttype = ((mods & print_store_value)!=0) ? (Datatype *)0 : ct;
pushPartialSymbol(symbol,off,0,(Varnode *)0,op,(Datatype *)0);
pushPartialSymbol(symbol,off,0,(Varnode *)0,op,-1);
}
}
if (arrayvalue)
@ -947,13 +972,13 @@ void PrintC::opPtrsub(const PcodeOp *op)
// becomes struct->arrayfield[i]
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
}
else { // EMIT *( )
pushOp(&dereference,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
}
}
else {
@ -961,7 +986,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&subscript,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
push_integer(0,4,false,(Varnode *)0,op);
}
else { // EMIT (* )[0]
@ -969,7 +994,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&dereference,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
push_integer(0,4,false,(Varnode *)0,op);
}
}
@ -988,7 +1013,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
void PrintC::opSegmentOp(const PcodeOp *op)
{
pushVnImplied(op->getIn(2),op,mods);
pushVn(op->getIn(2),op,mods);
}
void PrintC::opCpoolRefOp(const PcodeOp *op)
@ -1033,7 +1058,7 @@ void PrintC::opCpoolRefOp(const PcodeOp *op)
pushOp(&function_call,op);
pushAtom(Atom(rec->getToken(),functoken,EmitXml::funcname_color,op,outvn));
pushOp(&comma,(const PcodeOp *)0);
pushVnImplied(vn0,op,mods);
pushVn(vn0,op,mods);
pushAtom(Atom(dt->getName(),syntax,EmitXml::type_color,op,outvn));
break;
}
@ -1056,7 +1081,7 @@ void PrintC::opCpoolRefOp(const PcodeOp *op)
}
else {
pushOp(&pointer_member, op);
pushVnImplied(vn0, op, mods);
pushVn(vn0, op, mods);
pushAtom(Atom(rec->getToken(), syntax, color, op, outvn));
}
break;
@ -1081,7 +1106,7 @@ void PrintC::opNewOp(const PcodeOp *op)
nm = "<unused>";
}
else {
Datatype *dt = outvn->getType();
Datatype *dt = outvn->getTypeDefFacing();
while (dt->getMetatype() == TYPE_PTR) {
dt = ((TypePointer *)dt)->getPtrTo();
}
@ -1089,14 +1114,14 @@ void PrintC::opNewOp(const PcodeOp *op)
}
pushOp(&subscript,op);
pushAtom(Atom(nm,optoken,EmitXml::type_color,op));
pushVnImplied(vn1,op,mods);
pushVn(vn1,op,mods);
return;
}
}
// This printing is used only if the 'new' operator doesn't feed directly into a constructor
pushOp(&function_call,op);
pushAtom(Atom("new",optoken,EmitXml::keyword_color,op,outvn));
pushVnImplied(vn0,op,mods);
pushVn(vn0,op,mods);
}
void PrintC::opInsertOp(const PcodeOp *op)
@ -1133,7 +1158,7 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) {
Symbol *sym = vn->getHigh()->getSymbol();
if (sym != (Symbol *)0) {
if (sym->isNameLocked() && (sym->getCategory() == 1)) {
if (sym->isNameLocked() && (sym->getCategory() == Symbol::equate)) {
if (pushEquate(val,sz,(EquateSymbol *)sym,vn,op))
return;
}
@ -1448,7 +1473,7 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn,con
if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) {
Symbol *sym = vn->getHigh()->getSymbol();
if (sym != (Symbol *)0) {
if (sym->isNameLocked() && (sym->getCategory() == 1)) {
if (sym->isNameLocked() && (sym->getCategory() == Symbol::equate)) {
if (pushEquate(val,vn->getSize(),(EquateSymbol *)sym,vn,op))
return;
}
@ -1627,6 +1652,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,
case TYPE_CODE:
case TYPE_ARRAY:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_PARTIALSTRUCT:
break;
}
@ -1723,7 +1749,7 @@ void PrintC::pushAnnotation(const Varnode *vn,const PcodeOp *op)
pushSymbol(entry->getSymbol(),vn,op);
else {
int4 symboloff = vn->getOffset() - entry->getFirst();
pushPartialSymbol(entry->getSymbol(),symboloff,size,vn,op,(Datatype *)0);
pushPartialSymbol(entry->getSymbol(),symboloff,size,vn,op,-1);
}
}
else {
@ -1743,7 +1769,7 @@ void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
EmitXml::syntax_highlight tokenColor;
if (sym->getScope()->isGlobal())
tokenColor = EmitXml::global_color;
else if (sym->getCategory() == 0)
else if (sym->getCategory() == Symbol::function_parameter)
tokenColor = EmitXml::param_color;
else
tokenColor = EmitXml::var_color;
@ -1777,7 +1803,7 @@ void PrintC::pushUnnamedLocation(const Address &addr,
void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
const Varnode *vn,const PcodeOp *op,
Datatype *outtype)
int4 inslot)
{
// We need to print "bottom up" in order to get parentheses right
// I.e. we want to print globalstruct.arrayfield[0], rather than
@ -1788,12 +1814,19 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
Datatype *ct = sym->getType();
while(ct != (Datatype *)0) {
if (((sz==0)||(sz==ct->getSize()))&&(off==0))
break; // Found the full partial
if (off == 0) {
if (sz == 0 || (sz == ct->getSize() && (!ct->needsResolution() || ct->getMetatype()==TYPE_PTR)))
break;
}
bool succeeded = false;
if (ct->getMetatype()==TYPE_STRUCT) {
if (ct->needsResolution() && ct->getSize() == sz) {
Datatype *outtype = ct->findResolve(op, inslot);
if (outtype == ct)
break; // Turns out we don't resolve to the field
}
const TypeField *field;
field = ((TypeStruct *)ct)->getField(off,sz,&off);
field = ((TypeStruct *)ct)->resolveTruncation(off,sz,&off);
if (field != (const TypeField *)0) {
stack.emplace_back();
PartialSymbolEntry &entry( stack.back() );
@ -1822,13 +1855,32 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
succeeded = true;
}
}
else if ((outtype != (Datatype *)0)&&
castStrategy->isSubpieceCastEndian(outtype,ct,off,
sym->getFirstWholeMap()->getAddr().getSpace()->isBigEndian())) {
// Treat truncation as SUBPIECE style cast
finalcast = outtype;
ct = (Datatype *)0;
succeeded = true;
else if (ct->getMetatype() == TYPE_UNION) {
const TypeField *field;
field = ((TypeUnion *)ct)->findTruncation(off,op,inslot,off);
if (field != (const TypeField*)0) {
stack.emplace_back();
PartialSymbolEntry &entry(stack.back());
entry.token = &object_member;
entry.field = field;
entry.parent = ct;
entry.fieldname = entry.field->name;
entry.hilite = EmitXml::no_color;
ct = field->type;
succeeded = true;
}
else if (ct->getSize() == sz)
break; // Turns out we don't need to resolve the field
}
else if (inslot >= 0) {
Datatype *outtype = vn->getHigh()->getType();
if (castStrategy->isSubpieceCastEndian(outtype,ct,off,
sym->getFirstWholeMap()->getAddr().getSpace()->isBigEndian())) {
// Treat truncation as SUBPIECE style cast
finalcast = outtype;
ct = (Datatype*)0;
succeeded = true;
}
}
if (!succeeded) { // Subtype was not good
stack.emplace_back();
@ -1860,7 +1912,7 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
if (field == (const TypeField *)0)
pushAtom(Atom(stack[i].fieldname,syntax,stack[i].hilite,op));
else
pushAtom(Atom(stack[i].fieldname,fieldtoken,stack[i].hilite,stack[i].parent,field->offset));
pushAtom(Atom(stack[i].fieldname,fieldtoken,stack[i].hilite,stack[i].parent,field->ident,op));
}
}
@ -1882,6 +1934,39 @@ void PrintC::pushMismatchSymbol(const Symbol *sym,int4 off,int4 sz,
pushUnnamedLocation(vn->getAddr(),vn,op);
}
void PrintC::pushImpliedField(const Varnode *vn,const PcodeOp *op)
{
bool proceed = false;
Datatype *parent = vn->getHigh()->getType();
const TypeField *field;
if (parent->needsResolution() && parent->getMetatype() != TYPE_PTR) {
const Funcdata *fd = op->getParent()->getFuncdata();
int4 slot = op->getSlot(vn);
const ResolvedUnion *res = fd->getUnionField(parent, op, slot);
if (res != (const ResolvedUnion *)0 && res->getFieldNum() >= 0) {
if (parent->getMetatype() == TYPE_STRUCT && res->getFieldNum() == 0) {
field = &(*((TypeStruct *)parent)->beginField());
proceed = true;
}
else if (parent->getMetatype() == TYPE_UNION) {
field = ((TypeUnion *)parent)->getField(res->getFieldNum());
proceed = true;
}
}
}
const PcodeOp *defOp = vn->getDef();
if (!proceed) {
// Just push original op
defOp->getOpcode()->push(this,defOp,op);
return;
}
pushOp(&object_member,op);
defOp->getOpcode()->push(this,defOp,op);
pushAtom(Atom(field->name,fieldtoken,EmitXml::no_color,parent,field->ident,op));
}
/// Print all the components making up the data-type, using the \b struct keyword
/// \param ct is the structure data-type
void PrintC::emitStructDefinition(const TypeStruct *ct)
@ -2038,14 +2123,14 @@ void PrintC::emitLocalVarDecls(const Funcdata *fd)
{
bool notempty = false;
if (emitScopeVarDecls(fd->getScopeLocal(),-1))
if (emitScopeVarDecls(fd->getScopeLocal(),Symbol::no_category))
notempty = true;
ScopeMap::const_iterator iter,enditer;
iter = fd->getScopeLocal()->childrenBegin();
enditer = fd->getScopeLocal()->childrenEnd();
while(iter!=enditer) {
Scope *l1 = (*iter).second;
if (emitScopeVarDecls(l1,-1))
if (emitScopeVarDecls(l1,Symbol::no_category))
notempty = true;
++iter;
}
@ -2226,7 +2311,7 @@ bool PrintC::emitInplaceOp(const PcodeOp *op)
if (op->getOut()->getHigh() != vn->getHigh()) return false;
pushOp(tok,op);
pushVnExplicit(vn,op);
pushVnImplied(op->getIn(1),op,mods);
pushVn(op->getIn(1),op,mods);
recurse();
return true;
}
@ -2238,14 +2323,14 @@ void PrintC::emitExpression(const PcodeOp *op)
if (outvn != (Varnode *)0) {
if (option_inplace_ops && emitInplaceOp(op)) return;
pushOp(&assignment,op);
pushVnLHS(outvn,op);
pushSymbolDetail(outvn,op,false);
}
else if (op->doesSpecialPrinting()) {
// Printing of constructor syntax
const PcodeOp *newop = op->getIn(1)->getDef();
outvn = newop->getOut();
pushOp(&assignment,newop);
pushVnLHS(outvn,newop);
pushSymbolDetail(outvn,newop,false);
opConstructor(op,true);
recurse();
return;
@ -2377,7 +2462,7 @@ void PrintC::emitGlobalVarDeclsRecursive(Scope *symScope)
{
if (!symScope->isGlobal()) return;
emitScopeVarDecls(symScope,-1);
emitScopeVarDecls(symScope,Symbol::no_category);
ScopeMap::const_iterator iter,enditer;
iter = symScope->childrenBegin();
enditer = symScope->childrenEnd();