GP-1642 Display formats for data-types

This commit is contained in:
caheckman 2022-01-05 19:32:44 -05:00
parent 9c04807c8c
commit 955838cd62
12 changed files with 266 additions and 99 deletions

View File

@ -13,6 +13,7 @@ src/decompile/cpp/Makefile||GHIDRA||||END|
src/decompile/datatests/convert.xml||GHIDRA||||END| src/decompile/datatests/convert.xml||GHIDRA||||END|
src/decompile/datatests/deadvolatile.xml||GHIDRA||||END| src/decompile/datatests/deadvolatile.xml||GHIDRA||||END|
src/decompile/datatests/deindirect.xml||GHIDRA||||END| src/decompile/datatests/deindirect.xml||GHIDRA||||END|
src/decompile/datatests/displayformat.xml||GHIDRA||||END|
src/decompile/datatests/dupptr.xml||GHIDRA||||END| src/decompile/datatests/dupptr.xml||GHIDRA||||END|
src/decompile/datatests/elseif.xml||GHIDRA||||END| src/decompile/datatests/elseif.xml||GHIDRA||||END|
src/decompile/datatests/floatprint.xml||GHIDRA||||END| src/decompile/datatests/floatprint.xml||GHIDRA||||END|

View File

@ -159,6 +159,17 @@ public:
/// \brief Check is a constant input should be explicitly labeled as a \e long integer token /// \brief Check is a constant input should be explicitly labeled as a \e long integer token
bool markExplicitLongSize(PcodeOp *op,int4 slot) const; bool markExplicitLongSize(PcodeOp *op,int4 slot) const;
/// \brief For the given PcodeOp, does it matter if a constant operand is presented as a character or integer
///
/// In most languages, character constants are promoted to integers as a matter of course, so it
/// doesn't matter if the constant is represented as an integer (a string of digits) or a character
/// (surrounded by quotes). But its possible that a particular operator does care. If the operator
/// needs an explicit character representation for an operand with a character data-type, return \b true.
/// \param vn is the constant with character data-type
/// \param op is the given PcodeOp which reads the constant (may be null)
/// \return \b true if the constant must be represented as an explicit character
bool caresAboutCharRepresentation(const Varnode *vn,const PcodeOp *op) const { return false; }
}; };
/// \brief Casting strategies that are specific to the C language /// \brief Casting strategies that are specific to the C language

View File

