diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index ec05214ebd..d3bf7f5948 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -1260,6 +1260,14 @@ void BlockGraph::printRaw(ostream &s) const (*iter)->printRaw(s); } +PcodeOp *BlockGraph::firstOp(void) const + +{ + if (getSize() == 0) + return (PcodeOp *)0; + return getBlock(0)->firstOp(); +} + FlowBlock *BlockGraph::nextFlowAfter(const FlowBlock *bl) const { @@ -2255,6 +2263,13 @@ Address BlockBasic::getStop(void) const return range->getLastAddr(); } +PcodeOp *BlockBasic::firstOp(void) const + +{ + if (op.empty()) return (PcodeOp *)0; + return (PcodeOp *)op.front(); +} + PcodeOp *BlockBasic::lastOp(void) const { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index 69c3465647..102a9a7840 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh @@ -175,6 +175,7 @@ public: virtual void printRaw(ostream &s) const {} ///< Print raw instructions contained in \b this FlowBlock virtual void emit(PrintLanguage *lng) const; ///emitBlockGraph(this); } + virtual PcodeOp *firstOp(void) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual void finalTransform(Funcdata &data); virtual void finalizePrinting(Funcdata &data) const; @@ -400,6 +402,7 @@ public: virtual void printRaw(ostream &s) const; virtual void emit(PrintLanguage *lng) const { lng->emitBlockBasic(this); } virtual const FlowBlock *getExitLeaf(void) const { return this; } + virtual PcodeOp *firstOp(void) const; virtual PcodeOp *lastOp(void) const; virtual bool negateCondition(bool toporbottom); virtual FlowBlock *getSplitPoint(void); @@ -440,6 +443,7 @@ public: virtual void printRaw(ostream &s) const { copy->printRaw(s); } virtual void emit(PrintLanguage *lng) const { lng->emitBlockCopy(this); } virtual const FlowBlock *getExitLeaf(void) const { return this; } + virtual PcodeOp *firstOp(void) const { return copy->firstOp(); } virtual PcodeOp *lastOp(void) const { return copy->lastOp(); } virtual bool negateCondition(bool toporbottom) { bool res = copy->negateCondition(true); FlowBlock::negateCondition(toporbottom); return res; } virtual FlowBlock *getSplitPoint(void) { return copy->getSplitPoint(); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc index 3f3dd23c8f..f4c25bfdf4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc @@ -244,6 +244,19 @@ void EmitMarkup::tagLabel(const string &name,syntax_highlight hl,const AddrSpace encoder->closeElement(ELEM_LABEL); } +void EmitMarkup::tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value) + +{ + encoder->openElement(ELEM_VALUE); + if (hl != no_color) + encoder->writeUnsignedInteger(ATTRIB_COLOR,hl); + encoder->writeUnsignedInteger(ATTRIB_OFF, value); + if (op != (const PcodeOp *)0) + encoder->writeUnsignedInteger(ATTRIB_OPREF, op->getTime()); + encoder->writeString(ATTRIB_CONTENT,name); + encoder->closeElement(ELEM_VALUE); +} + void EmitMarkup::print(const string &data,syntax_highlight hl) { @@ -357,6 +370,9 @@ void TokenSplit::print(Emit *emit) const case label_t: // tagLabel emit->tagLabel(tok,hl,ptr_second.spc,off); break; + case case_t: // tagCaseLabel + emit->tagCaseLabel(tok, hl, op, off); + break; case synt_t: // print emit->print(tok,hl); break; @@ -448,6 +464,9 @@ void TokenSplit::printDebug(ostream &s) const case label_t: // tagLabel s << "label_t"; break; + case case_t: // tagCaseLabel + s << "case_t"; + break; case synt_t: // print s << "synt_t"; break; @@ -1011,6 +1030,15 @@ void EmitPrettyPrint::tagLabel(const string &name,syntax_highlight hl,const Addr scan(); } +void EmitPrettyPrint::tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value) + +{ + checkstring(); + TokenSplit &tok( tokqueue.push() ); + tok.tagCaseLabel(name, hl, op, value); + scan(); +} + void EmitPrettyPrint::print(const string &data,syntax_highlight hl) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh index 6e7124ccc5..ca01a613da 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.hh @@ -292,6 +292,15 @@ public: /// \param off is the offset of the code address being labeled virtual void tagLabel(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off)=0; + /// \brief Emit a \e case label constant + /// + /// A string describing the \e switch variable value is emitted and starting PcodeOp of the \e case block. + /// \param name is the character data of the value + /// \param hl indicates how the value should be highlighted + /// \param op is the first PcodeOp in the \e case block + /// \param value is the raw integer value underlying the switch value + virtual void tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value)=0; + /// \brief Emit other (more unusual) syntax as part of source code generation /// /// This method is used to emit syntax not covered by the other methods, such as @@ -473,6 +482,7 @@ public: virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op); virtual void tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off); virtual void tagLabel(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off); + virtual void tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value); virtual void print(const string &data,syntax_highlight hl=no_color); virtual int4 openParen(const string &paren,int4 id=0); virtual void closeParen(const string &paren,int4 id); @@ -522,6 +532,8 @@ public: *s << name; } virtual void tagLabel(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off) { *s << name; } + virtual void tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value) { + *s << name; } virtual void print(const string &data,syntax_highlight hl=no_color) { *s << data; } virtual int4 openParen(const string &paren,int4 id=0) { @@ -584,6 +596,7 @@ public: field_t, ///< A field name for a structured data-type comm_t, ///< Part of a comment block label_t, ///< A code label + case_t, ///< A case label synt_t, ///< Other unspecified syntax opar_t, ///< Open parenthesis cpar_t, ///< Close parenthesis @@ -774,6 +787,16 @@ public: tok = name; size = tok.size(); ptr_second.spc=s; off=o; tagtype=label_t; delimtype=tokenstring; hl=h; } + /// \brief Create a \e case label token + /// + /// \param name is the character data of the label + /// \param h indicates how the label should be highlighted + /// \param inOp is the first PcodeOp in the \e case block + /// \param intValue is the constant value underlying the case label + void tagCaseLabel(const string &name,EmitMarkup::syntax_highlight h,const PcodeOp *inOp,uintb intValue) { + tok = name; size = tok.size(); op = inOp; off = intValue; + tagtype=case_t; delimtype=tokenstring; hl=h; } + /// \brief Create a token for other (more unusual) syntax in source code /// /// \param data is the character data of the syntax being emitted @@ -1019,6 +1042,7 @@ public: virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op); virtual void tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off); virtual void tagLabel(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off); + virtual void tagCaseLabel(const string &name,syntax_highlight hl,const PcodeOp *op,uintb value); virtual void print(const string &data,syntax_highlight hl=no_color); virtual int4 openParen(const string &paren,int4 id=0); virtual void closeParen(const string &paren,int4 id); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index 25afd2e439..2db668b566 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -324,7 +324,7 @@ void PrintC::pushTypeEnd(const Datatype *ct) else if (ct->getMetatype()==TYPE_ARRAY) { const TypeArray *ctarray = (const TypeArray *)ct; ct = ctarray->getBase(); - push_integer(ctarray->numElements(),4,false, + push_integer(ctarray->numElements(),4,false,syntax, (const Varnode *)0,(const PcodeOp *)0); } else if (ct->getMetatype()==TYPE_CODE) { @@ -967,7 +967,7 @@ void PrintC::opPtrsub(const PcodeOp *op) pushAtom(Atom(fieldname,fieldtoken,EmitMarkup::no_color,ct,fieldid,op)); } if (arrayvalue) - push_integer(0,4,false,(Varnode *)0,op); + push_integer(0,4,false,syntax,(Varnode *)0,op); } } else if (ct->getMetatype() == TYPE_SPACEBASE) { @@ -1009,7 +1009,7 @@ void PrintC::opPtrsub(const PcodeOp *op) } } if (arrayvalue) - push_integer(0,4,false,(Varnode *)0,op); + push_integer(0,4,false,syntax,(Varnode *)0,op); } else if (ct->getMetatype() == TYPE_ARRAY) { if (in1const != 0) { @@ -1040,7 +1040,7 @@ void PrintC::opPtrsub(const PcodeOp *op) if (ptrel != (TypePointerRel *)0) pushTypePointerRel(op); pushVn(in0,op,m); - push_integer(0,4,false,(Varnode *)0,op); + push_integer(0,4,false,syntax,(Varnode *)0,op); } else { // EMIT (* )[0] pushOp(&subscript,op); @@ -1048,7 +1048,7 @@ void PrintC::opPtrsub(const PcodeOp *op) if (ptrel != (TypePointerRel *)0) pushTypePointerRel(op); pushVn(in0,op,m); - push_integer(0,4,false,(Varnode *)0,op); + push_integer(0,4,false,syntax,(Varnode *)0,op); } } } @@ -1198,9 +1198,10 @@ void PrintC::opExtractOp(const PcodeOp *op) /// \param val is the given integer value /// \param sz is the size (in bytes) to associate with the integer /// \param sign is set to \b true if the integer should be treated as a signed value +/// \param tag is the type of token to associate with the integer /// \param vn is the Varnode holding the value /// \param op is the PcodeOp using the value -void PrintC::push_integer(uintb val,int4 sz,bool sign, +void PrintC::push_integer(uintb val,int4 sz,bool sign,tagtype tag, const Varnode *vn,const PcodeOp *op) { bool print_negsign; @@ -1279,10 +1280,7 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign, if (force_sized_token) t << sizeSuffix; - if (vn==(const Varnode *)0) - pushAtom(Atom(t.str(),syntax,EmitMarkup::const_color,op)); - else - pushAtom(Atom(t.str(),vartoken,EmitMarkup::const_color,op,vn)); + pushAtom(Atom(t.str(),tag,EmitMarkup::const_color,op,vn,val)); } /// \brief Push a constant with a floating-point data-type to the RPN stack @@ -1292,9 +1290,10 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign, /// is decided upon, and the constant is pushed as a single token. /// \param val is the given encoded floating-point value /// \param sz is the size (in bytes) of the encoded value +/// \param tag is the type of token to associate with the float /// \param vn is the Varnode holding the value /// \param op is the PcodeOp using the value -void PrintC::push_float(uintb val,int4 sz,const Varnode *vn,const PcodeOp *op) +void PrintC::push_float(uintb val,int4 sz,tagtype tag,const Varnode *vn,const PcodeOp *op) { string token; @@ -1345,10 +1344,7 @@ void PrintC::push_float(uintb val,int4 sz,const Varnode *vn,const PcodeOp *op) } } } - if (vn==(const Varnode *)0) - pushAtom(Atom(token,syntax,EmitMarkup::const_color,op)); - else - pushAtom(Atom(token,vartoken,EmitMarkup::const_color,op,vn)); + pushAtom(Atom(token,tag,EmitMarkup::const_color,op,vn,val)); } void PrintC::printUnicode(ostream &s,int4 onechar) const @@ -1410,16 +1406,16 @@ void PrintC::pushType(const Datatype *ct) /// A single Atom representing the boolean value is emitted /// \param val is the boolean value (non-zero for \b true) /// \param ct is the data-type associated with the value +/// \param tag is the type of token to associate with the boolean value /// \param vn is the Varnode holding the value /// \param op is the PcodeOp using the value -void PrintC::pushBoolConstant(uintb val,const TypeBase *ct, - const Varnode *vn, - const PcodeOp *op) +void PrintC::pushBoolConstant(uintb val,const TypeBase *ct,tagtype tag, + const Varnode *vn,const PcodeOp *op) { if (val != 0) - pushAtom(Atom(KEYWORD_TRUE,vartoken,EmitMarkup::const_color,op,vn)); + pushAtom(Atom(KEYWORD_TRUE,tag,EmitMarkup::const_color,op,vn,val)); else - pushAtom(Atom(KEYWORD_FALSE,vartoken,EmitMarkup::const_color,op,vn)); + pushAtom(Atom(KEYWORD_FALSE,tag,EmitMarkup::const_color,op,vn,val)); } /// \brief Return \b true if this language requires a prefix when expressing \e wide characters @@ -1524,9 +1520,10 @@ void PrintC::resetDefaultsPrintC(void) /// Handle unicode, wide characters, etc. Characters come in with the compiler's raw encoding. /// \param val is the constant value /// \param ct is data-type attached to the value +/// \param tag is the type of token to associate with the character /// \param vn is the Varnode holding the value /// \param op is the PcodeOp using the value -void PrintC::pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn,const PcodeOp *op) +void PrintC::pushCharConstant(uintb val,const Datatype *ct,tagtype tag,const Varnode *vn,const PcodeOp *op) { uint4 displayFormat = 0; @@ -1546,7 +1543,7 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn,con } if (displayFormat != 0 && displayFormat != Symbol::force_char) { if (!castStrategy->caresAboutCharRepresentation(vn, op)) { - push_integer(val, ct->getSize(), isSigned, vn, op); + push_integer(val, ct->getSize(), isSigned, tag, vn, op); return; } } @@ -1556,7 +1553,7 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn,con // unicode code-point. Its either part of a multi-byte UTF-8 encoding or an unknown // code-page value. In either case, we print as an integer or an escape sequence. if (displayFormat != Symbol::force_hex && displayFormat != Symbol::force_char) { - push_integer(val, 1, isSigned, vn, op); + push_integer(val, 1, isSigned, tag, vn, op); return; } displayFormat = Symbol::force_hex; // Fallthru but force a hex representation @@ -1574,7 +1571,7 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn,con else printUnicode(t,(int4)val); t << '\''; - pushAtom(Atom(t.str(),vartoken,EmitMarkup::const_color,op,vn)); + pushAtom(Atom(t.str(),tag,EmitMarkup::const_color,op,vn,val)); } /// \brief Push an enumerated value to the RPN stack @@ -1583,11 +1580,11 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn,con /// enumeration or where the value cannot be expressed using named elements /// \param val is the enumerated value being pushed /// \param ct is the enumerated data-type attached to the value +/// \param tag is the type of token to associate with the value /// \param vn is the Varnode holding the value /// \param op is the PcodeOp using the value -void PrintC::pushEnumConstant(uintb val,const TypeEnum *ct, - const Varnode *vn, - const PcodeOp *op) +void PrintC::pushEnumConstant(uintb val,const TypeEnum *ct,tagtype tag, + const Varnode *vn,const PcodeOp *op) { vector valnames; @@ -1598,10 +1595,10 @@ void PrintC::pushEnumConstant(uintb val,const TypeEnum *ct, for(int4 i=valnames.size()-1;i>0;--i) pushOp(&enum_cat,op); for(int4 i=0;igetSize(),false,vn,op); + push_integer(val,ct->getSize(),false,tag,vn,op); // ostringstream s; // s << "BAD_ENUM(0x" << hex << val << ")"; // pushAtom(Atom(s.str(),vartoken,EmitMarkup::const_color,op,vn)); @@ -1650,8 +1647,7 @@ bool PrintC::pushPtrCharConstant(uintb val,const TypePointer *ct,const Varnode * /// \param op is the PcodeOp using the value /// \return \b true if a name was pushed to the RPN stack, return \b false otherwise bool PrintC::pushPtrCodeConstant(uintb val,const TypePointer *ct, - const Varnode *vn, - const PcodeOp *op) + const Varnode *vn,const PcodeOp *op) { AddrSpace *spc = glb->getDefaultCodeSpace(); Funcdata *fd = (Funcdata *)0; @@ -1664,7 +1660,7 @@ bool PrintC::pushPtrCodeConstant(uintb val,const TypePointer *ct, return false; } -void PrintC::pushConstant(uintb val,const Datatype *ct, +void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag, const Varnode *vn, const PcodeOp *op) { @@ -1672,25 +1668,25 @@ void PrintC::pushConstant(uintb val,const Datatype *ct, switch(ct->getMetatype()) { case TYPE_UINT: if (ct->isCharPrint()) - pushCharConstant(val,(TypeChar *)ct,vn,op); + pushCharConstant(val,(TypeChar *)ct,tag,vn,op); else if (ct->isEnumType()) - pushEnumConstant(val,(TypeEnum *)ct,vn,op); + pushEnumConstant(val,(TypeEnum *)ct,tag,vn,op); else - push_integer(val,ct->getSize(),false,vn,op); + push_integer(val,ct->getSize(),false,tag,vn,op); return; case TYPE_INT: if (ct->isCharPrint()) - pushCharConstant(val,(TypeChar *)ct,vn,op); + pushCharConstant(val,(TypeChar *)ct,tag,vn,op); else if (ct->isEnumType()) - pushEnumConstant(val,(TypeEnum *)ct,vn,op); + pushEnumConstant(val,(TypeEnum *)ct,tag,vn,op); else - push_integer(val,ct->getSize(),true,vn,op); + push_integer(val,ct->getSize(),true,tag,vn,op); return; case TYPE_UNKNOWN: - push_integer(val,ct->getSize(),false,vn,op); + push_integer(val,ct->getSize(),false,tag,vn,op); return; case TYPE_BOOL: - pushBoolConstant(val,(const TypeBase *)ct,vn,op); + pushBoolConstant(val,(const TypeBase *)ct,tag,vn,op); return; case TYPE_VOID: clear(); @@ -1712,7 +1708,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct, } break; case TYPE_FLOAT: - push_float(val,ct->getSize(),vn,op); + push_float(val,ct->getSize(),tag,vn,op); return; case TYPE_SPACEBASE: case TYPE_CODE: @@ -1731,7 +1727,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct, pushMod(); if (!isSet(force_dec)) setMod(force_hex); - push_integer(val,ct->getSize(),false,vn,op); + push_integer(val,ct->getSize(),false,tag,vn,op); popMod(); } @@ -1765,14 +1761,14 @@ bool PrintC::pushEquate(uintb val,int4 sz,const EquateSymbol *sym,const Varnode if (modval == val) { pushOp(&binary_plus,(const PcodeOp *)0); pushSymbol(sym,vn,op); - push_integer(1, sz, false, (const Varnode *)0, (const PcodeOp *)0); + push_integer(1, sz, false, syntax, (const Varnode *)0, (const PcodeOp *)0); return true; } modval = (baseval - 1) & mask; if (modval == val) { pushOp(&binary_minus,(const PcodeOp *)0); pushSymbol(sym,vn,op); - push_integer(1, sz, false, (const Varnode *)0, (const PcodeOp *)0); + push_integer(1, sz, false, syntax, (const Varnode *)0, (const PcodeOp *)0); return true; } return false; @@ -2092,8 +2088,7 @@ void PrintC::emitEnumDefinition(const TypeEnum *ct) emit->spaces(1); emit->print(EQUALSIGN,EmitMarkup::no_color); emit->spaces(1); - push_integer((*iter).first,ct->getSize(),sign,(Varnode *)0, - (PcodeOp *)0); + push_integer((*iter).first,ct->getSize(),sign,syntax,(Varnode *)0,(PcodeOp *)0); recurse(); emit->print(SEMICOLON); ++iter; @@ -3087,12 +3082,15 @@ void PrintC::emitSwitchCase(int4 casenum,const BlockSwitch *switchbl) int4 i,num; uintb val; const Datatype *ct; + const PcodeOp *op; ct = switchbl->getSwitchType(); + op = switchbl->getCaseBlock(casenum)->firstOp(); if (switchbl->isDefaultCase(casenum)) { + val = switchbl->getLabel(casenum,0); emit->tagLine(); - emit->print(KEYWORD_DEFAULT,EmitMarkup::keyword_color); + emit->tagCaseLabel(KEYWORD_DEFAULT, EmitMarkup::keyword_color, op, val); emit->print(COLON); } else { @@ -3102,7 +3100,7 @@ void PrintC::emitSwitchCase(int4 casenum,const BlockSwitch *switchbl) emit->tagLine(); emit->print(KEYWORD_CASE,EmitMarkup::keyword_color); emit->spaces(1); - pushConstant(val,ct,(Varnode *)0,(PcodeOp *)0); + pushConstant(val,ct,casetoken,(Varnode *)0,op); recurse(); emit->print(COLON); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh index 9009784a8d..7e07905c71 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh @@ -159,12 +159,12 @@ protected: void emitSymbolScope(const Symbol *symbol); ///< Emit tokens resolving a symbol's scope virtual void pushTypeStart(const Datatype *ct,bool noident); ///< Push part of a data-type declaration onto the RPN stack, up to the identifier virtual void pushTypeEnd(const Datatype *ct); ///< Push the tail ends of a data-type declaration onto the RPN stack - void pushBoolConstant(uintb val,const TypeBase *ct,const Varnode *vn, - const PcodeOp *op); - void pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn, - const PcodeOp *op); - void pushEnumConstant(uintb val,const TypeEnum *ct,const Varnode *vn, - const PcodeOp *op); + void pushBoolConstant(uintb val,const TypeBase *ct,tagtype tag,const Varnode *vn, + const PcodeOp *op); + void pushCharConstant(uintb val,const Datatype *ct,tagtype tag,const Varnode *vn, + const PcodeOp *op); + void pushEnumConstant(uintb val,const TypeEnum *ct,tagtype tag,const Varnode *vn, + const PcodeOp *op); virtual bool pushPtrCharConstant(uintb val,const TypePointer *ct,const Varnode *vn, const PcodeOp *op); bool pushPtrCodeConstant(uintb val,const TypePointer *ct,const Varnode *vn, @@ -196,10 +196,10 @@ protected: bool printCharacterConstant(ostream &s,const Address &addr,Datatype *charType) const; int4 getHiddenThisSlot(const PcodeOp *op,FuncProto *fc); ///< Get position of "this" pointer needing to be hidden void resetDefaultsPrintC(void); ///< Set default values for options specific to PrintC - virtual void pushConstant(uintb val,const Datatype *ct, + virtual void pushConstant(uintb val,const Datatype *ct,tagtype tag, const Varnode *vn,const PcodeOp *op); virtual bool pushEquate(uintb val,int4 sz,const EquateSymbol *sym, - const Varnode *vn,const PcodeOp *op); + const Varnode *vn,const PcodeOp *op); virtual void pushAnnotation(const Varnode *vn,const PcodeOp *op); virtual void pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op); virtual void pushUnnamedLocation(const Address &addr, @@ -209,10 +209,10 @@ protected: virtual void pushMismatchSymbol(const Symbol *sym,int4 off,int4 sz, const Varnode *vn,const PcodeOp *op); virtual void pushImpliedField(const Varnode *vn,const PcodeOp *op); - virtual void push_integer(uintb val,int4 sz,bool sign, + virtual void push_integer(uintb val,int4 sz,bool sign,tagtype tag, const Varnode *vn, const PcodeOp *op); - virtual void push_float(uintb val,int4 sz,const Varnode *vn, + virtual void push_float(uintb val,int4 sz,tagtype tag,const Varnode *vn, const PcodeOp *op); virtual void printUnicode(ostream &s,int4 onechar) const; virtual void pushType(const Datatype *ct); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc index 5885f2d585..f50d80d49c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printjava.cc @@ -234,7 +234,7 @@ void PrintJava::opLoad(const PcodeOp *op) pushOp(&subscript,op); pushVn(op->getIn(1),op,m); if (printArrayRef) - push_integer(0,4,false,(Varnode *)0,op); + push_integer(0,4,false,syntax,(Varnode *)0,op); } void PrintJava::opStore(const PcodeOp *op) @@ -245,7 +245,7 @@ void PrintJava::opStore(const PcodeOp *op) if (needZeroArray(op->getIn(1))) { pushOp(&subscript,op); pushVn(op->getIn(1),op,m); - push_integer(0,4,false,(Varnode *)0,op); + push_integer(0,4,false,syntax,(Varnode *)0,op); pushVn(op->getIn(2),op,mods); } else { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.cc index c3b4317372..d29bd4e2a8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.cc @@ -223,7 +223,7 @@ void PrintLanguage::pushVnExplicit(const Varnode *vn,const PcodeOp *op) return; } if (vn->isConstant()) { - pushConstant(vn->getOffset(),vn->getHighTypeReadFacing(op),vn,op); + pushConstant(vn->getOffset(),vn->getHighTypeReadFacing(op),vartoken,vn,op); return; } pushSymbolDetail(vn,op,true); @@ -394,6 +394,9 @@ void PrintLanguage::emitAtom(const Atom &atom) case fieldtoken: emit->tagField(atom.name,atom.highlight,atom.ptr_second.ct,atom.offset,atom.op); break; + case casetoken: + emit->tagCaseLabel(atom.name, atom.highlight, atom.op, atom.ptr_second.intValue); + break; case blanktoken: break; // Print nothing } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh index ef5bbccc49..07e3bda04e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh @@ -167,6 +167,7 @@ public: optoken, ///< Emit atom as operator typetoken, ///< Emit atom as operator fieldtoken, ///< Emit atom as structure field + casetoken, ///< Emit atom as a \e case label blanktoken ///< For anonymous types }; @@ -215,6 +216,7 @@ public: const Varnode *vn; ///< A Varnode associated with the token const Funcdata *fd; ///< A function associated with the token const Datatype *ct; ///< A type associated with the token + uintb intValue; ///< An integer value associated with the token } ptr_second; ///< Other meta-data associated with the token int4 offset; ///< The offset (within the parent structure) for a \e field token @@ -241,6 +243,19 @@ public: /// \brief Construct a token for a function name Atom(const string &nm,tagtype t,EmitMarkup::syntax_highlight hl,const PcodeOp *o,const Funcdata *f) : name(nm) { type=t; highlight = hl; op = o; ptr_second.fd = f; } + + /// \brief Construct a token with an associated PcodeOp, Varnode, and constant value + Atom(const string &nm,tagtype t,EmitMarkup::syntax_highlight hl,const PcodeOp *o,const Varnode *v,uintb intValue) + : name(nm) { + type=t; + highlight = hl; + if (t==casetoken) + ptr_second.intValue = intValue; + else + ptr_second.vn = v; + op = o; + } + }; private: string name; ///< The name of the high-level language @@ -308,9 +323,10 @@ protected: /// The value is ultimately emitted based on its data-type and other associated mark-up /// \param val is the value of the constant /// \param ct is the data-type of the constant + /// \param tag is the type of token associated with the constant /// \param vn is the Varnode holding the constant (optional) /// \param op is the PcodeOp using the constant (optional) - virtual void pushConstant(uintb val,const Datatype *ct, + virtual void pushConstant(uintb val,const Datatype *ct,tagtype tag, const Varnode *vn,const PcodeOp *op)=0; /// \brief Push a constant marked up by and EquateSymbol onto the RPN stack diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangCaseToken.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangCaseToken.java new file mode 100644 index 0000000000..3030741fbb --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangCaseToken.java @@ -0,0 +1,151 @@ +/* ### + * 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. + */ +package ghidra.app.decompiler; + +import ghidra.program.model.address.Address; +import ghidra.program.model.data.AbstractIntegerDataType; +import ghidra.program.model.data.DataType; +import ghidra.program.model.pcode.*; +import ghidra.program.model.scalar.Scalar; + +/** + * A token representing a switch "case" label, or other constant not directly linked to data-flow. + * The token has an associated constant value and a data-type + */ +public class ClangCaseToken extends ClangToken { + + private PcodeOp op; // Op associated with the start of the "case" + private long value; // The constant value + + public ClangCaseToken(ClangNode par) { + super(par); + op = null; + value = 0; + } + + @Override + public boolean isVariableRef() { + return true; + } + + @Override + public Address getMinAddress() { + if (op == null) { + return null; + } + return op.getSeqnum().getTarget(); + } + + @Override + public Address getMaxAddress() { + if (op == null) { + return null; + } + return op.getSeqnum().getTarget(); + } + + @Override + public Varnode getVarnode() { + PcodeOp switchOp = getSwitchOp(); + if (switchOp == null) { + return null; + } + return switchOp.getInput(0); + } + + @Override + public PcodeOp getPcodeOp() { + return op; + } + + @Override + public HighVariable getHighVariable() { + Varnode vn = getVarnode(); + if (vn == null) { + return null; + } + return vn.getHigh(); + } + + @Override + public HighSymbol getHighSymbol(HighFunction highFunction) { + HighVariable hvar = getHighVariable(); + if (hvar != null) { + HighSymbol symbol = hvar.getSymbol(); + if (symbol != null) { + return symbol; + } + } + return null; + } + + @Override + public Scalar getScalar() { + HighVariable hvar = getHighVariable(); + if (hvar == null) { + return null; + } + DataType dt = hvar.getDataType(); + int sz = dt.getLength(); + if (sz < 1 || sz > 8) { + return null; + } + boolean isSigned = true; + if (dt instanceof AbstractIntegerDataType) { + isSigned = ((AbstractIntegerDataType) dt).isSigned(); + } + + return new Scalar(sz * 8, value, isSigned); + } + + /** + * @return the BRANCHIND PcodeOp that jumps to this label + */ + public PcodeOp getSwitchOp() { + if (op == null) { + return null; + } + PcodeBlockBasic parent = op.getParent(); + for (int i = 0; i < parent.getInSize(); ++i) { + PcodeBlockBasic in = (PcodeBlockBasic) parent.getIn(i); + PcodeOp switchOp = in.getLastOp(); + if (switchOp != null && switchOp.getOpcode() == PcodeOp.BRANCHIND) { + return switchOp; + } + } + return null; + } + + @Override + public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException { + for (;;) { + int attribId = decoder.getNextAttributeId(); + if (attribId == 0) { + break; + } + else if (attribId == AttributeId.ATTRIB_OPREF.id()) { + int refid = (int) decoder.readUnsignedInteger(); + op = pfactory.getOpRef(refid); + } + else if (attribId == AttributeId.ATTRIB_OFF.id()) { + value = decoder.readUnsignedInteger(); + } + } + decoder.rewindAttributes(); + super.decode(decoder, pfactory); + } + +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangToken.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangToken.java index 1018864087..d2b0d5fe63 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangToken.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangToken.java @@ -24,6 +24,7 @@ import java.util.List; //import ghidra.app.plugin.core.decompile.*; import ghidra.program.model.address.Address; import ghidra.program.model.pcode.*; +import ghidra.program.model.scalar.Scalar; /** * Class representing a source code language token. @@ -257,6 +258,9 @@ public class ClangToken implements ClangNode { else if (node == ELEM_FIELD.id()) { token = new ClangFieldToken(par); } + else if (node == ELEM_VALUE.id()) { + token = new ClangCaseToken(par); + } else { throw new DecoderException("Expecting token element"); } @@ -319,4 +323,13 @@ public class ClangToken implements ClangNode { public PcodeOp getPcodeOp() { return null; } + + /** + * If the token represents an underlying integer constant, return the constant as a Scalar. + * Otherwise return null. + * @return the Scalar that the token represents or null + */ + public Scalar getScalar() { + return null; + } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangVariableToken.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangVariableToken.java index bf28db8e4d..7c3f1b50bb 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangVariableToken.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/ClangVariableToken.java @@ -17,7 +17,10 @@ package ghidra.app.decompiler; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressFactory; +import ghidra.program.model.data.AbstractIntegerDataType; +import ghidra.program.model.data.DataType; import ghidra.program.model.pcode.*; +import ghidra.program.model.scalar.Scalar; /** * @@ -44,6 +47,34 @@ public class ClangVariableToken extends ClangToken { return op; } + @Override + public Scalar getScalar() { + if (varnode == null) { + return null; + } + + long offset = varnode.getOffset(); + int sz = varnode.getSize(); + HighVariable high = varnode.getHigh(); + if (!(high instanceof HighConstant)) { + return null; + } + + HighConstant constant = (HighConstant) high; + boolean isSigned = true; + DataType dt = constant.getDataType(); + if (dt instanceof AbstractIntegerDataType) { + isSigned = ((AbstractIntegerDataType) dt).isSigned(); + } + + if (sz > 8) { + // our Scalar can currently only handle long values + return null; + } + + return new Scalar(sz * 8, offset, isSigned); + } + @Override public boolean isVariableRef() { return true; diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/hover/ScalarValueDecompilerHover.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/hover/ScalarValueDecompilerHover.java index faeac467bd..4d2b395749 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/hover/ScalarValueDecompilerHover.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/hover/ScalarValueDecompilerHover.java @@ -21,15 +21,11 @@ import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.support.FieldLocation; import ghidra.GhidraOptions; import ghidra.app.decompiler.ClangToken; -import ghidra.app.decompiler.ClangVariableToken; import ghidra.app.decompiler.component.ClangTextField; import ghidra.app.plugin.core.hover.AbstractScalarOperandHover; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; -import ghidra.program.model.data.AbstractIntegerDataType; -import ghidra.program.model.data.DataType; import ghidra.program.model.listing.Program; -import ghidra.program.model.pcode.*; import ghidra.program.model.scalar.Scalar; import ghidra.program.util.ProgramLocation; @@ -82,35 +78,10 @@ public class ScalarValueDecompilerHover extends AbstractScalarOperandHover } ClangToken token = ((ClangTextField) field).getToken(fieldLocation); - if (!(token instanceof ClangVariableToken)) { + Scalar scalar = token.getScalar(); + if (scalar == null) { return null; } - - Varnode vn = ((ClangVariableToken) token).getVarnode(); - if (vn == null) { - return null; - } - - long offset = vn.getOffset(); - int sz = vn.getSize(); - HighVariable high = vn.getHigh(); - if (!(high instanceof HighConstant)) { - return null; - } - - HighConstant constant = (HighConstant) high; - boolean isSigned = true; - DataType dt = constant.getDataType(); - if (dt instanceof AbstractIntegerDataType) { - isSigned = ((AbstractIntegerDataType) dt).isSigned(); - } - - if (sz > 8) { - // our Scalar can currently only handle long values - return null; - } - - Scalar scalar = new Scalar(sz * 8, offset, isSigned); Address addr = token.getMinAddress(); String formatted = formatScalar(program, addr, scalar); return createTooltipComponent(formatted); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ListLinked.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ListLinked.java index 7ca691fe72..ac63a2c65d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ListLinked.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ListLinked.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +16,7 @@ package ghidra.program.model.pcode; import java.util.Iterator; + /** * * @@ -31,64 +31,60 @@ public class ListLinked { public LinkedNode previousNode; public LinkedNode nextNode; public T data; - - LinkedNode(LinkedNode prev,LinkedNode nxt,T d) { + + LinkedNode(LinkedNode prev, LinkedNode nxt, T d) { previousNode = prev; nextNode = nxt; data = d; } } - private class LinkedIterator implements Iterator { + private class LinkedIterator implements Iterator { private LinkedNode curNode; // Current node in the linked list being pointed at by this iterator public LinkedIterator(LinkedNode cur) { - curNode = cur; - } - - /* (non-Javadoc) - * @see java.util.Iterator#remove() - */ - public void remove() { - if (curNode.data == null) return; // Should probably throw an exception here - curNode.nextNode.previousNode = curNode.previousNode; - curNode.previousNode.nextNode = curNode.nextNode; - curNode = curNode.previousNode; + curNode = cur; } - /* (non-Javadoc) - * @see java.util.Iterator#hasNext() - */ + @Override + public void remove() { + if (curNode.data == null) { + return; // Should probably throw an exception here + } + curNode.nextNode.previousNode = curNode.previousNode; + curNode.previousNode.nextNode = curNode.nextNode; + curNode = curNode.previousNode; + } + + @Override public boolean hasNext() { return (curNode.nextNode.data != null); } - /* (non-Javadoc) - * @see java.util.Iterator#next() - */ + @Override public T next() { curNode = curNode.nextNode; return curNode.data; } - + public boolean hasPrevious() { return (curNode.data != null); } - + public Object previous() { curNode = curNode.previousNode; return curNode.nextNode.data; } } - + private LinkedNode terminal; // The boundary of the linked list - + ListLinked() { - terminal = new LinkedNode(null,null,null); + terminal = new LinkedNode(null, null, null); terminal.nextNode = terminal; terminal.previousNode = terminal; // Create empty list } - + /** * Add object to end of the list, any existing iterators remain valid * @@ -96,11 +92,11 @@ public class ListLinked { * @return Iterator to new object */ public Iterator add(T o) { - LinkedNode newNode = new LinkedNode(terminal.previousNode,terminal,o); + LinkedNode newNode = new LinkedNode(terminal.previousNode, terminal, o); terminal.previousNode.nextNode = newNode; terminal.previousNode = newNode; LinkedIterator iter = new LinkedIterator(newNode); - return iter; + return iter; } /** @@ -110,14 +106,14 @@ public class ListLinked { * @param o New object to add * @return Iterator to new object */ - public Iterator insertAfter(Iterator itr,T o) { // Insert object AFTER object indicated by iter + public Iterator insertAfter(Iterator itr, T o) { // Insert object AFTER object indicated by iter LinkedNode cur = ((LinkedIterator) itr).curNode; - LinkedNode newNode = new LinkedNode(cur,cur.nextNode,o); + LinkedNode newNode = new LinkedNode(cur, cur.nextNode, o); cur.nextNode.previousNode = newNode; cur.nextNode = newNode; return new LinkedIterator(newNode); } - + /** * Insert new object BEFORE object pointed to by iterator, other Iterators remain valid * @@ -125,14 +121,14 @@ public class ListLinked { * @param o New object to add * @return Iterator to new object */ - public Iterator insertBefore(Iterator itr,T o) { // Insert BEFORE iterator - LinkedNode cur = ((LinkedIterator)itr).curNode; - LinkedNode newNode = new LinkedNode(cur.previousNode,cur,o); + public Iterator insertBefore(Iterator itr, T o) { // Insert BEFORE iterator + LinkedNode cur = ((LinkedIterator) itr).curNode; + LinkedNode newNode = new LinkedNode(cur.previousNode, cur, o); cur.previousNode.nextNode = newNode; cur.previousNode = newNode; return new LinkedIterator(newNode); } - + /** * Remove object from list indicated by Iterator, all iterators that point to objects other * than this one remain valid @@ -140,8 +136,10 @@ public class ListLinked { * @param itr Iterator to object to be removed */ public void remove(Iterator itr) { - LinkedNode cur = ((LinkedIterator)itr).curNode; - if (cur.data == null) return; // Should probably throw an exception here + LinkedNode cur = ((LinkedIterator) itr).curNode; + if (cur.data == null) { + return; // Should probably throw an exception here + } cur.previousNode.nextNode = cur.nextNode; cur.nextNode.previousNode = cur.previousNode; } @@ -151,9 +149,9 @@ public class ListLinked { */ public Iterator iterator() { LinkedIterator iter = new LinkedIterator(terminal); // Build starting iterator - return iter; + return iter; } - + /** * Get rid of all entries on the linked list. */ @@ -161,5 +159,18 @@ public class ListLinked { terminal.nextNode = terminal; terminal.previousNode = terminal; // Recreate empty list } - + + /** + * @return the first element in the list (or null) + */ + public T first() { + return terminal.nextNode.data; + } + + /** + * @return the last element in the list (or null) + */ + public T last() { + return terminal.previousNode.data; + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeBlockBasic.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeBlockBasic.java index 5a25faba4b..d337320fa8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeBlockBasic.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeBlockBasic.java @@ -118,10 +118,8 @@ public class PcodeBlockBasic extends PcodeBlock { AddressRange range = iter.next(); encoder.openElement(ELEM_RANGE); encoder.writeSpace(ATTRIB_SPACE, range.getAddressSpace()); - encoder.writeUnsignedInteger(ATTRIB_FIRST, - range.getMinAddress().getOffset()); - encoder.writeUnsignedInteger(ATTRIB_LAST, - range.getMaxAddress().getOffset()); + encoder.writeUnsignedInteger(ATTRIB_FIRST, range.getMinAddress().getOffset()); + encoder.writeUnsignedInteger(ATTRIB_LAST, range.getMaxAddress().getOffset()); } encoder.closeElement(ELEM_RANGELIST); } @@ -146,4 +144,18 @@ public class PcodeBlockBasic extends PcodeBlock { decoder.closeElement(rangelistel); } + + /** + * @return the first PcodeOp in this block (or null if the block is empty) + */ + public PcodeOp getFirstOp() { + return oplist.first(); + } + + /** + * @return the last PcodeOp in this block (or null if the block is empty) + */ + public PcodeOp getLastOp() { + return oplist.last(); + } }