@ -375,18 +375,8 @@ void Symbol::saveXmlHeader(ostream &s) const
int4 format = getDisplayFormat(); int4 format = getDisplayFormat();
if (format != 0) { if (format != 0) {
s << " format=\""; s << " format=\"";
if (format == force_hex) s << Datatype::decodeIntegerFormat(format);
s << "hex\""; s << '\"';
else if (format == force_dec)
s << "dec\"";
else if (format == force_char)
s << "char\"";
else if (format == force_oct)
s << "oct\"";
else if (format == force_bin)
s << "bin\"";
else
s << "hex\"";
} }
a_v_i(s,"cat",category); a_v_i(s,"cat",category);
if (category >= 0) if (category >= 0)
@ -413,16 +403,7 @@ void Symbol::restoreXmlHeader(const Element *el)
case 'f': case 'f':
if (attName == "format") { if (attName == "format") {
const string &formString(el->getAttributeValue(i)); const string &formString(el->getAttributeValue(i));
if (formString == "hex") dispflags |= Datatype::encodeIntegerFormat(formString);
dispflags |= force_hex;
else if (formString == "dec")
dispflags |= force_dec;
else if (formString == "char")
dispflags |= force_char;
else if (formString == "oct")
dispflags |= force_oct;
else if (formString == "bin")
dispflags |= force_bin;
} }
break; break;
case 'h': case 'h':
@ -3088,9 +3069,9 @@ Scope *Database::resolveScope(uint8 id) const
/// ///
/// The name is parsed using a \b delimiter that is passed in. The name can /// The name is parsed using a \b delimiter that is passed in. The name can
/// be only partially qualified by passing in a starting Scope, which the /// be only partially qualified by passing in a starting Scope, which the
/// name is assumed to be relative to. Otherwise the name is assumed to be /// name is assumed to be relative to. If the starting scope is \b null, or the name
/// relative to the global Scope. The unqualified (base) name of the Symbol /// starts with the delimiter, the name is assumed to be relative to the global Scope.
/// is passed back to the caller. /// The unqualified (base) name of the Symbol is passed back to the caller.
/// \param fullname is the qualified Symbol name /// \param fullname is the qualified Symbol name
/// \param delim is the delimiter separating names /// \param delim is the delimiter separating names
/// \param basename will hold the passed back base Symbol name /// \param basename will hold the passed back base Symbol name
@ -3107,10 +3088,15 @@ Scope *Database::resolveScopeFromSymbolName(const string &fullname,const string
for(;;) { for(;;) {
endmark = fullname.find(delim,mark); endmark = fullname.find(delim,mark);
if (endmark == string::npos) break; if (endmark == string::npos) break;
string scopename = fullname.substr(mark,endmark-mark); if (endmark == 0) { // Path is "absolute"
start = start->resolveScope(scopename,idByNameHash); start = globalscope; // Start from the global scope
if (start == (Scope *)0) // Was the scope name bad }
return start; else {
string scopename = fullname.substr(mark,endmark-mark);
start = start->resolveScope(scopename,idByNameHash);
if (start == (Scope *)0) // Was the scope name bad
return start;
}
mark = endmark + delim.size(); mark = endmark + delim.size();
} }
basename = fullname.substr(mark,endmark); basename = fullname.substr(mark,endmark);

View File

@ -3191,7 +3191,12 @@ void parse_C(Architecture *glb,istream &s)
Datatype *ct = decl->buildType(glb); Datatype *ct = decl->buildType(glb);
if (decl->getIdentifier().size() == 0) if (decl->getIdentifier().size() == 0)
throw ParseError("Missing identifier for typedef"); throw ParseError("Missing identifier for typedef");
glb->types->setName(ct,decl->getIdentifier()); if (ct->getMetatype() == TYPE_STRUCT) {
glb->types->setName(ct,decl->getIdentifier());
}
else {
glb->types->getTypedef(ct,decl->getIdentifier(),0,0);
}
} }
else if (decl->getBaseType()->getMetatype()==TYPE_STRUCT) { else if (decl->getBaseType()->getMetatype()==TYPE_STRUCT) {
// We parsed a struct, treat as a typedef // We parsed a struct, treat as a typedef

View File

@ -1406,7 +1406,12 @@ void parse_C(Architecture *glb,istream &s)
Datatype *ct = decl->buildType(glb); Datatype *ct = decl->buildType(glb);
if (decl->getIdentifier().size() == 0) if (decl->getIdentifier().size() == 0)
throw ParseError("Missing identifier for typedef"); throw ParseError("Missing identifier for typedef");
glb->types->setName(ct,decl->getIdentifier()); if (ct->getMetatype() == TYPE_STRUCT) {
glb->types->setName(ct,decl->getIdentifier());
}
else {
glb->types->getTypedef(ct,decl->getIdentifier(),0,0);
}
} }
else if (decl->getBaseType()->getMetatype()==TYPE_STRUCT) { else if (decl->getBaseType()->getMetatype()==TYPE_STRUCT) {
// We parsed a struct, treat as a typedef // We parsed a struct, treat as a typedef

View File

@ -37,7 +37,6 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
status->registerCom(new IfcComment(),"%"); //Note: A space must follow this when used. status->registerCom(new IfcComment(),"%"); //Note: A space must follow this when used.
status->registerCom(new IfcQuit(),"quit"); status->registerCom(new IfcQuit(),"quit");
status->registerCom(new IfcHistory(),"history"); status->registerCom(new IfcHistory(),"history");
status->registerCom(new IfcOpenfile(),"openfile");
status->registerCom(new IfcOpenfile(),"openfile", "write"); status->registerCom(new IfcOpenfile(),"openfile", "write");
status->registerCom(new IfcOpenfileAppend(),"openfile","append"); status->registerCom(new IfcOpenfileAppend(),"openfile","append");
status->registerCom(new IfcClosefile(),"closefile"); status->registerCom(new IfcClosefile(),"closefile");
@ -63,8 +62,8 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
status->registerCom(new IfcDump(),"dump"); status->registerCom(new IfcDump(),"dump");
status->registerCom(new IfcDumpbinary(),"binary"); status->registerCom(new IfcDumpbinary(),"binary");
status->registerCom(new IfcForcegoto(),"force","goto"); status->registerCom(new IfcForcegoto(),"force","goto");
status->registerCom(new IfcForceHex(),"force","hex"); status->registerCom(new IfcForceFormat(),"force","varnode");
status->registerCom(new IfcForceDec(),"force","dec"); status->registerCom(new IfcForceDatatypeFormat(),"force","datatype");
status->registerCom(new IfcProtooverride(),"override","prototype"); status->registerCom(new IfcProtooverride(),"override","prototype");
status->registerCom(new IfcJumpOverride(),"override","jumptable"); status->registerCom(new IfcJumpOverride(),"override","jumptable");
status->registerCom(new IfcFlowOverride(),"override","flow"); status->registerCom(new IfcFlowOverride(),"override","flow");
@ -1254,10 +1253,7 @@ void IfcRename::execute(istream &s)
Symbol *sym; Symbol *sym;
vector<Symbol *> symList; vector<Symbol *> symList;
if (dcp->fd != (Funcdata *)0) dcp->readSymbol(oldname,symList);
dcp->fd->getScopeLocal()->queryByName(oldname,symList);
else
dcp->conf->symboltab->getGlobalScope()->queryByName(oldname,symList);
if (symList.empty()) if (symList.empty())
throw IfaceExecutionError("No symbol named: "+oldname); throw IfaceExecutionError("No symbol named: "+oldname);
@ -1273,7 +1269,7 @@ void IfcRename::execute(istream &s)
} }
/// \class IfcRemove /// \class IfcRemove
/// \brief Remove a symbol by name: `remove <varname>` /// \brief Remove a symbol by name: `remove <symbolname>`
/// ///
/// The symbol is searched for starting in the current function's scope. /// The symbol is searched for starting in the current function's scope.
/// The resulting symbol is removed completely from the symbol table. /// The resulting symbol is removed completely from the symbol table.
@ -1287,10 +1283,7 @@ void IfcRemove::execute(istream &s)
throw IfaceParseError("Missing symbol name"); throw IfaceParseError("Missing symbol name");
vector<Symbol *> symList; vector<Symbol *> symList;
if (dcp->fd != (Funcdata *)0) dcp->readSymbol(name,symList);
dcp->fd->getScopeLocal()->queryByName(name,symList);
else
dcp->conf->symboltab->getGlobalScope()->queryByName(name,symList);
if (symList.empty()) if (symList.empty())
throw IfaceExecutionError("No symbol named: "+name); throw IfaceExecutionError("No symbol named: "+name);
@ -1300,7 +1293,7 @@ void IfcRemove::execute(istream &s)
} }
/// \class IfcRetype /// \class IfcRetype
/// \brief Change the data-type of a symbol: `retype <varname> <typedeclaration>` /// \brief Change the data-type of a symbol: `retype <symbolname> <typedeclaration>`
/// ///
/// The symbol is searched for by name starting in the current function's scope. /// The symbol is searched for by name starting in the current function's scope.
/// If the type declaration includes a new name for the variable, the /// If the type declaration includes a new name for the variable, the
@ -1318,10 +1311,7 @@ void IfcRetype::execute(istream &s)
Symbol *sym; Symbol *sym;
vector<Symbol *> symList; vector<Symbol *> symList;
if (dcp->fd != (Funcdata *)0) dcp->readSymbol(name,symList);
dcp->fd->getScopeLocal()->queryByName(name,symList);
else
dcp->conf->symboltab->getGlobalScope()->queryByName(name,symList);
if (symList.empty()) if (symList.empty())
throw IfaceExecutionError("No symbol named: "+name); throw IfaceExecutionError("No symbol named: "+name);
@ -1414,6 +1404,21 @@ Varnode *IfaceDecompData::readVarnode(istream &s)
return vn; return vn;
} }
/// Find any symbols matching the given name in the current scope. Scope is either the
/// current function scope if a function is active, otherwise the global scope.
/// \param name is the given name, either absolute or partial
/// \param res will hold any matching symbols
void IfaceDecompData::readSymbol(const string &name,vector<Symbol *> &res)
{
Scope *scope = (fd == (Funcdata *)0) ? conf->symboltab->getGlobalScope() : fd->getScopeLocal();
string basename;
scope = conf->symboltab->resolveScopeFromSymbolName(name, "::", basename, scope);
if (scope == (Scope *)0)
throw IfaceParseError("Bad namespace for symbol: " + name);
scope->queryByName(basename,res);
}
/// \class IfcPrintVarnode /// \class IfcPrintVarnode
/// \brief Print information about a Varnode: `print varnode <varnode>` /// \brief Print information about a Varnode: `print varnode <varnode>`
/// ///
@ -1644,56 +1649,51 @@ void IfcTypeVarnode::execute(istream &s)
*status->fileoptr << " to scope " << scope->getFullName() << endl; *status->fileoptr << " to scope " << scope->getFullName() << endl;
} }
/// \class IfcForceHex /// \class IfcForceFormat
/// \brief Mark a constant to be printed in hex format: `force hex <varnode>` /// \brief Mark a constant to be printed in a specific format: `force varnode <varnode> [hex|dec|oct|bin|char]`
/// ///
/// A selected constant Varnode in the \e current function is marked so /// A constant Varnode in the \e current function is marked so that is forced
/// that it will be printed in hexadecimal format in decompiler output. /// to print in one of the formats: \b hex, \b dec, \b oct, \b bin, \b char.
void IfcForceHex::execute(istream &s) void IfcForceFormat::execute(istream &s)
{ {
if (dcp->fd == (Funcdata *)0)
throw IfaceExecutionError("No function selected");
Varnode *vn = dcp->readVarnode(s); Varnode *vn = dcp->readVarnode(s);
if (!vn->isConstant()) if (!vn->isConstant())
throw IfaceExecutionError("Can only force hex on a constant"); throw IfaceExecutionError("Can only force format on a constant");
type_metatype mt = vn->getType()->getMetatype(); type_metatype mt = vn->getType()->getMetatype();
if ((mt!=TYPE_INT)&&(mt!=TYPE_UINT)&&(mt!=TYPE_UNKNOWN)) if ((mt!=TYPE_INT)&&(mt!=TYPE_UINT)&&(mt!=TYPE_UNKNOWN))
throw IfaceExecutionError("Can only force hex on integer type constant"); throw IfaceExecutionError("Can only force format on integer type constant");
dcp->fd->buildDynamicSymbol(vn); dcp->fd->buildDynamicSymbol(vn);
Symbol *sym = vn->getHigh()->getSymbol(); Symbol *sym = vn->getHigh()->getSymbol();
if (sym == (Symbol *)0) if (sym == (Symbol *)0)
throw IfaceExecutionError("Unable to create symbol"); throw IfaceExecutionError("Unable to create symbol");
sym->getScope()->setDisplayFormat(sym,Symbol::force_hex); string formatString;
s >> ws >> formatString;
uint4 format = Datatype::encodeIntegerFormat(formatString);
sym->getScope()->setDisplayFormat(sym,format);
sym->getScope()->setAttribute(sym,Varnode::typelock); sym->getScope()->setAttribute(sym,Varnode::typelock);
*status->optr << "Successfully forced hex display" << endl; *status->optr << "Successfully forced format display" << endl;
} }
/// \class IfcForceDec /// \class IfcForceDatatypeFormat
/// \brief Mark a constant to be printed in decimal format: `force dec <varnode>` /// \brief Mark constants of a data-type to be printed in a specific format: `force datatype <datatype> [hex|dec|oct|bin|char]`
/// ///
/// A selected constant Varnode in the \e current function is marked so /// A display format attribute is set on the indicated data-type.
/// that it will be printed in decimal format in decompiler output. void IfcForceDatatypeFormat::execute(istream &s)
void IfcForceDec::execute(istream &s)
{ {
if (dcp->fd == (Funcdata *)0) Datatype *dt;
throw IfaceExecutionError("No function selected");
Varnode *vn = dcp->readVarnode(s); string typeName;
if (!vn->isConstant()) s >> ws >> typeName;
throw IfaceExecutionError("Can only force hex on a constant"); dt = dcp->conf->types->findByName(typeName);
type_metatype mt = vn->getType()->getMetatype(); if (dt == (Datatype *)0)
if ((mt!=TYPE_INT)&&(mt!=TYPE_UINT)&&(mt!=TYPE_UNKNOWN)) throw IfaceExecutionError("Unknown data-type: " + typeName);
throw IfaceExecutionError("Can only force dec on integer type constant"); string formatString;
dcp->fd->buildDynamicSymbol(vn); s >> ws >> formatString;
Symbol *sym = vn->getHigh()->getSymbol(); uint4 format = Datatype::encodeIntegerFormat(formatString);
if (sym == (Symbol *)0) dcp->conf->types->setDisplayFormat(dt, format);
throw IfaceExecutionError("Unable to create symbol"); *status->optr << "Successfully forced data-type display" << endl;
sym->getScope()->setDisplayFormat(sym,Symbol::force_dec);
sym->getScope()->setAttribute(sym,Varnode::typelock);
*status->optr << "Successfully forced dec display" << endl;
} }
/// \class IfcForcegoto /// \class IfcForcegoto

View File

@ -59,6 +59,7 @@ public:
void clearArchitecture(void); ///< Free all resources for the current architecture/program void clearArchitecture(void); ///< Free all resources for the current architecture/program
void followFlow(ostream &s,int4 size); void followFlow(ostream &s,int4 size);
Varnode *readVarnode(istream &s); ///< Read a varnode from the given stream Varnode *readVarnode(istream &s); ///< Read a varnode from the given stream
void readSymbol(const string &name,vector<Symbol *> &res); ///< Find a symbol by name
}; };
/// \brief Disassembly emitter that prints to a console stream /// \brief Disassembly emitter that prints to a console stream
@ -352,12 +353,12 @@ public:
virtual void execute(istream &s); virtual void execute(istream &s);
}; };
class IfcForceHex : public IfaceDecompCommand { class IfcForceFormat : public IfaceDecompCommand {
public: public:
virtual void execute(istream &s); virtual void execute(istream &s);
}; };
class IfcForceDec : public IfaceDecompCommand { class IfcForceDatatypeFormat : public IfaceDecompCommand {
public: public:
virtual void execute(istream &s); virtual void execute(istream &s);
}; };

View File

@ -1158,7 +1158,8 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
force_unsigned_token = false; force_unsigned_token = false;
force_sized_token = false; force_sized_token = false;
if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) { if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) {
Symbol *sym = vn->getHigh()->getSymbol(); HighVariable *high = vn->getHigh();
Symbol *sym = high->getSymbol();
if (sym != (Symbol *)0) { if (sym != (Symbol *)0) {
if (sym->isNameLocked() && (sym->getCategory() == Symbol::equate)) { if (sym->isNameLocked() && (sym->getCategory() == Symbol::equate)) {
if (pushEquate(val,sz,(EquateSymbol *)sym,vn,op)) if (pushEquate(val,sz,(EquateSymbol *)sym,vn,op))
@ -1168,6 +1169,8 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
} }
force_unsigned_token = vn->isUnsignedPrint(); force_unsigned_token = vn->isUnsignedPrint();
force_sized_token = vn->isLongPrint(); force_sized_token = vn->isLongPrint();
if (displayFormat == 0) // The symbol's formatting overrides any formatting on the data-type
displayFormat = high->getType()->getDisplayFormat();
} }
if (sign && displayFormat != Symbol::force_char) { // Print the constant as signed if (sign && displayFormat != Symbol::force_char) { // Print the constant as signed
uintb mask = calc_mask(sz); uintb mask = calc_mask(sz);
@ -1476,17 +1479,22 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn,con
uint4 displayFormat = 0; uint4 displayFormat = 0;
bool isSigned = (ct->getMetatype() == TYPE_INT); bool isSigned = (ct->getMetatype() == TYPE_INT);
if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) { if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) {
Symbol *sym = vn->getHigh()->getSymbol(); HighVariable *high = vn->getHigh();
Symbol *sym = high->getSymbol();
if (sym != (Symbol *)0) { if (sym != (Symbol *)0) {
if (sym->isNameLocked() && (sym->getCategory() == Symbol::equate)) { if (sym->isNameLocked() && (sym->getCategory() == Symbol::equate)) {
if (pushEquate(val,vn->getSize(),(EquateSymbol *)sym,vn,op)) if (pushEquate(val,vn->getSize(),(EquateSymbol *)sym,vn,op))
return; return;
} }
displayFormat = sym->getDisplayFormat(); displayFormat = sym->getDisplayFormat();
if (displayFormat == Symbol::force_bin || displayFormat == Symbol::force_dec || displayFormat == Symbol::force_oct) { }
push_integer(val, ct->getSize(), isSigned, vn, op); if (displayFormat == 0)
return; displayFormat = high->getType()->getDisplayFormat();
} }
if (displayFormat != 0 && displayFormat != Symbol::force_char) {
if (!castStrategy->caresAboutCharRepresentation(vn, op)) {
push_integer(val, ct->getSize(), isSigned, vn, op);
return;
} }
} }
if ((ct->getSize()==1)&&(val >= 0x80)) { if ((ct->getSize()==1)&&(val >= 0x80)) {

View File

@ -316,6 +316,9 @@ void Datatype::saveXmlBasic(type_metatype meta,ostream &s) const
a_v_b(s,"varlength",true); a_v_b(s,"varlength",true);
if ((flags & opaque_string)!=0) if ((flags & opaque_string)!=0)
a_v_b(s,"opaquestring",true); a_v_b(s,"opaquestring",true);
uint4 format = getDisplayFormat();
if (format != 0)
a_v(s,"format",decodeIntegerFormat(format));
} }
/// Write a simple reference to \b this data-type as an XML \<typeref> tag, /// Write a simple reference to \b this data-type as an XML \<typeref> tag,
@ -350,6 +353,9 @@ void Datatype::saveXmlTypedef(ostream &s) const
s << "<def"; s << "<def";
a_v(s,"name",name); a_v(s,"name",name);
a_v_u(s,"id",id); a_v_u(s,"id",id);
uint4 format = getDisplayFormat();
if (format != 0)
a_v(s,"format",Datatype::decodeIntegerFormat(format));
s << ">"; s << ">";
typedefImm->saveXmlRef(s); typedefImm->saveXmlRef(s);
s << "</def>"; s << "</def>";
@ -445,6 +451,10 @@ void Datatype::restoreXmlBasic(const Element *el)
if (xml_readbool(el->getAttributeValue(i))) if (xml_readbool(el->getAttributeValue(i)))
flags |= opaque_string; flags |= opaque_string;
} }
else if (attribName == "format") {
uint4 val = encodeIntegerFormat(el->getAttributeValue(i));
setDisplayFormat(val);
}
} }
if ((id==0)&&(name.size()>0)) // If there is a type name if ((id==0)&&(name.size()>0)) // If there is a type name
id = hashName(name); // There must be some kind of id id = hashName(name); // There must be some kind of id
@ -488,6 +498,53 @@ uint8 Datatype::hashSize(uint8 id,int4 size)
id ^= sizeHash; id ^= sizeHash;
return id; return id;
} }
/// \brief Encode the \b format attribute from an XML element
///
/// Possible values are:
/// - 1 - \b hex
/// - 2 - \b dec
/// - 3 - \b oct
/// - 4 - \b bin
/// - 5 - \b char
///
/// \param val is the string to encode
/// \return the encoded value
uint4 Datatype::encodeIntegerFormat(const string &val)
{
if (val == "hex")
return 1;
else if (val == "dec")
return 2;
else if (val == "oct")
return 3;
else if (val == "bin")
return 4;
else if (val == "char")
return 5;
throw LowlevelError("Unrecognized integer format: " + val);
}
/// \brief Decode the given format value into an XML attribute string
///
/// Possible encoded values are 1-5 corresponding to "hex", "dec", "oct", "bin", "char"
/// \param val is the value to decode
/// \return the decoded string
string Datatype::decodeIntegerFormat(uint4 val)
{
if (val == 1)
return "hex";
else if (val == 2)
return "dec";
else if (val == 3)
return "oct";
else if (val == 4)
return "bin";
else if (val == 5)
return "char";
throw LowlevelError("Unrecognized integer format encoding");
}
/// Contruct from the given \<field> element. /// Contruct from the given \<field> element.
/// \param el is the element /// \param el is the element
@ -2600,6 +2657,17 @@ Datatype *TypeFactory::setName(Datatype *ct,const string &n)
return ct; return ct;
} }
/// The display format for the data-type is changed based on the given format. A value of
/// zero clears any preexisting format. Otherwise the value can be one of:
/// 1=\b hex, 2=\b dec, 4=\b oct, 8=\b bin, 16=\b char
/// \param ct is the given data-type to change
/// \param format is the given format
void TypeFactory::setDisplayFormat(Datatype *ct,uint4 format)
{
ct->setDisplayFormat(format);
}
/// Make sure all the offsets are fully established then set fields of the structure /// Make sure all the offsets are fully established then set fields of the structure
/// If \b fixedsize is greater than 0, force the final structure to have that size. /// If \b fixedsize is greater than 0, force the final structure to have that size.
/// This method should only be used on an incomplete structure. It will mark the structure as complete. /// This method should only be used on an incomplete structure. It will mark the structure as complete.
@ -2947,8 +3015,9 @@ void TypeFactory::recalcPointerSubmeta(Datatype *base,sub_metatype sub)
/// \param ct is the given data-type to clone /// \param ct is the given data-type to clone
/// \param name is the new name for the clone /// \param name is the new name for the clone
/// \param id is the new id for the clone (or 0) /// \param id is the new id for the clone (or 0)
/// \param format is a particular format to force when printing (or zero)
/// \return the (found or created) \e typedef data-type /// \return the (found or created) \e typedef data-type
Datatype *TypeFactory::getTypedef(Datatype *ct,const string &name,uint8 id) Datatype *TypeFactory::getTypedef(Datatype *ct,const string &name,uint8 id,uint4 format)
{ {
if (id == 0) if (id == 0)
@ -2964,6 +3033,7 @@ Datatype *TypeFactory::getTypedef(Datatype *ct,const string &name,uint8 id)
res->id = id; // and new id res->id = id; // and new id
res->flags &= ~((uint4)Datatype::coretype); // Not a core type res->flags &= ~((uint4)Datatype::coretype); // Not a core type
res->typedefImm = ct; res->typedefImm = ct;
res->setDisplayFormat(format);
insert(res); insert(res);
return res; return res;
} }
@ -3328,15 +3398,19 @@ Datatype *TypeFactory::restoreTypedef(const Element *el)
{ {
uint8 id = 0; uint8 id = 0;
string nm; string nm;
uint4 format = 0; // No forced display format by default
for(int4 i=0;i<el->getNumAttributes();++i) { for(int4 i=0;i<el->getNumAttributes();++i) {
const string &attribName(el->getAttributeName(i)); const string &attribName(el->getAttributeName(i));
if (attribName == "id") { if (attribName == "id") {
istringstream s1(el->getAttributeValue("id")); istringstream s1(el->getAttributeValue(i));
s1.unsetf(ios::dec | ios::hex | ios::oct); s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> id; s1 >> id;
} }
else if (attribName == "name") { else if (attribName == "name") {
nm = el->getAttributeValue("name"); nm = el->getAttributeValue(i);
}
else if (attribName == "format") {
format = Datatype::encodeIntegerFormat(el->getAttributeValue(i));
} }
} }
if (id == 0) { // Its possible the typedef is a builtin if (id == 0) { // Its possible the typedef is a builtin
@ -3367,7 +3441,7 @@ Datatype *TypeFactory::restoreTypedef(const Element *el)
return prev; return prev;
} }
} }
return getTypedef(defedType, nm, id); return getTypedef(defedType, nm, id, format);
} }
/// If necessary create a stub object before parsing the field descriptions, to deal with recursive definitions /// If necessary create a stub object before parsing the field descriptions, to deal with recursive definitions

View File

@ -93,11 +93,6 @@ protected:
/// Boolean properties of datatypes /// Boolean properties of datatypes
enum { enum {
coretype = 1, ///< This is a basic type which will never be redefined coretype = 1, ///< This is a basic type which will never be redefined
// Bits above the first bit are considered a sub-metatype
// If the metatypes are equal, we compare on sub-metatype
// Currently this is only used to order int, char, and enum
// The order of the sub-metatype is reversed so that
// char comes before int1
chartype = 2, ///< ASCII character data chartype = 2, ///< ASCII character data
enumtype = 4, ///< An enumeration type (as well as an integer) enumtype = 4, ///< An enumeration type (as well as an integer)
poweroftwo = 8, ///< An enumeration type where all values are of 2^^n form poweroftwo = 8, ///< An enumeration type where all values are of 2^^n form
@ -108,7 +103,8 @@ protected:
has_stripped = 0x100, ///< Datatype has a stripped form for formal declarations has_stripped = 0x100, ///< Datatype has a stripped form for formal declarations
is_ptrrel = 0x200, ///< Datatype is a TypePointerRel is_ptrrel = 0x200, ///< Datatype is a TypePointerRel
type_incomplete = 0x400, ///< Set if \b this (recursive) data-type has not been fully defined yet type_incomplete = 0x400, ///< Set if \b this (recursive) data-type has not been fully defined yet
needs_resolution = 0x800 ///< Datatype (union, pointer to union) needs resolution before propagation needs_resolution = 0x800, ///< Datatype (union, pointer to union) needs resolution before propagation
force_format = 0x7000, ///< 3-bits encoding display format, 0=none, 1=hex, 2=dec, 3=oct, 4=bin, 5=char
}; };
friend class TypeFactory; friend class TypeFactory;
friend struct DatatypeCompare; friend struct DatatypeCompare;
@ -123,6 +119,7 @@ protected:
void saveXmlBasic(type_metatype meta,ostream &s) const; ///< Save basic data-type properties void saveXmlBasic(type_metatype meta,ostream &s) const; ///< Save basic data-type properties
void saveXmlTypedef(ostream &s) const; ///< Write \b this as a \e typedef tag to stream void saveXmlTypedef(ostream &s) const; ///< Write \b this as a \e typedef tag to stream
void markComplete(void) { flags &= ~(uint4)type_incomplete; } ///< Mark \b this data-type as completely defined void markComplete(void) { flags &= ~(uint4)type_incomplete; } ///< Mark \b this data-type as completely defined
void setDisplayFormat(uint4 format); ///< Set a specific display format
virtual Datatype *clone(void) const=0; ///< Clone the data-type virtual Datatype *clone(void) const=0; ///< Clone the data-type
static uint8 hashName(const string &nm); ///< Produce a data-type id by hashing the type name static uint8 hashName(const string &nm); ///< Produce a data-type id by hashing the type name
static uint8 hashSize(uint8 id,int4 size); ///< Reversibly hash size into id static uint8 hashSize(uint8 id,int4 size); ///< Reversibly hash size into id
@ -149,6 +146,7 @@ public:
bool isIncomplete(void) const { return (flags & type_incomplete)!=0; } ///< Is \b this an incompletely defined data-type bool isIncomplete(void) const { return (flags & type_incomplete)!=0; } ///< Is \b this an incompletely defined data-type
bool needsResolution(void) const { return (flags & needs_resolution)!=0; } ///< Is \b this a union or a pointer to union bool needsResolution(void) const { return (flags & needs_resolution)!=0; } ///< Is \b this a union or a pointer to union
uint4 getInheritable(void) const { return (flags & coretype); } ///< Get properties pointers inherit uint4 getInheritable(void) const { return (flags & coretype); } ///< Get properties pointers inherit
uint4 getDisplayFormat(void) const; ///< Get the display format for constants with \b this data-type
type_metatype getMetatype(void) const { return metatype; } ///< Get the type \b meta-type type_metatype getMetatype(void) const { return metatype; } ///< Get the type \b meta-type
sub_metatype getSubMeta(void) const { return submeta; } ///< Get the \b sub-metatype sub_metatype getSubMeta(void) const { return submeta; } ///< Get the \b sub-metatype
uint8 getId(void) const { return id; } ///< Get the type id uint8 getId(void) const { return id; } ///< Get the type id
@ -173,6 +171,8 @@ public:
int4 typeOrder(const Datatype &op) const { if (this==&op) return 0; return compare(op,10); } ///< Order this with -op- datatype int4 typeOrder(const Datatype &op) const { if (this==&op) return 0; return compare(op,10); } ///< Order this with -op- datatype
int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special
void saveXmlRef(ostream &s) const; ///< Write an XML reference of \b this to stream void saveXmlRef(ostream &s) const; ///< Write an XML reference of \b this to stream
static uint4 encodeIntegerFormat(const string &val);
static string decodeIntegerFormat(uint4 val);
}; };
/// \brief A field within a structure or union /// \brief A field within a structure or union
@ -575,6 +575,7 @@ public:
Architecture *getArch(void) const { return glb; } ///< Get the Architecture object Architecture *getArch(void) const { return glb; } ///< Get the Architecture object
Datatype *findByName(const string &n); ///< Return type of given name Datatype *findByName(const string &n); ///< Return type of given name
Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name
void setDisplayFormat(Datatype *ct,uint4 format); ///< Set the display format associated with the given data-type
bool setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeStruct bool setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeStruct
bool setFields(vector<TypeField> &fd,TypeUnion *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeUnion bool setFields(vector<TypeField> &fd,TypeUnion *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeUnion
void setPrototype(const FuncProto *fp,TypeCode *newCode,uint4 flags); ///< Set the prototype on a TypeCode void setPrototype(const FuncProto *fp,TypeCode *newCode,uint4 flags); ///< Set the prototype on a TypeCode
@ -601,7 +602,7 @@ public:
TypeCode *getTypeCode(ProtoModel *model,Datatype *outtype, TypeCode *getTypeCode(ProtoModel *model,Datatype *outtype,
const vector<Datatype *> &intypes, const vector<Datatype *> &intypes,
bool dotdotdot); ///< Create a "function" datatype bool dotdotdot); ///< Create a "function" datatype
Datatype *getTypedef(Datatype *ct,const string &name,uint8 id); ///< Create a new \e typedef data-type Datatype *getTypedef(Datatype *ct,const string &name,uint8 id,uint4 format); ///< Create a new \e typedef data-type
TypePointerRel *getTypePointerRel(TypePointer *parentPtr,Datatype *ptrTo,int4 off); ///< Get pointer offset relative to a container TypePointerRel *getTypePointerRel(TypePointer *parentPtr,Datatype *ptrTo,int4 off); ///< Get pointer offset relative to a container
TypePointerRel *getTypePointerRel(int4 sz,Datatype *parent,Datatype *ptrTo,int4 ws,int4 off,const string &nm); TypePointerRel *getTypePointerRel(int4 sz,Datatype *parent,Datatype *ptrTo,int4 ws,int4 off,const string &nm);
TypePointer *getTypePointerWithSpace(Datatype *ptrTo,AddrSpace *spc,const string &nm); TypePointer *getTypePointerWithSpace(Datatype *ptrTo,AddrSpace *spc,const string &nm);
@ -618,6 +619,32 @@ public:
void cacheCoreTypes(void); ///< Cache common types void cacheCoreTypes(void); ///< Cache common types
}; };
/// The display format for the data-type is changed based on the given format. A value of
/// zero clears any preexisting format. Otherwise the value can be one of:
/// 1=\b hex, 2=\b dec, 3=\b oct, 4=\b bin, 5=\b char
/// \param format is the given format
inline void Datatype::setDisplayFormat(uint4 format)
{
flags &= ~(uint4)force_format; // Clear preexisting
flags |= (format << 12);
}
/// A non-zero result indicates the type of formatting that is forced on the constant.
/// One of the following values is returned.
/// - 1 for hexadecimal
/// - 2 for decimal
/// - 3 for octal
/// - 4 for binary
/// - 5 for char
///
/// \return the forced encoding type or zero
inline uint4 Datatype::getDisplayFormat(void) const
{
return (flags & force_format) >> 12;
}
/// Order data-types, with special handling of the \e bool data-type. Data-types are compared /// Order data-types, with special handling of the \e bool data-type. Data-types are compared
/// using the normal ordering, but \e bool is ordered after all other data-types. A return value /// using the normal ordering, but \e bool is ordered after all other data-types. A return value
/// of 0 indicates the data-types are the same, -1 indicates that \b this is prefered (ordered earlier), /// of 0 indicates the data-types are the same, -1 indicates that \b this is prefered (ordered earlier),

View File

@ -0,0 +1,36 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!--
A function that sets global variables with constant values. The data-types
associated with the symbol, or the symbol itself is set to specific display formats.
The output should reflect these formats.
-->
<bytechunk space="ram" offset="0x1005fa" readonly="true">
554889e5c705
0c0a200064000000c6050d0a200077c7
05ff0920006d0b0000c705fd092000aa
000000905dc3
</bytechunk>
<symbol space="ram" offset="0x1005fa" name="setglobals"/>
</binaryimage>
<script>
<com>parse line typedef char uint8_t;</com>
<com>parse line typedef int4 octint4;</com>
<com>parse line typedef int4 binint4;</com>
<com>force datatype uint8_t hex</com>
<com>force datatype octint4 oct</com>
<com>map addr r0x301014 int4 globalfree</com>
<com>map addr r0x30101c uint8_t globalhex</com>
<com>map addr r0x301018 octint4 globaloct</com>
<com>map addr r0x301020 octint4 globalbin</com>
<com>lo fu setglobals</com>
<com>decompile</com>
<com>force varnode #0xaa(0x100625:0x12) bin</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Display Format #1" min="1" max="1">globalfree = 100;</stringmatch>
<stringmatch name="Display Format #2" min="1" max="1">globalhex = 0x77;</stringmatch>
<stringmatch name="Display Format #3" min="1" max="1">globaloct = 05555;</stringmatch>
<stringmatch name="Display Format #4" min="1" max="1">globalbin = 0b10101010;</stringmatch>
</decompilertest>

View File

@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.docking.settings.FormatSettingsDefinition;
import ghidra.program.database.data.PointerTypedefInspector; import ghidra.program.database.data.PointerTypedefInspector;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
@ -784,6 +785,7 @@ public class PcodeDataTypeManager {
*/ */
private void buildTypeDef(StringBuilder resBuf, TypeDef type, int size) { private void buildTypeDef(StringBuilder resBuf, TypeDef type, int size) {
DataType refType = type.getDataType(); DataType refType = type.getDataType();
String format = null;
int sz = refType.getLength(); int sz = refType.getLength();
if (sz <= 0) { if (sz <= 0) {
sz = size; sz = size;
@ -810,9 +812,20 @@ public class PcodeDataTypeManager {
} }
} }
} }
else {
if (FormatSettingsDefinition.DEF.hasValue(type.getDefaultSettings())) {
format = FormatSettingsDefinition.DEF.getValueString(type.getDefaultSettings());
if (format.length() > 4) {
format = format.substring(0, 3);
}
}
}
resBuf.append("<def"); resBuf.append("<def");
appendNameIdAttributes(resBuf, type); appendNameIdAttributes(resBuf, type);
if (format != null) {
SpecXmlUtils.encodeStringAttribute(resBuf, "format", format);
}
resBuf.append('>'); resBuf.append('>');
buildTypeRef(resBuf, refType, sz); buildTypeRef(resBuf, refType, sz);