mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
3b9263f1b4
31 changed files with 709 additions and 134 deletions
|
@ -18,13 +18,14 @@ package ghidra.app.util.template;
|
||||||
import ghidra.GhidraOptions;
|
import ghidra.GhidraOptions;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
|
import ghidra.program.model.symbol.NameTransformer;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for simplify names with template data. This class can be used with tool options or
|
* Class for simplify names with template data. This class can be used with tool options or
|
||||||
* as a stand alone configurable simplifier.
|
* as a stand alone configurable simplifier.
|
||||||
*/
|
*/
|
||||||
public class TemplateSimplifier {
|
public class TemplateSimplifier implements NameTransformer {
|
||||||
public static final String SUB_OPTION_NAME = "Templates";
|
public static final String SUB_OPTION_NAME = "Templates";
|
||||||
|
|
||||||
public static final String SIMPLIFY_TEMPLATES_OPTION =
|
public static final String SIMPLIFY_TEMPLATES_OPTION =
|
||||||
|
@ -145,6 +146,7 @@ public class TemplateSimplifier {
|
||||||
* @param input the input string to be simplified
|
* @param input the input string to be simplified
|
||||||
* @return a simplified string
|
* @return a simplified string
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public String simplify(String input) {
|
public String simplify(String input) {
|
||||||
if (!doSimplify) {
|
if (!doSimplify) {
|
||||||
return input;
|
return input;
|
||||||
|
@ -192,10 +194,13 @@ public class TemplateSimplifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String doSimplify(String input, int depth) {
|
private String doSimplify(String input, int depth) {
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
TemplateString ts;
|
TemplateString ts = findTemplateString(input, pos);
|
||||||
while ((ts = findTemplateString(input, pos)) != null) {
|
if (ts == null) {
|
||||||
|
return input; // Fast fail if no template characters present
|
||||||
|
}
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
do {
|
||||||
builder.append(input.substring(pos, ts.start));
|
builder.append(input.substring(pos, ts.start));
|
||||||
String template = ts.getTemplate();
|
String template = ts.getTemplate();
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
|
@ -215,7 +220,9 @@ public class TemplateSimplifier {
|
||||||
builder.append(">");
|
builder.append(">");
|
||||||
}
|
}
|
||||||
pos = ts.end + 1;
|
pos = ts.end + 1;
|
||||||
|
ts = findTemplateString(input, pos);
|
||||||
}
|
}
|
||||||
|
while (ts != null);
|
||||||
builder.append(input.substring(pos));
|
builder.append(input.substring(pos));
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,7 @@ CallGraphNode *CallGraph::addNode(Funcdata *f)
|
||||||
throw LowlevelError("Functions with duplicate entry points: "+f->getName()+" "+node.getFuncdata()->getName());
|
throw LowlevelError("Functions with duplicate entry points: "+f->getName()+" "+node.getFuncdata()->getName());
|
||||||
|
|
||||||
node.entryaddr = f->getAddress();
|
node.entryaddr = f->getAddress();
|
||||||
node.name = f->getName();
|
node.name = f->getDisplayName();
|
||||||
node.fd = f;
|
node.fd = f;
|
||||||
return &node;
|
return &node;
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,6 +395,7 @@ void Symbol::decodeHeader(Decoder &decoder)
|
||||||
|
|
||||||
{
|
{
|
||||||
name.clear();
|
name.clear();
|
||||||
|
displayName.clear();
|
||||||
category = no_category;
|
category = no_category;
|
||||||
symbolId = 0;
|
symbolId = 0;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@ -447,12 +448,17 @@ void Symbol::decodeHeader(Decoder &decoder)
|
||||||
if (decoder.readBool())
|
if (decoder.readBool())
|
||||||
flags |= Varnode::volatil;
|
flags |= Varnode::volatil;
|
||||||
}
|
}
|
||||||
|
else if (attribId == ATTRIB_LABEL) {
|
||||||
|
displayName = decoder.readString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (category == function_parameter) {
|
if (category == function_parameter) {
|
||||||
catindex = decoder.readUnsignedInteger(ATTRIB_INDEX);
|
catindex = decoder.readUnsignedInteger(ATTRIB_INDEX);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
catindex = 0;
|
catindex = 0;
|
||||||
|
if (displayName.size() == 0)
|
||||||
|
displayName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encode the data-type for the Symbol
|
/// Encode the data-type for the Symbol
|
||||||
|
@ -532,6 +538,7 @@ FunctionSymbol::FunctionSymbol(Scope *sc,const string &nm,int4 size)
|
||||||
consumeSize = size;
|
consumeSize = size;
|
||||||
buildType();
|
buildType();
|
||||||
name = nm;
|
name = nm;
|
||||||
|
displayName = nm;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionSymbol::FunctionSymbol(Scope *sc,int4 size)
|
FunctionSymbol::FunctionSymbol(Scope *sc,int4 size)
|
||||||
|
@ -552,7 +559,7 @@ Funcdata *FunctionSymbol::getFunction(void)
|
||||||
{
|
{
|
||||||
if (fd != (Funcdata *)0) return fd;
|
if (fd != (Funcdata *)0) return fd;
|
||||||
SymbolEntry *entry = getFirstWholeMap();
|
SymbolEntry *entry = getFirstWholeMap();
|
||||||
fd = new Funcdata(name,scope,entry->getAddr(),this);
|
fd = new Funcdata(name,displayName,scope,entry->getAddr(),this);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,7 +582,7 @@ void FunctionSymbol::decode(Decoder &decoder)
|
||||||
{
|
{
|
||||||
uint4 elemId = decoder.peekElement();
|
uint4 elemId = decoder.peekElement();
|
||||||
if (elemId == ELEM_FUNCTION) {
|
if (elemId == ELEM_FUNCTION) {
|
||||||
fd = new Funcdata("",scope,Address(),this);
|
fd = new Funcdata("","",scope,Address(),this);
|
||||||
try {
|
try {
|
||||||
symbolId = fd->decode(decoder);
|
symbolId = fd->decode(decoder);
|
||||||
} catch(RecovError &err) {
|
} catch(RecovError &err) {
|
||||||
|
@ -583,6 +590,7 @@ void FunctionSymbol::decode(Decoder &decoder)
|
||||||
throw DuplicateFunctionError(fd->getAddress(),fd->getName());
|
throw DuplicateFunctionError(fd->getAddress(),fd->getName());
|
||||||
}
|
}
|
||||||
name = fd->getName();
|
name = fd->getName();
|
||||||
|
displayName = fd->getDisplayName();
|
||||||
if (consumeSize < fd->getSize()) {
|
if (consumeSize < fd->getSize()) {
|
||||||
if ((fd->getSize()>1)&&(fd->getSize() <= 8))
|
if ((fd->getSize()>1)&&(fd->getSize() <= 8))
|
||||||
consumeSize = fd->getSize();
|
consumeSize = fd->getSize();
|
||||||
|
@ -599,6 +607,9 @@ void FunctionSymbol::decode(Decoder &decoder)
|
||||||
else if (attribId == ATTRIB_ID) {
|
else if (attribId == ATTRIB_ID) {
|
||||||
symbolId = decoder.readUnsignedInteger();
|
symbolId = decoder.readUnsignedInteger();
|
||||||
}
|
}
|
||||||
|
else if (attribId == ATTRIB_LABEL) {
|
||||||
|
displayName = decoder.readString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
decoder.closeElement(elemId);
|
decoder.closeElement(elemId);
|
||||||
}
|
}
|
||||||
|
@ -727,6 +738,7 @@ LabSymbol::LabSymbol(Scope *sc,const string &nm)
|
||||||
{
|
{
|
||||||
buildType();
|
buildType();
|
||||||
name = nm;
|
name = nm;
|
||||||
|
displayName = nm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param sc is the Scope that will contain the new Symbol
|
/// \param sc is the Scope that will contain the new Symbol
|
||||||
|
@ -766,6 +778,8 @@ void ExternRefSymbol::buildNameType(void)
|
||||||
name = s.str();
|
name = s.str();
|
||||||
name += "_exref"; // Indicate this is an external reference variable
|
name += "_exref"; // Indicate this is an external reference variable
|
||||||
}
|
}
|
||||||
|
if (displayName.size() == 0)
|
||||||
|
displayName = name;
|
||||||
flags |= Varnode::externref | Varnode::typelock;
|
flags |= Varnode::externref | Varnode::typelock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,12 +806,15 @@ void ExternRefSymbol::decode(Decoder &decoder)
|
||||||
|
|
||||||
{
|
{
|
||||||
uint4 elemId = decoder.openElement(ELEM_EXTERNREFSYMBOL);
|
uint4 elemId = decoder.openElement(ELEM_EXTERNREFSYMBOL);
|
||||||
name = ""; // Name is empty
|
name.clear(); // Name is empty
|
||||||
|
displayName.clear();
|
||||||
for(;;) {
|
for(;;) {
|
||||||
uint4 attribId = decoder.getNextAttributeId();
|
uint4 attribId = decoder.getNextAttributeId();
|
||||||
if (attribId == 0) break;
|
if (attribId == 0) break;
|
||||||
if (attribId == ATTRIB_NAME) // Unless we see it explicitly
|
if (attribId == ATTRIB_NAME) // Unless we see it explicitly
|
||||||
name = decoder.readString();
|
name = decoder.readString();
|
||||||
|
else if (attribId == ATTRIB_LABEL)
|
||||||
|
displayName = decoder.readString();
|
||||||
}
|
}
|
||||||
refaddr = Address::decode(decoder);
|
refaddr = Address::decode(decoder);
|
||||||
decoder.closeElement(elemId);
|
decoder.closeElement(elemId);
|
||||||
|
@ -1798,8 +1815,10 @@ void ScopeInternal::addSymbolInternal(Symbol *sym)
|
||||||
nextUniqueId += 1;
|
nextUniqueId += 1;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (sym->name.size() == 0)
|
if (sym->name.size() == 0) {
|
||||||
sym->name = buildUndefinedName();
|
sym->name = buildUndefinedName();
|
||||||
|
sym->displayName = sym->name;
|
||||||
|
}
|
||||||
if (sym->getType() == (Datatype *)0)
|
if (sym->getType() == (Datatype *)0)
|
||||||
throw LowlevelError(sym->getName() + " symbol created with no type");
|
throw LowlevelError(sym->getName() + " symbol created with no type");
|
||||||
if (sym->getType()->getSize() < 1)
|
if (sym->getType()->getSize() < 1)
|
||||||
|
@ -2138,6 +2157,7 @@ void ScopeInternal::renameSymbol(Symbol *sym,const string &newname)
|
||||||
multiEntrySet.erase(sym); // The multi-entry set is sorted by name, remove
|
multiEntrySet.erase(sym); // The multi-entry set is sorted by name, remove
|
||||||
string oldname = sym->name;
|
string oldname = sym->name;
|
||||||
sym->name = newname;
|
sym->name = newname;
|
||||||
|
sym->displayName = newname;
|
||||||
insertNameTree(sym);
|
insertNameTree(sym);
|
||||||
if (sym->wholeCount > 1)
|
if (sym->wholeCount > 1)
|
||||||
multiEntrySet.insert(sym); // Reenter into the multi-entry set now that name is changed
|
multiEntrySet.insert(sym); // Reenter into the multi-entry set now that name is changed
|
||||||
|
@ -3315,14 +3335,32 @@ void Database::decode(Decoder &decoder)
|
||||||
for(;;) {
|
for(;;) {
|
||||||
uint4 subId = decoder.openElement();
|
uint4 subId = decoder.openElement();
|
||||||
if (subId != ELEM_SCOPE) break;
|
if (subId != ELEM_SCOPE) break;
|
||||||
string name = decoder.readString(ATTRIB_NAME);
|
string name;
|
||||||
uint8 id = decoder.readUnsignedInteger(ATTRIB_ID);
|
string displayName;
|
||||||
|
uint8 id = 0;
|
||||||
|
bool seenId = false;
|
||||||
|
for(;;) {
|
||||||
|
uint4 attribId = decoder.getNextAttributeId();
|
||||||
|
if (attribId == 0) break;
|
||||||
|
if (attribId == ATTRIB_NAME)
|
||||||
|
name = decoder.readString();
|
||||||
|
else if (attribId == ATTRIB_ID) {
|
||||||
|
id = decoder.readUnsignedInteger();
|
||||||
|
seenId = true;
|
||||||
|
}
|
||||||
|
else if (attribId == ATTRIB_LABEL)
|
||||||
|
displayName = decoder.readString();
|
||||||
|
}
|
||||||
|
if (name.empty() || !seenId)
|
||||||
|
throw DecoderError("Missing name and id attributes in scope");
|
||||||
Scope *parentScope = (Scope *)0;
|
Scope *parentScope = (Scope *)0;
|
||||||
uint4 parentId = decoder.peekElement();
|
uint4 parentId = decoder.peekElement();
|
||||||
if (parentId == ELEM_PARENT) {
|
if (parentId == ELEM_PARENT) {
|
||||||
parentScope = parseParentTag(decoder);
|
parentScope = parseParentTag(decoder);
|
||||||
}
|
}
|
||||||
Scope *newScope = findCreateScope(id, name, parentScope);
|
Scope *newScope = findCreateScope(id, name, parentScope);
|
||||||
|
if (!displayName.empty())
|
||||||
|
newScope->setDisplayName(displayName);
|
||||||
newScope->decode(decoder);
|
newScope->decode(decoder);
|
||||||
decoder.closeElement(subId);
|
decoder.closeElement(subId);
|
||||||
}
|
}
|
||||||
|
@ -3356,4 +3394,39 @@ void Database::decodeScope(Decoder &decoder,Scope *newScope)
|
||||||
decoder.closeElement(elemId);
|
decoder.closeElement(elemId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Some namespace objects may already exist. Create those that don't.
|
||||||
|
/// \param decoder is the stream to decode the path from
|
||||||
|
/// \return the namespace described by the path
|
||||||
|
Scope *Database::decodeScopePath(Decoder &decoder)
|
||||||
|
|
||||||
|
{
|
||||||
|
Scope *curscope = getGlobalScope();
|
||||||
|
uint4 elemId = decoder.openElement(ELEM_PARENT);
|
||||||
|
uint4 subId = decoder.openElement();
|
||||||
|
decoder.closeElementSkipping(subId); // Skip element describing the root scope
|
||||||
|
for(;;) {
|
||||||
|
subId = decoder.openElement();
|
||||||
|
if (subId != ELEM_VAL) break;
|
||||||
|
string displayName;
|
||||||
|
uint8 scopeId = 0;
|
||||||
|
for(;;) {
|
||||||
|
uint4 attribId = decoder.getNextAttributeId();
|
||||||
|
if (attribId == 0) break;
|
||||||
|
if (attribId == ATTRIB_ID)
|
||||||
|
scopeId = decoder.readUnsignedInteger();
|
||||||
|
else if (attribId == ATTRIB_LABEL)
|
||||||
|
displayName = decoder.readString();
|
||||||
|
}
|
||||||
|
string name = decoder.readString(ATTRIB_CONTENT);
|
||||||
|
if (scopeId == 0)
|
||||||
|
throw DecoderError("Missing name and id in scope");
|
||||||
|
curscope = findCreateScope(scopeId, name, curscope);
|
||||||
|
if (!displayName.empty())
|
||||||
|
curscope->setDisplayName(displayName);
|
||||||
|
decoder.closeElement(subId);
|
||||||
|
}
|
||||||
|
decoder.closeElement(elemId);
|
||||||
|
return curscope;
|
||||||
|
}
|
||||||
|
|
||||||
} // End namespace ghidra
|
} // End namespace ghidra
|
||||||
|
|
|
@ -176,6 +176,7 @@ class Symbol {
|
||||||
protected:
|
protected:
|
||||||
Scope *scope; ///< The scope that owns this symbol
|
Scope *scope; ///< The scope that owns this symbol
|
||||||
string name; ///< The local name of the symbol
|
string name; ///< The local name of the symbol
|
||||||
|
string displayName; ///< Name to use when displaying symbol in output
|
||||||
Datatype *type; ///< The symbol's data-type
|
Datatype *type; ///< The symbol's data-type
|
||||||
uint4 nameDedup; ///< id to distinguish symbols with the same name
|
uint4 nameDedup; ///< id to distinguish symbols with the same name
|
||||||
uint4 flags; ///< Varnode-like properties of the symbol
|
uint4 flags; ///< Varnode-like properties of the symbol
|
||||||
|
@ -218,6 +219,7 @@ public:
|
||||||
Symbol(Scope *sc,const string &nm,Datatype *ct); ///< Construct given a name and data-type
|
Symbol(Scope *sc,const string &nm,Datatype *ct); ///< Construct given a name and data-type
|
||||||
Symbol(Scope *sc); ///< Construct for use with decode()
|
Symbol(Scope *sc); ///< Construct for use with decode()
|
||||||
const string &getName(void) const { return name; } ///< Get the local name of the symbol
|
const string &getName(void) const { return name; } ///< Get the local name of the symbol
|
||||||
|
const string &getDisplayName(void) const { return displayName; } ///< Get the name to display in output
|
||||||
Datatype *getType(void) const { return type; } ///< Get the data-type
|
Datatype *getType(void) const { return type; } ///< Get the data-type
|
||||||
uint8 getId(void) const { return symbolId; } ///< Get a unique id for the symbol
|
uint8 getId(void) const { return symbolId; } ///< Get a unique id for the symbol
|
||||||
uint4 getFlags(void) const { return flags; } ///< Get the boolean properties of the Symbol
|
uint4 getFlags(void) const { return flags; } ///< Get the boolean properties of the Symbol
|
||||||
|
@ -469,6 +471,7 @@ class Scope {
|
||||||
protected:
|
protected:
|
||||||
Architecture *glb; ///< Architecture of \b this scope
|
Architecture *glb; ///< Architecture of \b this scope
|
||||||
string name; ///< Name of \b this scope
|
string name; ///< Name of \b this scope
|
||||||
|
string displayName; ///< Name to display in output
|
||||||
Funcdata *fd; ///< (If non-null) the function which \b this is the local Scope for
|
Funcdata *fd; ///< (If non-null) the function which \b this is the local Scope for
|
||||||
uint8 uniqueId; ///< Unique id for the scope, for deduping scope names, assigning symbol ids
|
uint8 uniqueId; ///< Unique id for the scope, for deduping scope names, assigning symbol ids
|
||||||
static const Scope *stackAddr(const Scope *scope1,
|
static const Scope *stackAddr(const Scope *scope1,
|
||||||
|
@ -551,6 +554,7 @@ protected:
|
||||||
const RangeList &uselim)=0;
|
const RangeList &uselim)=0;
|
||||||
SymbolEntry *addMap(SymbolEntry &entry); ///< Integrate a SymbolEntry into the range maps
|
SymbolEntry *addMap(SymbolEntry &entry); ///< Integrate a SymbolEntry into the range maps
|
||||||
void setSymbolId(Symbol *sym,uint8 id) const { sym->symbolId = id; } ///< Adjust the id associated with a symbol
|
void setSymbolId(Symbol *sym,uint8 id) const { sym->symbolId = id; } ///< Adjust the id associated with a symbol
|
||||||
|
void setDisplayName(const string &nm) { displayName = nm; } ///< Change name displayed in output
|
||||||
public:
|
public:
|
||||||
#ifdef OPACTION_DEBUG
|
#ifdef OPACTION_DEBUG
|
||||||
mutable bool debugon;
|
mutable bool debugon;
|
||||||
|
@ -559,7 +563,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
/// \brief Construct an empty scope, given a name and Architecture
|
/// \brief Construct an empty scope, given a name and Architecture
|
||||||
Scope(uint8 id,const string &nm,Architecture *g,Scope *own) {
|
Scope(uint8 id,const string &nm,Architecture *g,Scope *own) {
|
||||||
uniqueId = id; name = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; owner=own;
|
uniqueId = id; name = nm; displayName = nm; glb = g; parent = (Scope *)0; fd = (Funcdata *)0; owner=own;
|
||||||
#ifdef OPACTION_DEBUG
|
#ifdef OPACTION_DEBUG
|
||||||
debugon = false;
|
debugon = false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -732,6 +736,7 @@ public:
|
||||||
const Address &addr,const Address &usepoint);
|
const Address &addr,const Address &usepoint);
|
||||||
|
|
||||||
const string &getName(void) const { return name; } ///< Get the name of the Scope
|
const string &getName(void) const { return name; } ///< Get the name of the Scope
|
||||||
|
const string &getDisplayName(void) const { return displayName; } ///< Get name displayed in output
|
||||||
uint8 getId(void) const { return uniqueId; } ///< Get the globally unique id
|
uint8 getId(void) const { return uniqueId; } ///< Get the globally unique id
|
||||||
bool isGlobal(void) const { return (fd == (Funcdata *)0); } ///< Return \b true if \b this scope is global
|
bool isGlobal(void) const { return (fd == (Funcdata *)0); } ///< Return \b true if \b this scope is global
|
||||||
|
|
||||||
|
@ -938,7 +943,8 @@ public:
|
||||||
const partmap<Address,uint4> &getProperties(void) const { return flagbase; } ///< Get the entire property map
|
const partmap<Address,uint4> &getProperties(void) const { return flagbase; } ///< Get the entire property map
|
||||||
void encode(Encoder &encoder) const; ///< Encode the whole Database to a stream
|
void encode(Encoder &encoder) const; ///< Encode the whole Database to a stream
|
||||||
void decode(Decoder &decoder); ///< Decode the whole database from a stream
|
void decode(Decoder &decoder); ///< Decode the whole database from a stream
|
||||||
void decodeScope(Decoder &decoder,Scope *newScope); ///< Register and fill out a single Scope from an XML \<scope> tag
|
void decodeScope(Decoder &decoder,Scope *newScope); ///< Register and fill out a single Scope from an XML \<scope> tag
|
||||||
|
Scope *decodeScopePath(Decoder &decoder); ///< Decode a namespace path and make sure each namespace exists
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \param sc is the scope containing the new symbol
|
/// \param sc is the scope containing the new symbol
|
||||||
|
@ -949,6 +955,7 @@ inline Symbol::Symbol(Scope *sc,const string &nm,Datatype *ct)
|
||||||
{
|
{
|
||||||
scope=sc;
|
scope=sc;
|
||||||
name=nm;
|
name=nm;
|
||||||
|
displayName = nm;
|
||||||
nameDedup=0;
|
nameDedup=0;
|
||||||
type=ct;
|
type=ct;
|
||||||
flags=0;
|
flags=0;
|
||||||
|
|
|
@ -42,7 +42,7 @@ ScopeGhidra::~ScopeGhidra(void)
|
||||||
|
|
||||||
/// The Ghidra client reports a \e namespace id associated with
|
/// The Ghidra client reports a \e namespace id associated with
|
||||||
/// Symbol. Determine if a matching \e namespace Scope already exists in the cache and build
|
/// Symbol. Determine if a matching \e namespace Scope already exists in the cache and build
|
||||||
/// it if it isn't. This may mean creating a new \e namespace Scope.
|
/// it if it isn't. This may mean creating the \e namespace Scope and its ancestors.
|
||||||
/// \param id is the ID associated with the Ghidra namespace
|
/// \param id is the ID associated with the Ghidra namespace
|
||||||
/// \return the Scope matching the id.
|
/// \return the Scope matching the id.
|
||||||
Scope *ScopeGhidra::reresolveScope(uint8 id) const
|
Scope *ScopeGhidra::reresolveScope(uint8 id) const
|
||||||
|
@ -58,19 +58,7 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const
|
||||||
if (!ghidra->getNamespacePath(id,decoder))
|
if (!ghidra->getNamespacePath(id,decoder))
|
||||||
throw LowlevelError("Could not get namespace info");
|
throw LowlevelError("Could not get namespace info");
|
||||||
|
|
||||||
Scope *curscope = symboltab->getGlobalScope(); // Get pointer to ourselves (which is not const)
|
return symboltab->decodeScopePath(decoder);
|
||||||
uint4 elemId = decoder.openElement();
|
|
||||||
uint4 subId = decoder.openElement();
|
|
||||||
decoder.closeElementSkipping(subId); // Skip element describing the root scope
|
|
||||||
for(;;) {
|
|
||||||
subId = decoder.openElement();
|
|
||||||
if (subId == 0) break;
|
|
||||||
uint8 scopeId = decoder.readUnsignedInteger(ATTRIB_ID);
|
|
||||||
curscope = symboltab->findCreateScope(scopeId, decoder.readString(ATTRIB_CONTENT), curscope);
|
|
||||||
decoder.closeElement(subId);
|
|
||||||
}
|
|
||||||
decoder.closeElement(elemId);
|
|
||||||
return curscope;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Ghidra client can respond to a query negatively by sending a
|
/// The Ghidra client can respond to a query negatively by sending a
|
||||||
|
|
|
@ -1398,8 +1398,9 @@ void FlowInfo::recoverJumpTables(vector<JumpTable *> &newTables,vector<PcodeOp *
|
||||||
s1 << data.getName() << "@@jump@";
|
s1 << data.getName() << "@@jump@";
|
||||||
op->getAddr().printRaw(s1);
|
op->getAddr().printRaw(s1);
|
||||||
|
|
||||||
|
string nm = s1.str();
|
||||||
// Prepare partial Funcdata object for analysis if necessary
|
// Prepare partial Funcdata object for analysis if necessary
|
||||||
Funcdata partial(s1.str(),data.getScopeLocal()->getParent(),data.getAddress(),(FunctionSymbol *)0);
|
Funcdata partial(nm,nm,data.getScopeLocal()->getParent(),data.getAddress(),(FunctionSymbol *)0);
|
||||||
|
|
||||||
for(int4 i=0;i<tablelist.size();++i) {
|
for(int4 i=0;i<tablelist.size();++i) {
|
||||||
op = tablelist[i];
|
op = tablelist[i];
|
||||||
|
|
|
@ -4668,8 +4668,8 @@ void FuncCallSpecs::setFuncdata(Funcdata *f)
|
||||||
fd = f;
|
fd = f;
|
||||||
if (fd != (Funcdata *)0) {
|
if (fd != (Funcdata *)0) {
|
||||||
entryaddress = fd->getAddress();
|
entryaddress = fd->getAddress();
|
||||||
if (fd->getName().size() != 0)
|
if (fd->getDisplayName().size() != 0)
|
||||||
name = fd->getName();
|
name = fd->getDisplayName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5130,7 +5130,7 @@ void FuncCallSpecs::deindirect(Funcdata &data,Funcdata *newfd)
|
||||||
|
|
||||||
{
|
{
|
||||||
entryaddress = newfd->getAddress();
|
entryaddress = newfd->getAddress();
|
||||||
name = newfd->getName();
|
name = newfd->getDisplayName();
|
||||||
fd = newfd;
|
fd = newfd;
|
||||||
|
|
||||||
Varnode *vn = data.newVarnodeCallSpecs(this);
|
Varnode *vn = data.newVarnodeCallSpecs(this);
|
||||||
|
|
|
@ -30,7 +30,7 @@ ElementId ELEM_VARNODES = ElementId("varnodes",119);
|
||||||
/// \param addr is the entry address for the function
|
/// \param addr is the entry address for the function
|
||||||
/// \param sym is the symbol representing the function
|
/// \param sym is the symbol representing the function
|
||||||
/// \param sz is the number of bytes (of code) in the function body
|
/// \param sz is the number of bytes (of code) in the function body
|
||||||
Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSymbol *sym,int4 sz)
|
Funcdata::Funcdata(const string &nm,const string &disp,Scope *scope,const Address &addr,FunctionSymbol *sym,int4 sz)
|
||||||
: baseaddr(addr),
|
: baseaddr(addr),
|
||||||
funcp(),
|
funcp(),
|
||||||
vbank(scope->getArch()),
|
vbank(scope->getArch()),
|
||||||
|
@ -47,6 +47,7 @@ Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSym
|
||||||
glb = scope->getArch();
|
glb = scope->getArch();
|
||||||
minLanedSize = glb->getMinimumLanedRegisterSize();
|
minLanedSize = glb->getMinimumLanedRegisterSize();
|
||||||
name = nm;
|
name = nm;
|
||||||
|
displayName = disp;
|
||||||
|
|
||||||
size = sz;
|
size = sz;
|
||||||
AddrSpace *stackid = glb->getStackSpace();
|
AddrSpace *stackid = glb->getStackSpace();
|
||||||
|
@ -734,9 +735,13 @@ uint8 Funcdata::decode(Decoder &decoder)
|
||||||
if (decoder.readBool())
|
if (decoder.readBool())
|
||||||
flags |= no_code;
|
flags |= no_code;
|
||||||
}
|
}
|
||||||
|
else if (attribId == ATTRIB_LABEL)
|
||||||
|
displayName = decoder.readString();
|
||||||
}
|
}
|
||||||
if (name.size() == 0)
|
if (name.size() == 0)
|
||||||
throw LowlevelError("Missing function name");
|
throw LowlevelError("Missing function name");
|
||||||
|
if (displayName.size() == 0)
|
||||||
|
displayName = name;
|
||||||
if (size == -1)
|
if (size == -1)
|
||||||
throw LowlevelError("Missing function size");
|
throw LowlevelError("Missing function size");
|
||||||
baseaddr = Address::decode( decoder );
|
baseaddr = Address::decode( decoder );
|
||||||
|
|
|
@ -79,6 +79,7 @@ class Funcdata {
|
||||||
Architecture *glb; ///< Global configuration data
|
Architecture *glb; ///< Global configuration data
|
||||||
FunctionSymbol *functionSymbol; ///< The symbol representing \b this function
|
FunctionSymbol *functionSymbol; ///< The symbol representing \b this function
|
||||||
string name; ///< Name of function
|
string name; ///< Name of function
|
||||||
|
string displayName; ///< Name to display in output
|
||||||
Address baseaddr; ///< Starting code address of binary data
|
Address baseaddr; ///< Starting code address of binary data
|
||||||
FuncProto funcp; ///< Prototype of this function
|
FuncProto funcp; ///< Prototype of this function
|
||||||
ScopeLocal *localmap; ///< Local variables (symbols in the function scope)
|
ScopeLocal *localmap; ///< Local variables (symbols in the function scope)
|
||||||
|
@ -136,9 +137,10 @@ class Funcdata {
|
||||||
static PcodeOp *findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer,
|
static PcodeOp *findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer,
|
||||||
bool findbranch,bool findcall,bool findreturn);
|
bool findbranch,bool findcall,bool findreturn);
|
||||||
public:
|
public:
|
||||||
Funcdata(const string &nm,Scope *conf,const Address &addr,FunctionSymbol *sym,int4 sz=0); ///< Constructor
|
Funcdata(const string &nm,const string &disp,Scope *conf,const Address &addr,FunctionSymbol *sym,int4 sz=0); ///< Constructor
|
||||||
~Funcdata(void); ///< Destructor
|
~Funcdata(void); ///< Destructor
|
||||||
const string &getName(void) const { return name; } ///< Get the function's local symbol name
|
const string &getName(void) const { return name; } ///< Get the function's local symbol name
|
||||||
|
const string &getDisplayName(void) const { return displayName; } ///< Get the name to display in output
|
||||||
const Address &getAddress(void) const { return baseaddr; } ///< Get the entry point address
|
const Address &getAddress(void) const { return baseaddr; } ///< Get the entry point address
|
||||||
int4 getSize(void) const { return size; } ///< Get the function body size in bytes
|
int4 getSize(void) const { return size; } ///< Get the function body size in bytes
|
||||||
Architecture *getArch(void) const { return glb; } ///< Get the program/architecture owning \b this function
|
Architecture *getArch(void) const { return glb; } ///< Get the program/architecture owning \b this function
|
||||||
|
|
|
@ -222,7 +222,7 @@ void PrintC::pushSymbolScope(const Symbol *symbol)
|
||||||
pushOp(&scope, (PcodeOp *)0);
|
pushOp(&scope, (PcodeOp *)0);
|
||||||
}
|
}
|
||||||
for(int4 i=scopedepth-1;i>=0;--i) {
|
for(int4 i=scopedepth-1;i>=0;--i) {
|
||||||
pushAtom(Atom(scopeList[i]->getName(),syntax,EmitMarkup::global_color,(PcodeOp *)0,(Varnode *)0));
|
pushAtom(Atom(scopeList[i]->getDisplayName(),syntax,EmitMarkup::global_color,(PcodeOp *)0,(Varnode *)0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,7 +252,7 @@ void PrintC::emitSymbolScope(const Symbol *symbol)
|
||||||
point = point->getParent();
|
point = point->getParent();
|
||||||
}
|
}
|
||||||
for(int4 i=scopedepth-1;i>=0;--i) {
|
for(int4 i=scopedepth-1;i>=0;--i) {
|
||||||
emit->print(scopeList[i]->getName(), EmitMarkup::global_color);
|
emit->print(scopeList[i]->getDisplayName(), EmitMarkup::global_color);
|
||||||
emit->print(scope.print1, EmitMarkup::no_color);
|
emit->print(scope.print1, EmitMarkup::no_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,7 @@ void PrintC::pushTypeStart(const Datatype *ct,bool noident)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pushOp(tok,(const PcodeOp *)0);
|
pushOp(tok,(const PcodeOp *)0);
|
||||||
pushAtom(Atom(ct->getName(),typetoken,EmitMarkup::type_color,ct));
|
pushAtom(Atom(ct->getDisplayName(),typetoken,EmitMarkup::type_color,ct));
|
||||||
}
|
}
|
||||||
for(int4 i=typestack.size()-2;i>=0;--i) {
|
for(int4 i=typestack.size()-2;i>=0;--i) {
|
||||||
ct = typestack[i];
|
ct = typestack[i];
|
||||||
|
@ -661,7 +661,7 @@ void PrintC::opConstructor(const PcodeOp *op,bool withNew)
|
||||||
if (dt->getMetatype() == TYPE_PTR) {
|
if (dt->getMetatype() == TYPE_PTR) {
|
||||||
dt = ((TypePointer *)dt)->getPtrTo();
|
dt = ((TypePointer *)dt)->getPtrTo();
|
||||||
}
|
}
|
||||||
string nm = dt->getName();
|
string nm = dt->getDisplayName();
|
||||||
pushOp(&function_call,op);
|
pushOp(&function_call,op);
|
||||||
pushAtom(Atom(nm,optoken,EmitMarkup::funcname_color,op));
|
pushAtom(Atom(nm,optoken,EmitMarkup::funcname_color,op));
|
||||||
// implied vn's pushed on in reverse order for efficiency
|
// implied vn's pushed on in reverse order for efficiency
|
||||||
|
@ -1112,7 +1112,7 @@ void PrintC::opCpoolRefOp(const PcodeOp *op)
|
||||||
pushAtom(Atom(rec->getToken(),functoken,EmitMarkup::funcname_color,op,outvn));
|
pushAtom(Atom(rec->getToken(),functoken,EmitMarkup::funcname_color,op,outvn));
|
||||||
pushOp(&comma,(const PcodeOp *)0);
|
pushOp(&comma,(const PcodeOp *)0);
|
||||||
pushVn(vn0,op,mods);
|
pushVn(vn0,op,mods);
|
||||||
pushAtom(Atom(dt->getName(),syntax,EmitMarkup::type_color,op,outvn));
|
pushAtom(Atom(dt->getDisplayName(),syntax,EmitMarkup::type_color,op,outvn));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPoolRecord::primitive: // Should be eliminated
|
case CPoolRecord::primitive: // Should be eliminated
|
||||||
|
@ -1163,7 +1163,7 @@ void PrintC::opNewOp(const PcodeOp *op)
|
||||||
while (dt->getMetatype() == TYPE_PTR) {
|
while (dt->getMetatype() == TYPE_PTR) {
|
||||||
dt = ((TypePointer *)dt)->getPtrTo();
|
dt = ((TypePointer *)dt)->getPtrTo();
|
||||||
}
|
}
|
||||||
nm = dt->getName();
|
nm = dt->getDisplayName();
|
||||||
}
|
}
|
||||||
pushOp(&subscript,op);
|
pushOp(&subscript,op);
|
||||||
pushAtom(Atom(nm,optoken,EmitMarkup::type_color,op));
|
pushAtom(Atom(nm,optoken,EmitMarkup::type_color,op));
|
||||||
|
@ -1658,7 +1658,7 @@ bool PrintC::pushPtrCodeConstant(uintb val,const TypePointer *ct,
|
||||||
val = AddrSpace::addressToByte(val,spc->getWordSize());
|
val = AddrSpace::addressToByte(val,spc->getWordSize());
|
||||||
fd = glb->symboltab->getGlobalScope()->queryFunction( Address(spc,val));
|
fd = glb->symboltab->getGlobalScope()->queryFunction( Address(spc,val));
|
||||||
if (fd != (Funcdata *)0) {
|
if (fd != (Funcdata *)0) {
|
||||||
pushAtom(Atom(fd->getName(),functoken,EmitMarkup::funcname_color,op,fd));
|
pushAtom(Atom(fd->getDisplayName(),functoken,EmitMarkup::funcname_color,op,fd));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1839,7 +1839,7 @@ void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
|
||||||
HighVariable *high = vn->getHigh();
|
HighVariable *high = vn->getHigh();
|
||||||
if (high->isUnmerged()) {
|
if (high->isUnmerged()) {
|
||||||
ostringstream s;
|
ostringstream s;
|
||||||
s << sym->getName();
|
s << sym->getDisplayName();
|
||||||
SymbolEntry *entry = high->getSymbolEntry();
|
SymbolEntry *entry = high->getSymbolEntry();
|
||||||
if (entry != (SymbolEntry *)0) {
|
if (entry != (SymbolEntry *)0) {
|
||||||
s << '$' << dec << entry->getSymbol()->getMapEntryPosition(entry);
|
s << '$' << dec << entry->getSymbol()->getMapEntryPosition(entry);
|
||||||
|
@ -1850,7 +1850,7 @@ void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pushAtom(Atom(sym->getName(),vartoken,tokenColor,op,vn));
|
pushAtom(Atom(sym->getDisplayName(),vartoken,tokenColor,op,vn));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintC::pushUnnamedLocation(const Address &addr,
|
void PrintC::pushUnnamedLocation(const Address &addr,
|
||||||
|
@ -1984,7 +1984,7 @@ void PrintC::pushMismatchSymbol(const Symbol *sym,int4 off,int4 sz,
|
||||||
|
|
||||||
// We prepend an underscore to indicate a close
|
// We prepend an underscore to indicate a close
|
||||||
// but not quite match
|
// but not quite match
|
||||||
string nm = '_'+sym->getName();
|
string nm = '_'+sym->getDisplayName();
|
||||||
pushAtom(Atom(nm,vartoken,EmitMarkup::var_color,op,vn));
|
pushAtom(Atom(nm,vartoken,EmitMarkup::var_color,op,vn));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2057,7 +2057,7 @@ void PrintC::emitStructDefinition(const TypeStruct *ct)
|
||||||
emit->tagLine();
|
emit->tagLine();
|
||||||
emit->print(CLOSE_CURLY);
|
emit->print(CLOSE_CURLY);
|
||||||
emit->spaces(1);
|
emit->spaces(1);
|
||||||
emit->print(ct->getName());
|
emit->print(ct->getDisplayName());
|
||||||
emit->print(SEMICOLON);
|
emit->print(SEMICOLON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2100,7 +2100,7 @@ void PrintC::emitEnumDefinition(const TypeEnum *ct)
|
||||||
emit->tagLine();
|
emit->tagLine();
|
||||||
emit->print(CLOSE_CURLY);
|
emit->print(CLOSE_CURLY);
|
||||||
emit->spaces(1);
|
emit->spaces(1);
|
||||||
emit->print(ct->getName());
|
emit->print(ct->getDisplayName());
|
||||||
emit->print(SEMICOLON);
|
emit->print(SEMICOLON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2507,7 +2507,7 @@ void PrintC::emitFunctionDeclaration(const Funcdata *fd)
|
||||||
}
|
}
|
||||||
int4 id1 = emit->openGroup();
|
int4 id1 = emit->openGroup();
|
||||||
emitSymbolScope(fd->getSymbol());
|
emitSymbolScope(fd->getSymbol());
|
||||||
emit->tagFuncName(fd->getName(),EmitMarkup::funcname_color,fd,(PcodeOp *)0);
|
emit->tagFuncName(fd->getDisplayName(),EmitMarkup::funcname_color,fd,(PcodeOp *)0);
|
||||||
|
|
||||||
emit->spaces(function_call.spacing,function_call.bump);
|
emit->spaces(function_call.spacing,function_call.bump);
|
||||||
int4 id2 = emit->openParen(OPEN_PAREN);
|
int4 id2 = emit->openParen(OPEN_PAREN);
|
||||||
|
@ -3122,7 +3122,7 @@ void PrintC::emitLabel(const FlowBlock *bl)
|
||||||
const Scope *symScope = ((const BlockBasic *)bb)->getFuncdata()->getScopeLocal();
|
const Scope *symScope = ((const BlockBasic *)bb)->getFuncdata()->getScopeLocal();
|
||||||
Symbol *sym = symScope->queryCodeLabel(addr);
|
Symbol *sym = symScope->queryCodeLabel(addr);
|
||||||
if (sym != (Symbol *)0) {
|
if (sym != (Symbol *)0) {
|
||||||
emit->tagLabel(sym->getName(),EmitMarkup::no_color,spc,off);
|
emit->tagLabel(sym->getDisplayName(),EmitMarkup::no_color,spc,off);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ void PrintJava::pushTypeStart(const Datatype *ct,bool noident)
|
||||||
pushAtom(Atom(nm,typetoken,EmitMarkup::type_color,ct));
|
pushAtom(Atom(nm,typetoken,EmitMarkup::type_color,ct));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pushAtom(Atom(ct->getName(),typetoken,EmitMarkup::type_color,ct));
|
pushAtom(Atom(ct->getDisplayName(),typetoken,EmitMarkup::type_color,ct));
|
||||||
}
|
}
|
||||||
for(int4 i=0;i<arrayCount;++i)
|
for(int4 i=0;i<arrayCount;++i)
|
||||||
pushAtom(Atom(EMPTY_STRING,blanktoken,EmitMarkup::no_color)); // Fill in the blank array index
|
pushAtom(Atom(EMPTY_STRING,blanktoken,EmitMarkup::no_color)); // Fill in the blank array index
|
||||||
|
@ -332,7 +332,7 @@ void PrintJava::opCpoolRefOp(const PcodeOp *op)
|
||||||
}
|
}
|
||||||
pushOp(&instanceof,op);
|
pushOp(&instanceof,op);
|
||||||
pushVn(vn0,op,mods);
|
pushVn(vn0,op,mods);
|
||||||
pushAtom(Atom(dt->getName(),syntax,EmitMarkup::type_color,op,outvn));
|
pushAtom(Atom(dt->getDisplayName(),syntax,EmitMarkup::type_color,op,outvn));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPoolRecord::primitive: // Should be eliminated
|
case CPoolRecord::primitive: // Should be eliminated
|
||||||
|
|
|
@ -544,6 +544,9 @@ void Datatype::decodeBasic(Decoder &decoder)
|
||||||
uint4 val = encodeIntegerFormat(decoder.readString());
|
uint4 val = encodeIntegerFormat(decoder.readString());
|
||||||
setDisplayFormat(val);
|
setDisplayFormat(val);
|
||||||
}
|
}
|
||||||
|
else if (attrib == ATTRIB_LABEL) {
|
||||||
|
displayName = decoder.readString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
throw LowlevelError("Bad size for type "+name);
|
throw LowlevelError("Bad size for type "+name);
|
||||||
|
@ -554,6 +557,8 @@ void Datatype::decodeBasic(Decoder &decoder)
|
||||||
// Id needs to be unique compared to another data-type with the same name
|
// Id needs to be unique compared to another data-type with the same name
|
||||||
id = hashSize(id, size);
|
id = hashSize(id, size);
|
||||||
}
|
}
|
||||||
|
if (displayName.empty())
|
||||||
|
displayName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If a type id is explicitly provided for a data-type, this routine is used
|
/// If a type id is explicitly provided for a data-type, this routine is used
|
||||||
|
@ -3003,6 +3008,7 @@ Datatype *TypeFactory::setName(Datatype *ct,const string &n)
|
||||||
nametree.erase( ct ); // Erase any name reference
|
nametree.erase( ct ); // Erase any name reference
|
||||||
tree.erase(ct); // Remove new type completely from trees
|
tree.erase(ct); // Remove new type completely from trees
|
||||||
ct->name = n; // Change the name
|
ct->name = n; // Change the name
|
||||||
|
ct->displayName = n;
|
||||||
if (ct->id == 0)
|
if (ct->id == 0)
|
||||||
ct->id = Datatype::hashName(n);
|
ct->id = Datatype::hashName(n);
|
||||||
// Insert type with new name
|
// Insert type with new name
|
||||||
|
@ -3215,7 +3221,7 @@ TypeVoid *TypeFactory::getTypeVoid(void)
|
||||||
if (ct != (TypeVoid *)0)
|
if (ct != (TypeVoid *)0)
|
||||||
return ct;
|
return ct;
|
||||||
TypeVoid tv;
|
TypeVoid tv;
|
||||||
tv.id = Datatype::hashName(tv.getName());
|
tv.id = Datatype::hashName(tv.name);
|
||||||
ct = (TypeVoid *)tv.clone();
|
ct = (TypeVoid *)tv.clone();
|
||||||
tree.insert(ct);
|
tree.insert(ct);
|
||||||
nametree.insert(ct);
|
nametree.insert(ct);
|
||||||
|
@ -3332,6 +3338,7 @@ TypeCode *TypeFactory::getTypeCode(const string &nm)
|
||||||
if (nm.size()==0) return getTypeCode();
|
if (nm.size()==0) return getTypeCode();
|
||||||
TypeCode tmp; // Generic code data-type
|
TypeCode tmp; // Generic code data-type
|
||||||
tmp.name = nm; // with a name
|
tmp.name = nm; // with a name
|
||||||
|
tmp.displayName = nm;
|
||||||
tmp.id = Datatype::hashName(nm);
|
tmp.id = Datatype::hashName(nm);
|
||||||
tmp.markComplete(); // considered complete
|
tmp.markComplete(); // considered complete
|
||||||
return (TypeCode *) findAdd(tmp);
|
return (TypeCode *) findAdd(tmp);
|
||||||
|
@ -3384,6 +3391,7 @@ Datatype *TypeFactory::getTypedef(Datatype *ct,const string &name,uint8 id,uint4
|
||||||
}
|
}
|
||||||
res = ct->clone(); // Clone everything
|
res = ct->clone(); // Clone everything
|
||||||
res->name = name; // But a new name
|
res->name = name; // But a new name
|
||||||
|
res->displayName = name;
|
||||||
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;
|
||||||
|
@ -3438,6 +3446,7 @@ TypePointer *TypeFactory::getTypePointer(int4 s,Datatype *pt,uint4 ws,const stri
|
||||||
pt = pt->getStripped();
|
pt = pt->getStripped();
|
||||||
TypePointer tmp(s,pt,ws);
|
TypePointer tmp(s,pt,ws);
|
||||||
tmp.name = n;
|
tmp.name = n;
|
||||||
|
tmp.displayName = n;
|
||||||
tmp.id = Datatype::hashName(n);
|
tmp.id = Datatype::hashName(n);
|
||||||
return (TypePointer *) findAdd(tmp);
|
return (TypePointer *) findAdd(tmp);
|
||||||
}
|
}
|
||||||
|
@ -3485,6 +3494,7 @@ TypeStruct *TypeFactory::getTypeStruct(const string &n)
|
||||||
{
|
{
|
||||||
TypeStruct tmp;
|
TypeStruct tmp;
|
||||||
tmp.name = n;
|
tmp.name = n;
|
||||||
|
tmp.displayName = n;
|
||||||
tmp.id = Datatype::hashName(n);
|
tmp.id = Datatype::hashName(n);
|
||||||
return (TypeStruct *) findAdd(tmp);
|
return (TypeStruct *) findAdd(tmp);
|
||||||
}
|
}
|
||||||
|
@ -3505,6 +3515,7 @@ TypeUnion *TypeFactory::getTypeUnion(const string &n)
|
||||||
{
|
{
|
||||||
TypeUnion tmp;
|
TypeUnion tmp;
|
||||||
tmp.name = n;
|
tmp.name = n;
|
||||||
|
tmp.displayName = n;
|
||||||
tmp.id = Datatype::hashName(n);
|
tmp.id = Datatype::hashName(n);
|
||||||
return (TypeUnion *) findAdd(tmp);
|
return (TypeUnion *) findAdd(tmp);
|
||||||
}
|
}
|
||||||
|
@ -3587,6 +3598,7 @@ TypePointerRel *TypeFactory::getTypePointerRel(int4 sz,Datatype *parent,Datatype
|
||||||
{
|
{
|
||||||
TypePointerRel tp(sz,ptrTo,ws,parent,off);
|
TypePointerRel tp(sz,ptrTo,ws,parent,off);
|
||||||
tp.name = nm;
|
tp.name = nm;
|
||||||
|
tp.displayName = nm;
|
||||||
tp.id = Datatype::hashName(nm);
|
tp.id = Datatype::hashName(nm);
|
||||||
TypePointerRel *res = (TypePointerRel *)findAdd(tp);
|
TypePointerRel *res = (TypePointerRel *)findAdd(tp);
|
||||||
return res;
|
return res;
|
||||||
|
@ -3605,6 +3617,7 @@ TypePointer *TypeFactory::getTypePointerWithSpace(Datatype *ptrTo,AddrSpace *spc
|
||||||
{
|
{
|
||||||
TypePointer tp(ptrTo,spc);
|
TypePointer tp(ptrTo,spc);
|
||||||
tp.name = nm;
|
tp.name = nm;
|
||||||
|
tp.displayName = nm;
|
||||||
tp.id = Datatype::hashName(nm);
|
tp.id = Datatype::hashName(nm);
|
||||||
TypePointer *res = (TypePointer *)findAdd(tp);
|
TypePointer *res = (TypePointer *)findAdd(tp);
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -159,12 +159,13 @@ protected:
|
||||||
};
|
};
|
||||||
friend class TypeFactory;
|
friend class TypeFactory;
|
||||||
friend struct DatatypeCompare;
|
friend struct DatatypeCompare;
|
||||||
|
uint8 id; ///< A unique id for the type (or 0 if an id is not assigned)
|
||||||
int4 size; ///< Size (of variable holding a value of this type)
|
int4 size; ///< Size (of variable holding a value of this type)
|
||||||
|
uint4 flags; ///< Boolean properties of the type
|
||||||
string name; ///< Name of type
|
string name; ///< Name of type
|
||||||
|
string displayName; ///< Name to display in output
|
||||||
type_metatype metatype; ///< Meta-type - type disregarding size
|
type_metatype metatype; ///< Meta-type - type disregarding size
|
||||||
sub_metatype submeta; ///< Sub-type of of the meta-type, for comparisons
|
sub_metatype submeta; ///< Sub-type of of the meta-type, for comparisons
|
||||||
uint4 flags; ///< Boolean properties of the type
|
|
||||||
uint8 id; ///< A unique id for the type (or 0 if an id is not assigned)
|
|
||||||
Datatype *typedefImm; ///< The immediate data-type being typedefed by \e this
|
Datatype *typedefImm; ///< The immediate data-type being typedefed by \e this
|
||||||
void decodeBasic(Decoder &decoder); ///< Recover basic data-type properties
|
void decodeBasic(Decoder &decoder); ///< Recover basic data-type properties
|
||||||
void encodeBasic(type_metatype meta,Encoder &encoder) const; ///< Encode basic data-type properties
|
void encodeBasic(type_metatype meta,Encoder &encoder) const; ///< Encode basic data-type properties
|
||||||
|
@ -176,8 +177,8 @@ protected:
|
||||||
static uint8 hashSize(uint8 id,int4 size); ///< Reversibly hash size into id
|
static uint8 hashSize(uint8 id,int4 size); ///< Reversibly hash size into id
|
||||||
public:
|
public:
|
||||||
/// Construct the base data-type copying low-level properties of another
|
/// Construct the base data-type copying low-level properties of another
|
||||||
Datatype(const Datatype &op) { size = op.size; name=op.name; metatype=op.metatype; submeta=op.submeta; flags=op.flags;
|
Datatype(const Datatype &op) { size = op.size; name=op.name; displayName=op.displayName; metatype=op.metatype;
|
||||||
id=op.id; typedefImm=op.typedefImm; }
|
submeta=op.submeta; flags=op.flags; id=op.id; typedefImm=op.typedefImm; }
|
||||||
/// Construct the base data-type providing size and meta-type
|
/// Construct the base data-type providing size and meta-type
|
||||||
Datatype(int4 s,type_metatype m) { size=s; metatype=m; submeta=base2sub[m]; flags=0; id=0; typedefImm=(Datatype *)0; }
|
Datatype(int4 s,type_metatype m) { size=s; metatype=m; submeta=base2sub[m]; flags=0; id=0; typedefImm=(Datatype *)0; }
|
||||||
virtual ~Datatype(void) {} ///< Destructor
|
virtual ~Datatype(void) {} ///< Destructor
|
||||||
|
@ -203,6 +204,7 @@ public:
|
||||||
uint8 getId(void) const { return id; } ///< Get the type id
|
uint8 getId(void) const { return id; } ///< Get the type id
|
||||||
int4 getSize(void) const { return size; } ///< Get the type size
|
int4 getSize(void) const { return size; } ///< Get the type size
|
||||||
const string &getName(void) const { return name; } ///< Get the type name
|
const string &getName(void) const { return name; } ///< Get the type name
|
||||||
|
const string &getDisplayName(void) const { return displayName; } ///< Get string to use in display
|
||||||
Datatype *getTypedef(void) const { return typedefImm; } ///< Get the data-type immediately typedefed by \e this (or null)
|
Datatype *getTypedef(void) const { return typedefImm; } ///< Get the data-type immediately typedefed by \e this (or null)
|
||||||
virtual void printRaw(ostream &s) const; ///< Print a description of the type to stream
|
virtual void printRaw(ostream &s) const; ///< Print a description of the type to stream
|
||||||
virtual const TypeField *findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
virtual const TypeField *findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
||||||
|
@ -279,7 +281,7 @@ public:
|
||||||
/// Construct TypeBase from a size and meta-type
|
/// Construct TypeBase from a size and meta-type
|
||||||
TypeBase(int4 s,type_metatype m) : Datatype(s,m) {}
|
TypeBase(int4 s,type_metatype m) : Datatype(s,m) {}
|
||||||
/// Construct TypeBase from a size, meta-type, and name
|
/// Construct TypeBase from a size, meta-type, and name
|
||||||
TypeBase(int4 s,type_metatype m,const string &n) : Datatype(s,m) { name = n; }
|
TypeBase(int4 s,type_metatype m,const string &n) : Datatype(s,m) { name = n; displayName = n; }
|
||||||
virtual Datatype *clone(void) const { return new TypeBase(*this); }
|
virtual Datatype *clone(void) const { return new TypeBase(*this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -326,7 +328,7 @@ public:
|
||||||
/// Construct from another TypeVoid
|
/// Construct from another TypeVoid
|
||||||
TypeVoid(const TypeVoid &op) : Datatype(op) { flags |= Datatype::coretype; }
|
TypeVoid(const TypeVoid &op) : Datatype(op) { flags |= Datatype::coretype; }
|
||||||
/// Constructor
|
/// Constructor
|
||||||
TypeVoid(void) : Datatype(0,TYPE_VOID) { name = "void"; flags |= Datatype::coretype; }
|
TypeVoid(void) : Datatype(0,TYPE_VOID) { name = "void"; displayName = name; flags |= Datatype::coretype; }
|
||||||
virtual Datatype *clone(void) const { return new TypeVoid(*this); }
|
virtual Datatype *clone(void) const { return new TypeVoid(*this); }
|
||||||
virtual void encode(Encoder &encoder) const;
|
virtual void encode(Encoder &encoder) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -370,7 +370,7 @@ public class DecompInterface {
|
||||||
}
|
}
|
||||||
compilerSpec = spec;
|
compilerSpec = spec;
|
||||||
|
|
||||||
dtmanage = new PcodeDataTypeManager(prog);
|
dtmanage = new PcodeDataTypeManager(prog, options.getNameTransformer());
|
||||||
try {
|
try {
|
||||||
decompCallback =
|
decompCallback =
|
||||||
new DecompileCallback(prog, pcodelanguage, program.getCompilerSpec(), dtmanage);
|
new DecompileCallback(prog, pcodelanguage, program.getCompilerSpec(), dtmanage);
|
||||||
|
@ -642,6 +642,9 @@ public class DecompInterface {
|
||||||
*/
|
*/
|
||||||
public synchronized boolean setOptions(DecompileOptions options) {
|
public synchronized boolean setOptions(DecompileOptions options) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
if (dtmanage != null) {
|
||||||
|
dtmanage.setNameTransformer(options.getNameTransformer());
|
||||||
|
}
|
||||||
decompileMessage = "";
|
decompileMessage = "";
|
||||||
// Property can be set before process exists
|
// Property can be set before process exists
|
||||||
if (decompProcess == null) {
|
if (decompProcess == null) {
|
||||||
|
|
|
@ -539,7 +539,7 @@ public class DecompileCallback {
|
||||||
*/
|
*/
|
||||||
public void getNamespacePath(long id, Encoder resultEncoder) throws IOException {
|
public void getNamespacePath(long id, Encoder resultEncoder) throws IOException {
|
||||||
Namespace namespace = getNameSpaceByID(id);
|
Namespace namespace = getNameSpaceByID(id);
|
||||||
HighFunction.encodeNamespace(resultEncoder, namespace);
|
HighFunction.encodeNamespace(resultEncoder, namespace, dtmanage.getNameTransformer());
|
||||||
if (debug != null) {
|
if (debug != null) {
|
||||||
debug.getNamespacePath(namespace);
|
debug.getNamespacePath(namespace);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,16 +29,16 @@ import generic.theme.Gui;
|
||||||
import ghidra.GhidraOptions;
|
import ghidra.GhidraOptions;
|
||||||
import ghidra.GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES;
|
import ghidra.GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.app.util.template.TemplateSimplifier;
|
||||||
import ghidra.framework.options.ToolOptions;
|
import ghidra.framework.options.ToolOptions;
|
||||||
import ghidra.framework.plugintool.Plugin;
|
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
|
||||||
import ghidra.program.database.ProgramCompilerSpec;
|
import ghidra.program.database.ProgramCompilerSpec;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.lang.CompilerSpec.EvaluationModelType;
|
import ghidra.program.model.lang.CompilerSpec.EvaluationModelType;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.pcode.ElementId;
|
import ghidra.program.model.pcode.ElementId;
|
||||||
import ghidra.program.model.pcode.Encoder;
|
import ghidra.program.model.pcode.Encoder;
|
||||||
|
import ghidra.program.model.symbol.NameTransformer;
|
||||||
|
import ghidra.program.model.symbol.IdentityNameTransformer;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -397,6 +397,8 @@ public class DecompileOptions {
|
||||||
|
|
||||||
private DecompilerLanguage displayLanguage; // Output language displayed by the decompiler
|
private DecompilerLanguage displayLanguage; // Output language displayed by the decompiler
|
||||||
|
|
||||||
|
private NameTransformer nameTransformer; // Transformer applied to data-type/function names
|
||||||
|
|
||||||
private String protoEvalModel; // Name of the prototype evaluation model
|
private String protoEvalModel; // Name of the prototype evaluation model
|
||||||
|
|
||||||
public DecompileOptions() {
|
public DecompileOptions() {
|
||||||
|
@ -434,16 +436,17 @@ public class DecompileOptions {
|
||||||
payloadLimitMBytes = SUGGESTED_MAX_PAYLOAD_BYTES;
|
payloadLimitMBytes = SUGGESTED_MAX_PAYLOAD_BYTES;
|
||||||
maxIntructionsPer = SUGGESTED_MAX_INSTRUCTIONS;
|
maxIntructionsPer = SUGGESTED_MAX_INSTRUCTIONS;
|
||||||
cachedResultsSize = SUGGESTED_CACHED_RESULTS_SIZE;
|
cachedResultsSize = SUGGESTED_CACHED_RESULTS_SIZE;
|
||||||
|
nameTransformer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grab all the decompiler options from various sources within a specific tool and program
|
* Grab all the decompiler options from various sources within a specific tool and program
|
||||||
* and cache them in this object.
|
* and cache them in this object.
|
||||||
* @param ownerPlugin the plugin that owns the "tool options" for the decompiler
|
* @param fieldOptions the Options object containing options specific to listing fields
|
||||||
* @param opt the Options object that contains the "tool options" specific to the decompiler
|
* @param opt the Options object that contains the "tool options" specific to the decompiler
|
||||||
* @param program the program whose "program options" are relevant to the decompiler
|
* @param program the program whose "program options" are relevant to the decompiler
|
||||||
*/
|
*/
|
||||||
public void grabFromToolAndProgram(Plugin ownerPlugin, ToolOptions opt, Program program) {
|
public void grabFromToolAndProgram(ToolOptions fieldOptions, ToolOptions opt, Program program) {
|
||||||
|
|
||||||
grabFromProgram(program);
|
grabFromProgram(program);
|
||||||
|
|
||||||
|
@ -491,20 +494,18 @@ public class DecompileOptions {
|
||||||
maxIntructionsPer = opt.getInt(MAX_INSTRUCTIONS, SUGGESTED_MAX_INSTRUCTIONS);
|
maxIntructionsPer = opt.getInt(MAX_INSTRUCTIONS, SUGGESTED_MAX_INSTRUCTIONS);
|
||||||
cachedResultsSize = opt.getInt(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE);
|
cachedResultsSize = opt.getInt(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE);
|
||||||
|
|
||||||
grabFromToolOptions(ownerPlugin);
|
grabFromFieldOptions(fieldOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void grabFromToolOptions(Plugin ownerPlugin) {
|
private void grabFromFieldOptions(ToolOptions fieldOptions) {
|
||||||
if (ownerPlugin == null) {
|
if (fieldOptions == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginTool tool = ownerPlugin.getTool();
|
|
||||||
Options toolOptions = tool.getOptions(CATEGORY_BROWSER_FIELDS);
|
|
||||||
|
|
||||||
CURSOR_MOUSE_BUTTON_NAMES mouseEvent =
|
CURSOR_MOUSE_BUTTON_NAMES mouseEvent =
|
||||||
toolOptions.getEnum(CURSOR_HIGHLIGHT_BUTTON_NAME, CURSOR_MOUSE_BUTTON_NAMES.MIDDLE);
|
fieldOptions.getEnum(CURSOR_HIGHLIGHT_BUTTON_NAME, CURSOR_MOUSE_BUTTON_NAMES.MIDDLE);
|
||||||
middleMouseHighlightButton = mouseEvent.getMouseEventID();
|
middleMouseHighlightButton = mouseEvent.getMouseEventID();
|
||||||
|
nameTransformer = new TemplateSimplifier(fieldOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -531,10 +532,18 @@ public class DecompileOptions {
|
||||||
displayLanguage = cspec.getDecompilerOutputLanguage();
|
displayLanguage = cspec.getDecompilerOutputLanguage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the default prototype to assume if no other information about a function is known
|
||||||
|
*/
|
||||||
public String getProtoEvalModel() {
|
public String getProtoEvalModel() {
|
||||||
return protoEvalModel;
|
return protoEvalModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default prototype model for the decompiler. This is the model assumed if no other
|
||||||
|
* information about a function is known.
|
||||||
|
* @param protoEvalModel is the name of the prototype model to set as default
|
||||||
|
*/
|
||||||
public void setProtoEvalModel(String protoEvalModel) {
|
public void setProtoEvalModel(String protoEvalModel) {
|
||||||
this.protoEvalModel = protoEvalModel;
|
this.protoEvalModel = protoEvalModel;
|
||||||
}
|
}
|
||||||
|
@ -542,11 +551,11 @@ public class DecompileOptions {
|
||||||
/**
|
/**
|
||||||
* This registers all the decompiler tool options with ghidra, and has the side effect of
|
* This registers all the decompiler tool options with ghidra, and has the side effect of
|
||||||
* pulling all the current values for the options if they exist
|
* pulling all the current values for the options if they exist
|
||||||
* @param ownerPlugin the plugin to which the options should be registered
|
* @param fieldOptions the options object specific to listing fields
|
||||||
* @param opt the options object to register with
|
* @param opt the options object specific to the decompiler
|
||||||
* @param program the program
|
* @param program the program
|
||||||
*/
|
*/
|
||||||
public void registerOptions(Plugin ownerPlugin, ToolOptions opt, Program program) {
|
public void registerOptions(ToolOptions fieldOptions, ToolOptions opt, Program program) {
|
||||||
opt.registerOption(PREDICATE_OPTIONSTRING, PREDICATE_OPTIONDEFAULT,
|
opt.registerOption(PREDICATE_OPTIONSTRING, PREDICATE_OPTIONDEFAULT,
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisPredicate"),
|
new HelpLocation(HelpTopics.DECOMPILER, "AnalysisPredicate"),
|
||||||
PREDICATE_OPTIONDESCRIPTION);
|
PREDICATE_OPTIONDESCRIPTION);
|
||||||
|
@ -686,7 +695,7 @@ public class DecompileOptions {
|
||||||
"Current variable highlight");
|
"Current variable highlight");
|
||||||
opt.registerOption(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE,
|
opt.registerOption(CACHED_RESULTS_SIZE_MSG, SUGGESTED_CACHED_RESULTS_SIZE,
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "GeneralCacheSize"), CACHE_RESULTS_DESCRIPTION);
|
new HelpLocation(HelpTopics.DECOMPILER, "GeneralCacheSize"), CACHE_RESULTS_DESCRIPTION);
|
||||||
grabFromToolAndProgram(ownerPlugin, opt, program);
|
grabFromToolAndProgram(fieldOptions, opt, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void appendOption(Encoder encoder, ElementId option, String p1, String p2,
|
private static void appendOption(Encoder encoder, ElementId option, String p1, String p2,
|
||||||
|
@ -825,10 +834,17 @@ public class DecompileOptions {
|
||||||
encoder.closeElement(ELEM_OPTIONSLIST);
|
encoder.closeElement(ELEM_OPTIONSLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the maximum number of characters the decompiler displays in a single line of output
|
||||||
|
*/
|
||||||
public int getMaxWidth() {
|
public int getMaxWidth() {
|
||||||
return maxwidth;
|
return maxwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum number of characters the decompiler displays in a single line of output
|
||||||
|
* @param maxwidth is the maximum number of characters
|
||||||
|
*/
|
||||||
public void setMaxWidth(int maxwidth) {
|
public void setMaxWidth(int maxwidth) {
|
||||||
this.maxwidth = maxwidth;
|
this.maxwidth = maxwidth;
|
||||||
}
|
}
|
||||||
|
@ -938,139 +954,296 @@ public class DecompileOptions {
|
||||||
return SEARCH_HIGHLIGHT_COLOR;
|
return SEARCH_HIGHLIGHT_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the mouse button that should be used to toggle the primary token highlight
|
||||||
|
*/
|
||||||
public int getMiddleMouseHighlightButton() {
|
public int getMiddleMouseHighlightButton() {
|
||||||
return middleMouseHighlightButton;
|
return middleMouseHighlightButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if Pre comments are included as part of decompiler output
|
||||||
|
*/
|
||||||
public boolean isPRECommentIncluded() {
|
public boolean isPRECommentIncluded() {
|
||||||
return commentPREInclude;
|
return commentPREInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether Pre comments are displayed as part of decompiler output
|
||||||
|
* @param commentPREInclude is true if Pre comments are output
|
||||||
|
*/
|
||||||
public void setPRECommentIncluded(boolean commentPREInclude) {
|
public void setPRECommentIncluded(boolean commentPREInclude) {
|
||||||
this.commentPREInclude = commentPREInclude;
|
this.commentPREInclude = commentPREInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if Plate comments are included as part of decompiler output
|
||||||
|
*/
|
||||||
public boolean isPLATECommentIncluded() {
|
public boolean isPLATECommentIncluded() {
|
||||||
return commentPLATEInclude;
|
return commentPLATEInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether Plate comments are displayed as part of decompiler output
|
||||||
|
* @param commentPLATEInclude is true if Plate comments are output
|
||||||
|
*/
|
||||||
public void setPLATECommentIncluded(boolean commentPLATEInclude) {
|
public void setPLATECommentIncluded(boolean commentPLATEInclude) {
|
||||||
this.commentPLATEInclude = commentPLATEInclude;
|
this.commentPLATEInclude = commentPLATEInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if Post comments are included as part of decompiler output
|
||||||
|
*/
|
||||||
public boolean isPOSTCommentIncluded() {
|
public boolean isPOSTCommentIncluded() {
|
||||||
return commentPOSTInclude;
|
return commentPOSTInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether Post comments are displayed as part of decompiler output
|
||||||
|
* @param commentPOSTInclude is true if Post comments are output
|
||||||
|
*/
|
||||||
public void setPOSTCommentIncluded(boolean commentPOSTInclude) {
|
public void setPOSTCommentIncluded(boolean commentPOSTInclude) {
|
||||||
this.commentPOSTInclude = commentPOSTInclude;
|
this.commentPOSTInclude = commentPOSTInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if End-of-line comments are included as part of decompiler output
|
||||||
|
*/
|
||||||
public boolean isEOLCommentIncluded() {
|
public boolean isEOLCommentIncluded() {
|
||||||
return commentEOLInclude;
|
return commentEOLInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether End-of-line comments are displayed as part of decompiler output.
|
||||||
|
* @param commentEOLInclude is true if End-of-line comments are output
|
||||||
|
*/
|
||||||
public void setEOLCommentIncluded(boolean commentEOLInclude) {
|
public void setEOLCommentIncluded(boolean commentEOLInclude) {
|
||||||
this.commentEOLInclude = commentEOLInclude;
|
this.commentEOLInclude = commentEOLInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if WARNING comments are included as part of decompiler output
|
||||||
|
*/
|
||||||
public boolean isWARNCommentIncluded() {
|
public boolean isWARNCommentIncluded() {
|
||||||
return commentWARNInclude;
|
return commentWARNInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether automatically generated WARNING comments are displayed as part of
|
||||||
|
* decompiler output.
|
||||||
|
* @param commentWARNInclude is true if WARNING comments are output
|
||||||
|
*/
|
||||||
public void setWARNCommentIncluded(boolean commentWARNInclude) {
|
public void setWARNCommentIncluded(boolean commentWARNInclude) {
|
||||||
this.commentWARNInclude = commentWARNInclude;
|
this.commentWARNInclude = commentWARNInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if function header comments are included as part of decompiler output
|
||||||
|
*/
|
||||||
public boolean isHeadCommentIncluded() {
|
public boolean isHeadCommentIncluded() {
|
||||||
return commentHeadInclude;
|
return commentHeadInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether function header comments are included as part of decompiler output.
|
||||||
|
* @param commentHeadInclude is true if header comments are output
|
||||||
|
*/
|
||||||
public void setHeadCommentIncluded(boolean commentHeadInclude) {
|
public void setHeadCommentIncluded(boolean commentHeadInclude) {
|
||||||
this.commentHeadInclude = commentHeadInclude;
|
this.commentHeadInclude = commentHeadInclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the decompiler currently eliminates unreachable code
|
||||||
|
*/
|
||||||
public boolean isEliminateUnreachable() {
|
public boolean isEliminateUnreachable() {
|
||||||
return eliminateUnreachable;
|
return eliminateUnreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether the decompiler should eliminate unreachable code as part of its analysis.
|
||||||
|
* @param eliminateUnreachable is true if unreachable code is eliminated
|
||||||
|
*/
|
||||||
public void setEliminateUnreachable(boolean eliminateUnreachable) {
|
public void setEliminateUnreachable(boolean eliminateUnreachable) {
|
||||||
this.eliminateUnreachable = eliminateUnreachable;
|
this.eliminateUnreachable = eliminateUnreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the decompiler currently applies transformation rules that identify and
|
||||||
|
* simplify double precision arithmetic operations, true is returned.
|
||||||
|
* @return true if the decompiler applies double precision rules
|
||||||
|
*/
|
||||||
public boolean isSimplifyDoublePrecision() {
|
public boolean isSimplifyDoublePrecision() {
|
||||||
return simplifyDoublePrecision;
|
return simplifyDoublePrecision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether the decompiler should apply transformation rules that identify and
|
||||||
|
* simplify double precision arithmetic operations.
|
||||||
|
* @param simplifyDoublePrecision is true if double precision rules should be applied
|
||||||
|
*/
|
||||||
public void setSimplifyDoublePrecision(boolean simplifyDoublePrecision) {
|
public void setSimplifyDoublePrecision(boolean simplifyDoublePrecision) {
|
||||||
this.simplifyDoublePrecision = simplifyDoublePrecision;
|
this.simplifyDoublePrecision = simplifyDoublePrecision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if line numbers should be displayed with decompiler output.
|
||||||
|
*/
|
||||||
public boolean isDisplayLineNumbers() {
|
public boolean isDisplayLineNumbers() {
|
||||||
return displayLineNumbers;
|
return displayLineNumbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the source programming language that decompiler output is rendered in
|
||||||
|
*/
|
||||||
public DecompilerLanguage getDisplayLanguage() {
|
public DecompilerLanguage getDisplayLanguage() {
|
||||||
return displayLanguage;
|
return displayLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the transformer being applied to data-type, function, and namespace names.
|
||||||
|
* If no transform is being applied, a pass-through object is returned.
|
||||||
|
* @return the transformer object
|
||||||
|
*/
|
||||||
|
public NameTransformer getNameTransformer() {
|
||||||
|
if (nameTransformer == null) {
|
||||||
|
nameTransformer = new IdentityNameTransformer();
|
||||||
|
}
|
||||||
|
return nameTransformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a specific transformer to be applied to all data-type, function, and namespace
|
||||||
|
* names in decompiler output. A null value indicates no transform should be applied.
|
||||||
|
* @param transformer is the transformer to apply
|
||||||
|
*/
|
||||||
|
public void setNameTransformer(NameTransformer transformer) {
|
||||||
|
nameTransformer = transformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if calling convention names are displayed as part of function signatures
|
||||||
|
*/
|
||||||
public boolean isConventionPrint() {
|
public boolean isConventionPrint() {
|
||||||
return conventionPrint;
|
return conventionPrint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether the calling convention name should be displayed as part of function signatures
|
||||||
|
* in decompiler output.
|
||||||
|
* @param conventionPrint is true if calling convention names should be displayed
|
||||||
|
*/
|
||||||
public void setConventionPrint(boolean conventionPrint) {
|
public void setConventionPrint(boolean conventionPrint) {
|
||||||
this.conventionPrint = conventionPrint;
|
this.conventionPrint = conventionPrint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if cast operations are not displayed in decompiler output
|
||||||
|
*/
|
||||||
public boolean isNoCastPrint() {
|
public boolean isNoCastPrint() {
|
||||||
return noCastPrint;
|
return noCastPrint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether decompiler output should display cast operations.
|
||||||
|
* @param noCastPrint is true if casts should NOT be displayed.
|
||||||
|
*/
|
||||||
public void setNoCastPrint(boolean noCastPrint) {
|
public void setNoCastPrint(boolean noCastPrint) {
|
||||||
this.noCastPrint = noCastPrint;
|
this.noCastPrint = noCastPrint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the source programming language that decompiler output should be rendered in.
|
||||||
|
* @param val is the source language
|
||||||
|
*/
|
||||||
public void setDisplayLanguage(DecompilerLanguage val) {
|
public void setDisplayLanguage(DecompilerLanguage val) {
|
||||||
displayLanguage = val;
|
displayLanguage = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the font that should be used to render decompiler output
|
||||||
|
*/
|
||||||
public Font getDefaultFont() {
|
public Font getDefaultFont() {
|
||||||
return Gui.getFont(DEFAULT_FONT_ID);
|
return Gui.getFont(DEFAULT_FONT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the time a decompiler process is allowed to analyze a single
|
||||||
|
* function exceeds this value, decompilation is aborted.
|
||||||
|
* @return the maximum time in seconds
|
||||||
|
*/
|
||||||
public int getDefaultTimeout() {
|
public int getDefaultTimeout() {
|
||||||
return decompileTimeoutSeconds;
|
return decompileTimeoutSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum time (in seconds) a decompiler process is allowed to analyze a single
|
||||||
|
* function. If it is exceeded, decompilation is aborted.
|
||||||
|
* @param timeout is the maximum time in seconds
|
||||||
|
*/
|
||||||
public void setDefaultTimeout(int timeout) {
|
public void setDefaultTimeout(int timeout) {
|
||||||
decompileTimeoutSeconds = timeout;
|
decompileTimeoutSeconds = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the size (in megabytes) of the payload returned by the decompiler
|
||||||
|
* process exceeds this value for a single function, decompilation is
|
||||||
|
* aborted.
|
||||||
|
* @return the maximum number of megabytes in a function payload
|
||||||
|
*/
|
||||||
public int getMaxPayloadMBytes() {
|
public int getMaxPayloadMBytes() {
|
||||||
return payloadLimitMBytes;
|
return payloadLimitMBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum size (in megabytes) of the payload that can be returned by the decompiler
|
||||||
|
* process when analyzing a single function. If this size is exceeded, decompilation is
|
||||||
|
* aborted.
|
||||||
|
* @param mbytes is the maximum number of megabytes in a function payload
|
||||||
|
*/
|
||||||
public void setMaxPayloadMBytes(int mbytes) {
|
public void setMaxPayloadMBytes(int mbytes) {
|
||||||
payloadLimitMBytes = mbytes;
|
payloadLimitMBytes = mbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the number of assembly instructions in a function exceeds this value, the function
|
||||||
|
* is not decompiled.
|
||||||
|
* @return the maximum number of instructions
|
||||||
|
*/
|
||||||
public int getMaxInstructions() {
|
public int getMaxInstructions() {
|
||||||
return maxIntructionsPer;
|
return maxIntructionsPer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum number of assembly instructions in a function to decompile.
|
||||||
|
* If the number exceeds this, the function is not decompiled.
|
||||||
|
* @param num is the number of instructions
|
||||||
|
*/
|
||||||
public void setMaxInstructions(int num) {
|
public void setMaxInstructions(int num) {
|
||||||
maxIntructionsPer = num;
|
maxIntructionsPer = num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the style in which comments are printed in decompiler output
|
||||||
|
*/
|
||||||
public CommentStyleEnum getCommentStyle() {
|
public CommentStyleEnum getCommentStyle() {
|
||||||
return commentStyle;
|
return commentStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the style in which comments are printed as part of decompiler output
|
||||||
|
* @param commentStyle is the new style to set
|
||||||
|
*/
|
||||||
public void setCommentStyle(CommentStyleEnum commentStyle) {
|
public void setCommentStyle(CommentStyleEnum commentStyle) {
|
||||||
this.commentStyle = commentStyle;
|
this.commentStyle = commentStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the maximum number of decompiled function results that should be cached
|
||||||
|
* by the controller of the decompiler process.
|
||||||
|
* @return the number of functions to cache
|
||||||
|
*/
|
||||||
public int getCacheSize() {
|
public int getCacheSize() {
|
||||||
return cachedResultsSize;
|
return cachedResultsSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
|
import ghidra.program.model.symbol.IllegalCharCppTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for getting at the various structures returned
|
* Class for getting at the various structures returned
|
||||||
|
@ -197,8 +198,9 @@ public class DecompileResults {
|
||||||
if (docroot == null) {
|
if (docroot == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
PrettyPrinter printer = new PrettyPrinter(function, docroot);
|
PrettyPrinter printer =
|
||||||
return printer.print(true);
|
new PrettyPrinter(function, docroot, new IllegalCharCppTransformer());
|
||||||
|
return printer.print();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decodeStream(Decoder decoder) {
|
private void decodeStream(Decoder decoder) {
|
||||||
|
|
|
@ -20,13 +20,16 @@ import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.symbol.IdentityNameTransformer;
|
||||||
|
import ghidra.program.model.symbol.NameTransformer;
|
||||||
import ghidra.util.StringUtilities;
|
import ghidra.util.StringUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to convert a C language
|
* This class is used to convert a C/C++ language
|
||||||
* token group into readable C code.
|
* token group into readable C/C++ code.
|
||||||
*/
|
*/
|
||||||
public class PrettyPrinter {
|
public class PrettyPrinter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The indent string to use when printing.
|
* The indent string to use when printing.
|
||||||
*/
|
*/
|
||||||
|
@ -34,29 +37,35 @@ public class PrettyPrinter {
|
||||||
|
|
||||||
private Function function;
|
private Function function;
|
||||||
private ClangTokenGroup tokgroup;
|
private ClangTokenGroup tokgroup;
|
||||||
private ArrayList<ClangLine> lines = new ArrayList<ClangLine>();
|
private ArrayList<ClangLine> lines = new ArrayList<>();
|
||||||
|
private NameTransformer transformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new pretty printer using the specified C language token group.
|
* Constructs a new pretty printer using the specified C language token group.
|
||||||
|
* The printer takes a NameTransformer that will be applied to symbols, which can replace
|
||||||
|
* illegal characters in the symbol name for instance. A null indicates no transform is applied.
|
||||||
|
* @param function is the function to be printed
|
||||||
* @param tokgroup the C language token group
|
* @param tokgroup the C language token group
|
||||||
|
* @param transformer the transformer to apply to symbols
|
||||||
*/
|
*/
|
||||||
public PrettyPrinter(Function function, ClangTokenGroup tokgroup) {
|
public PrettyPrinter(Function function, ClangTokenGroup tokgroup, NameTransformer transformer) {
|
||||||
this.function = function;
|
this.function = function;
|
||||||
this.tokgroup = tokgroup;
|
this.tokgroup = tokgroup;
|
||||||
|
this.transformer = (transformer != null) ? transformer : new IdentityNameTransformer();
|
||||||
flattenLines();
|
flattenLines();
|
||||||
padEmptyLines();
|
padEmptyLines();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void padEmptyLines() {
|
private void padEmptyLines() {
|
||||||
for (ClangLine line : lines) {
|
for (ClangLine line : lines) {
|
||||||
ArrayList<ClangToken> tokenList = line.getAllTokens();
|
ArrayList<ClangToken> tokenList = line.getAllTokens();
|
||||||
if (tokenList.size() == 0) {
|
if (tokenList.size() == 0) {
|
||||||
ClangToken spacer = ClangToken.buildSpacer(null, line.getIndent(), INDENT_STRING);
|
ClangToken spacer = ClangToken.buildSpacer(null, line.getIndent(), INDENT_STRING);
|
||||||
spacer.setLineParent( line );
|
spacer.setLineParent(line);
|
||||||
tokenList.add(0, spacer);
|
tokenList.add(0, spacer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Function getFunction() {
|
public Function getFunction() {
|
||||||
return function;
|
return function;
|
||||||
|
@ -74,11 +83,9 @@ public class PrettyPrinter {
|
||||||
/**
|
/**
|
||||||
* Prints the C language token group
|
* Prints the C language token group
|
||||||
* into a string of C code.
|
* into a string of C code.
|
||||||
* @param removeInvalidChars true if invalid character should be
|
|
||||||
* removed from functions and labels.
|
|
||||||
* @return a string of readable C code
|
* @return a string of readable C code
|
||||||
*/
|
*/
|
||||||
public DecompiledFunction print(boolean removeInvalidChars) {
|
public DecompiledFunction print() {
|
||||||
StringBuffer buff = new StringBuffer();
|
StringBuffer buff = new StringBuffer();
|
||||||
|
|
||||||
for (ClangLine line : lines) {
|
for (ClangLine line : lines) {
|
||||||
|
@ -87,30 +94,19 @@ public class PrettyPrinter {
|
||||||
|
|
||||||
for (ClangToken token : tokens) {
|
for (ClangToken token : tokens) {
|
||||||
boolean isToken2Clean = token instanceof ClangFuncNameToken ||
|
boolean isToken2Clean = token instanceof ClangFuncNameToken ||
|
||||||
token instanceof ClangVariableToken ||
|
token instanceof ClangVariableToken || token instanceof ClangTypeToken ||
|
||||||
token instanceof ClangTypeToken ||
|
token instanceof ClangFieldToken || token instanceof ClangLabelToken;
|
||||||
token instanceof ClangFieldToken ||
|
|
||||||
token instanceof ClangLabelToken;
|
|
||||||
|
|
||||||
//do not clean constant variable tokens
|
//do not clean constant variable tokens
|
||||||
if (isToken2Clean && token.getSyntaxType() == ClangToken.CONST_COLOR) {
|
if (isToken2Clean && token.getSyntaxType() == ClangToken.CONST_COLOR) {
|
||||||
isToken2Clean = false;
|
isToken2Clean = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (removeInvalidChars && isToken2Clean) {
|
String tokenText = token.getText();
|
||||||
String tokenText = token.getText();
|
if (isToken2Clean) {
|
||||||
for (int i = 0 ; i < tokenText.length() ; ++i) {
|
tokenText = transformer.simplify(tokenText);
|
||||||
if (StringUtilities.isValidCLanguageChar(tokenText.charAt(i))) {
|
|
||||||
buff.append(tokenText.charAt(i));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buff.append('_');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buff.append(token.getText());
|
|
||||||
}
|
}
|
||||||
|
buff.append(tokenText);
|
||||||
}
|
}
|
||||||
buff.append(StringUtilities.LINE_SEPARATOR);
|
buff.append(StringUtilities.LINE_SEPARATOR);
|
||||||
}
|
}
|
||||||
|
@ -119,10 +115,10 @@ public class PrettyPrinter {
|
||||||
|
|
||||||
private String findSignature() {
|
private String findSignature() {
|
||||||
int nChildren = tokgroup.numChildren();
|
int nChildren = tokgroup.numChildren();
|
||||||
for (int i = 0 ; i < nChildren ; ++i) {
|
for (int i = 0; i < nChildren; ++i) {
|
||||||
ClangNode node = tokgroup.Child(i);
|
ClangNode node = tokgroup.Child(i);
|
||||||
if (node instanceof ClangFuncProto) {
|
if (node instanceof ClangFuncProto) {
|
||||||
return node.toString()+";";
|
return node.toString() + ";";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -231,7 +231,7 @@ public class ClangLayoutController implements LayoutModel, LayoutModelListener {
|
||||||
|
|
||||||
// Assume docroot has been built.
|
// Assume docroot has been built.
|
||||||
|
|
||||||
PrettyPrinter printer = new PrettyPrinter(function, docroot);
|
PrettyPrinter printer = new PrettyPrinter(function, docroot, null);
|
||||||
lines = printer.getLines();
|
lines = printer.getLines();
|
||||||
|
|
||||||
int lineCount = lines.size();
|
int lineCount = lines.size();
|
||||||
|
|
|
@ -28,6 +28,7 @@ import docking.widgets.fieldpanel.FieldPanel;
|
||||||
import docking.widgets.fieldpanel.internal.FieldPanelCoordinator;
|
import docking.widgets.fieldpanel.internal.FieldPanelCoordinator;
|
||||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||||
import docking.widgets.label.GDHtmlLabel;
|
import docking.widgets.label.GDHtmlLabel;
|
||||||
|
import ghidra.GhidraOptions;
|
||||||
import ghidra.app.decompiler.DecompileOptions;
|
import ghidra.app.decompiler.DecompileOptions;
|
||||||
import ghidra.app.util.viewer.listingpanel.ProgramLocationListener;
|
import ghidra.app.util.viewer.listingpanel.ProgramLocationListener;
|
||||||
import ghidra.app.util.viewer.util.CodeComparisonPanel;
|
import ghidra.app.util.viewer.util.CodeComparisonPanel;
|
||||||
|
@ -88,10 +89,11 @@ public abstract class DecompilerCodeComparisonPanel<T extends DualDecompilerFiel
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
|
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||||
ToolOptions options = tool.getOptions(OPTIONS_TITLE);
|
ToolOptions options = tool.getOptions(OPTIONS_TITLE);
|
||||||
leftDecompileOptions.grabFromToolAndProgram(null, options,
|
leftDecompileOptions.grabFromToolAndProgram(fieldOptions, options,
|
||||||
(functions[LEFT] != null) ? functions[LEFT].getProgram() : null);
|
(functions[LEFT] != null) ? functions[LEFT].getProgram() : null);
|
||||||
rightDecompileOptions.grabFromToolAndProgram(null, options,
|
rightDecompileOptions.grabFromToolAndProgram(fieldOptions, options,
|
||||||
(functions[RIGHT] != null) ? functions[RIGHT].getProgram() : null);
|
(functions[RIGHT] != null) ? functions[RIGHT].getProgram() : null);
|
||||||
setFieldPanelCoordinator(createFieldPanelCoordinator());
|
setFieldPanelCoordinator(createFieldPanelCoordinator());
|
||||||
setScrollingSyncState(true);
|
setScrollingSyncState(true);
|
||||||
|
@ -465,17 +467,19 @@ public abstract class DecompilerCodeComparisonPanel<T extends DualDecompilerFiel
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setPrograms(Program leftProgram, Program rightProgram) {
|
protected void setPrograms(Program leftProgram, Program rightProgram) {
|
||||||
|
ToolOptions fieldOptions =
|
||||||
|
(tool != null) ? tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS) : null;
|
||||||
ToolOptions options = (tool != null) ? tool.getOptions(OPTIONS_TITLE) : null;
|
ToolOptions options = (tool != null) ? tool.getOptions(OPTIONS_TITLE) : null;
|
||||||
if (leftProgram != programs[LEFT]) {
|
if (leftProgram != programs[LEFT]) {
|
||||||
programs[LEFT] = leftProgram;
|
programs[LEFT] = leftProgram;
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
leftDecompileOptions.grabFromToolAndProgram(null, options, leftProgram);
|
leftDecompileOptions.grabFromToolAndProgram(fieldOptions, options, leftProgram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rightProgram != programs[RIGHT]) {
|
if (rightProgram != programs[RIGHT]) {
|
||||||
programs[RIGHT] = rightProgram;
|
programs[RIGHT] = rightProgram;
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
rightDecompileOptions.grabFromToolAndProgram(null, options, rightProgram);
|
rightDecompileOptions.grabFromToolAndProgram(fieldOptions, options, rightProgram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,8 +176,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||||
@Override
|
@Override
|
||||||
public void componentShown() {
|
public void componentShown() {
|
||||||
if (program != null && currentLocation != null) {
|
if (program != null && currentLocation != null) {
|
||||||
|
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||||
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
||||||
decompilerOptions.grabFromToolAndProgram(plugin, opt, program);
|
decompilerOptions.grabFromToolAndProgram(fieldOptions, opt, program);
|
||||||
controller.setOptions(decompilerOptions);
|
controller.setOptions(decompilerOptions);
|
||||||
controller.display(program, currentLocation, null);
|
controller.display(program, currentLocation, null);
|
||||||
}
|
}
|
||||||
|
@ -320,8 +321,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doRefresh() {
|
private void doRefresh() {
|
||||||
|
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||||
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
||||||
decompilerOptions.grabFromToolAndProgram(plugin, opt, program);
|
decompilerOptions.grabFromToolAndProgram(fieldOptions, opt, program);
|
||||||
controller.setOptions(decompilerOptions);
|
controller.setOptions(decompilerOptions);
|
||||||
if (currentLocation != null) {
|
if (currentLocation != null) {
|
||||||
controller.refreshDisplay(program, currentLocation, null);
|
controller.refreshDisplay(program, currentLocation, null);
|
||||||
|
@ -402,8 +404,9 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||||
currentSelection = null;
|
currentSelection = null;
|
||||||
if (program != null) {
|
if (program != null) {
|
||||||
program.addListener(this);
|
program.addListener(this);
|
||||||
|
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||||
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
||||||
decompilerOptions.grabFromToolAndProgram(plugin, opt, program);
|
decompilerOptions.grabFromToolAndProgram(fieldOptions, opt, program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,6 +723,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeDecompilerOptions() {
|
private void initializeDecompilerOptions() {
|
||||||
|
ToolOptions fieldOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||||
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
||||||
HelpLocation helpLocation = new HelpLocation(HelpTopics.DECOMPILER, "GeneralOptions");
|
HelpLocation helpLocation = new HelpLocation(HelpTopics.DECOMPILER, "GeneralOptions");
|
||||||
opt.setOptionsHelpLocation(helpLocation);
|
opt.setOptionsHelpLocation(helpLocation);
|
||||||
|
@ -727,7 +731,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||||
.setOptionsHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "AnalysisOptions"));
|
.setOptionsHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "AnalysisOptions"));
|
||||||
opt.getOptions("Display")
|
opt.getOptions("Display")
|
||||||
.setOptionsHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "DisplayOptions"));
|
.setOptionsHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "DisplayOptions"));
|
||||||
decompilerOptions.registerOptions(plugin, opt, program);
|
decompilerOptions.registerOptions(fieldOptions, opt, program);
|
||||||
|
|
||||||
opt.addOptionsChangeListener(this);
|
opt.addOptionsChangeListener(this);
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import ghidra.app.decompiler.component.DecompilerPanel;
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.framework.preferences.Preferences;
|
import ghidra.framework.preferences.Preferences;
|
||||||
|
import ghidra.program.model.symbol.IllegalCharCppTransformer;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.filechooser.ExtensionFileFilter;
|
import ghidra.util.filechooser.ExtensionFileFilter;
|
||||||
|
@ -111,8 +112,9 @@ public class ExportToCAction extends AbstractDecompilerAction {
|
||||||
try {
|
try {
|
||||||
PrintWriter writer = new PrintWriter(new FileOutputStream(file));
|
PrintWriter writer = new PrintWriter(new FileOutputStream(file));
|
||||||
ClangTokenGroup grp = context.getCCodeModel();
|
ClangTokenGroup grp = context.getCCodeModel();
|
||||||
PrettyPrinter printer = new PrettyPrinter(context.getFunction(), grp);
|
PrettyPrinter printer =
|
||||||
DecompiledFunction decompFunc = printer.print(true);
|
new PrettyPrinter(context.getFunction(), grp, new IllegalCharCppTransformer());
|
||||||
|
DecompiledFunction decompFunc = printer.print();
|
||||||
writer.write(decompFunc.getC());
|
writer.write(decompFunc.getC());
|
||||||
writer.close();
|
writer.close();
|
||||||
context.setStatusMessage(
|
context.setStatusMessage(
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import generic.cache.CachingPool;
|
import generic.cache.CachingPool;
|
||||||
import generic.cache.CountingBasicFactory;
|
import generic.cache.CountingBasicFactory;
|
||||||
import generic.concurrent.QCallback;
|
import generic.concurrent.QCallback;
|
||||||
|
import ghidra.GhidraOptions;
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.decompiler.DecompileOptions.CommentStyleEnum;
|
import ghidra.app.decompiler.DecompileOptions.CommentStyleEnum;
|
||||||
import ghidra.app.decompiler.parallel.ChunkingParallelDecompiler;
|
import ghidra.app.decompiler.parallel.ChunkingParallelDecompiler;
|
||||||
|
@ -67,15 +68,13 @@ public class CppExporter extends Exporter {
|
||||||
super("C/C++", "c", new HelpLocation("ExporterPlugin", "c_cpp"));
|
super("C/C++", "c", new HelpLocation("ExporterPlugin", "c_cpp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CppExporter(DecompileOptions options) {
|
public CppExporter(DecompileOptions options, boolean createHeader, boolean createFile,
|
||||||
|
boolean emitTypes, boolean excludeTags, String tags) {
|
||||||
this();
|
this();
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.userSuppliedOptions = true;
|
if (options != null) {
|
||||||
}
|
userSuppliedOptions = true;
|
||||||
|
}
|
||||||
public CppExporter(boolean createHeader, boolean createFile, boolean emitTypes,
|
|
||||||
boolean excludeTags, String tags) {
|
|
||||||
this();
|
|
||||||
isCreateHeaderFile = createHeader;
|
isCreateHeaderFile = createHeader;
|
||||||
isCreateCFile = createFile;
|
isCreateCFile = createFile;
|
||||||
emitDataTypeDefinitions = emitTypes;
|
emitDataTypeDefinitions = emitTypes;
|
||||||
|
@ -248,8 +247,10 @@ public class CppExporter extends Exporter {
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
OptionsService service = provider.getService(OptionsService.class);
|
OptionsService service = provider.getService(OptionsService.class);
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
|
ToolOptions fieldOptions =
|
||||||
|
service.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
|
||||||
ToolOptions opt = service.getOptions("Decompiler");
|
ToolOptions opt = service.getOptions("Decompiler");
|
||||||
options.grabFromToolAndProgram(null, opt, program);
|
options.grabFromToolAndProgram(fieldOptions, opt, program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -430,7 +430,12 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
if (id != 0) {
|
if (id != 0) {
|
||||||
encoder.writeUnsignedInteger(ATTRIB_ID, id);
|
encoder.writeUnsignedInteger(ATTRIB_ID, id);
|
||||||
}
|
}
|
||||||
encoder.writeString(ATTRIB_NAME, func.getName());
|
String funcName = func.getName();
|
||||||
|
encoder.writeString(ATTRIB_NAME, funcName);
|
||||||
|
String altName = getDataTypeManager().getNameTransformer().simplify(funcName);
|
||||||
|
if (!altName.equals(funcName)) {
|
||||||
|
encoder.writeString(ATTRIB_LABEL, altName);
|
||||||
|
}
|
||||||
encoder.writeSignedInteger(ATTRIB_SIZE, size);
|
encoder.writeSignedInteger(ATTRIB_SIZE, size);
|
||||||
if (func.isInline()) {
|
if (func.isInline()) {
|
||||||
encoder.writeBool(ATTRIB_INLINE, true);
|
encoder.writeBool(ATTRIB_INLINE, true);
|
||||||
|
@ -444,7 +449,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
else {
|
else {
|
||||||
AddressXML.encode(encoder, entryPoint); // Address is forced on XML
|
AddressXML.encode(encoder, entryPoint); // Address is forced on XML
|
||||||
}
|
}
|
||||||
localSymbols.encodeLocalDb(encoder, namespace);
|
localSymbols.encodeLocalDb(encoder, namespace, getDataTypeManager().getNameTransformer());
|
||||||
proto.encodePrototype(encoder, getDataTypeManager());
|
proto.encodePrototype(encoder, getDataTypeManager());
|
||||||
if ((jumpTables != null) && (jumpTables.size() > 0)) {
|
if ((jumpTables != null) && (jumpTables.size() > 0)) {
|
||||||
encoder.openElement(ELEM_JUMPTABLELIST);
|
encoder.openElement(ELEM_JUMPTABLELIST);
|
||||||
|
@ -575,9 +580,11 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
* from the root (global) namespace up to the given namespace
|
* from the root (global) namespace up to the given namespace
|
||||||
* @param encoder is the stream encoder
|
* @param encoder is the stream encoder
|
||||||
* @param namespace is the namespace being described
|
* @param namespace is the namespace being described
|
||||||
|
* @param transformer is used to computer the displayed version of each namespace
|
||||||
* @throws IOException for errors in the underlying stream
|
* @throws IOException for errors in the underlying stream
|
||||||
*/
|
*/
|
||||||
static public void encodeNamespace(Encoder encoder, Namespace namespace) throws IOException {
|
static public void encodeNamespace(Encoder encoder, Namespace namespace,
|
||||||
|
NameTransformer transformer) throws IOException {
|
||||||
encoder.openElement(ELEM_PARENT);
|
encoder.openElement(ELEM_PARENT);
|
||||||
if (namespace != null) {
|
if (namespace != null) {
|
||||||
ArrayList<Namespace> arr = new ArrayList<>();
|
ArrayList<Namespace> arr = new ArrayList<>();
|
||||||
|
@ -595,7 +602,12 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
Namespace curScope = arr.get(i);
|
Namespace curScope = arr.get(i);
|
||||||
encoder.openElement(ELEM_VAL);
|
encoder.openElement(ELEM_VAL);
|
||||||
encoder.writeUnsignedInteger(ATTRIB_ID, curScope.getID());
|
encoder.writeUnsignedInteger(ATTRIB_ID, curScope.getID());
|
||||||
encoder.writeString(ATTRIB_CONTENT, curScope.getName());
|
String nm = curScope.getName();
|
||||||
|
String altName = transformer.simplify(nm);
|
||||||
|
if (!nm.equals(altName)) {
|
||||||
|
encoder.writeString(ATTRIB_LABEL, altName);
|
||||||
|
}
|
||||||
|
encoder.writeString(ATTRIB_CONTENT, nm);
|
||||||
encoder.closeElement(ELEM_VAL);
|
encoder.closeElement(ELEM_VAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@ public class HighFunctionShellSymbol extends HighSymbol {
|
||||||
encoder.openElement(ELEM_FUNCTION);
|
encoder.openElement(ELEM_FUNCTION);
|
||||||
encoder.writeUnsignedInteger(ATTRIB_ID, getId());
|
encoder.writeUnsignedInteger(ATTRIB_ID, getId());
|
||||||
encoder.writeString(ATTRIB_NAME, name);
|
encoder.writeString(ATTRIB_NAME, name);
|
||||||
|
String altName = dtmanage.getNameTransformer().simplify(name);
|
||||||
|
if (!name.equals(altName)) {
|
||||||
|
encoder.writeString(ATTRIB_LABEL, altName);
|
||||||
|
}
|
||||||
encoder.writeSignedInteger(ATTRIB_SIZE, 1);
|
encoder.writeSignedInteger(ATTRIB_SIZE, 1);
|
||||||
AddressXML.encode(encoder, getStorage().getMinAddress());
|
AddressXML.encode(encoder, getStorage().getMinAddress());
|
||||||
encoder.closeElement(ELEM_FUNCTION);
|
encoder.closeElement(ELEM_FUNCTION);
|
||||||
|
|
|
@ -330,14 +330,21 @@ public class LocalSymbolMap {
|
||||||
* Encode all the variables in this local variable map to the stream
|
* Encode all the variables in this local variable map to the stream
|
||||||
* @param encoder is the stream encoder
|
* @param encoder is the stream encoder
|
||||||
* @param namespace if the namespace of the function
|
* @param namespace if the namespace of the function
|
||||||
|
* @param transformer is used to compute a simplified version of the namespace name
|
||||||
* @throws IOException for errors in the underlying stream
|
* @throws IOException for errors in the underlying stream
|
||||||
*/
|
*/
|
||||||
public void encodeLocalDb(Encoder encoder, Namespace namespace) throws IOException {
|
public void encodeLocalDb(Encoder encoder, Namespace namespace, NameTransformer transformer)
|
||||||
|
throws IOException {
|
||||||
encoder.openElement(ELEM_LOCALDB);
|
encoder.openElement(ELEM_LOCALDB);
|
||||||
encoder.writeBool(ATTRIB_LOCK, false);
|
encoder.writeBool(ATTRIB_LOCK, false);
|
||||||
encoder.writeSpace(ATTRIB_MAIN, localSpace);
|
encoder.writeSpace(ATTRIB_MAIN, localSpace);
|
||||||
encoder.openElement(ELEM_SCOPE);
|
encoder.openElement(ELEM_SCOPE);
|
||||||
encoder.writeString(ATTRIB_NAME, func.getFunction().getName());
|
String nm = func.getFunction().getName();
|
||||||
|
encoder.writeString(ATTRIB_NAME, nm);
|
||||||
|
String altName = transformer.simplify(nm);
|
||||||
|
if (!nm.equals(altName)) {
|
||||||
|
encoder.writeString(ATTRIB_LABEL, altName);
|
||||||
|
}
|
||||||
encoder.openElement(ELEM_PARENT);
|
encoder.openElement(ELEM_PARENT);
|
||||||
long parentid = Namespace.GLOBAL_NAMESPACE_ID;
|
long parentid = Namespace.GLOBAL_NAMESPACE_ID;
|
||||||
if (!HighFunction.collapseToGlobal(namespace)) {
|
if (!HighFunction.collapseToGlobal(namespace)) {
|
||||||
|
@ -345,7 +352,7 @@ public class LocalSymbolMap {
|
||||||
}
|
}
|
||||||
encoder.writeUnsignedInteger(ATTRIB_ID, parentid);
|
encoder.writeUnsignedInteger(ATTRIB_ID, parentid);
|
||||||
encoder.closeElement(ELEM_PARENT);
|
encoder.closeElement(ELEM_PARENT);
|
||||||
encoder.openElement(ELEM_RANGELIST); // Emptry address range
|
encoder.openElement(ELEM_RANGELIST); // Empty address range
|
||||||
encoder.closeElement(ELEM_RANGELIST);
|
encoder.closeElement(ELEM_RANGELIST);
|
||||||
encoder.openElement(ELEM_SYMBOLLIST);
|
encoder.openElement(ELEM_SYMBOLLIST);
|
||||||
Iterator<HighSymbol> iter = symbolMap.values().iterator();
|
Iterator<HighSymbol> iter = symbolMap.values().iterator();
|
||||||
|
|
|
@ -31,6 +31,7 @@ import ghidra.program.model.data.Enum;
|
||||||
import ghidra.program.model.lang.CompilerSpec;
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.lang.DecompilerLanguage;
|
import ghidra.program.model.lang.DecompilerLanguage;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.symbol.NameTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -98,6 +99,7 @@ public class PcodeDataTypeManager {
|
||||||
private DataTypeManager progDataTypes; // DataTypes from a particular program
|
private DataTypeManager progDataTypes; // DataTypes from a particular program
|
||||||
private DataTypeManager builtInDataTypes = BuiltInDataTypeManager.getDataTypeManager();
|
private DataTypeManager builtInDataTypes = BuiltInDataTypeManager.getDataTypeManager();
|
||||||
private DataOrganization dataOrganization;
|
private DataOrganization dataOrganization;
|
||||||
|
private NameTransformer nameTransformer;
|
||||||
private DecompilerLanguage displayLanguage;
|
private DecompilerLanguage displayLanguage;
|
||||||
private boolean voidInputIsVarargs; // true if we should consider void parameter lists as varargs
|
private boolean voidInputIsVarargs; // true if we should consider void parameter lists as varargs
|
||||||
// Some C header conventions use an empty prototype to mean a
|
// Some C header conventions use an empty prototype to mean a
|
||||||
|
@ -107,11 +109,12 @@ public class PcodeDataTypeManager {
|
||||||
private VoidDataType voidDt;
|
private VoidDataType voidDt;
|
||||||
private int pointerWordSize; // Wordsize to assign to all pointer datatypes
|
private int pointerWordSize; // Wordsize to assign to all pointer datatypes
|
||||||
|
|
||||||
public PcodeDataTypeManager(Program prog) {
|
public PcodeDataTypeManager(Program prog, NameTransformer simplifier) {
|
||||||
|
|
||||||
program = prog;
|
program = prog;
|
||||||
progDataTypes = prog.getDataTypeManager();
|
progDataTypes = prog.getDataTypeManager();
|
||||||
dataOrganization = progDataTypes.getDataOrganization();
|
dataOrganization = progDataTypes.getDataOrganization();
|
||||||
|
nameTransformer = simplifier;
|
||||||
voidInputIsVarargs = true; // By default, do not lock-in void parameter lists
|
voidInputIsVarargs = true; // By default, do not lock-in void parameter lists
|
||||||
displayLanguage = prog.getCompilerSpec().getDecompilerOutputLanguage();
|
displayLanguage = prog.getCompilerSpec().getDecompilerOutputLanguage();
|
||||||
if (displayLanguage != DecompilerLanguage.C_LANGUAGE) {
|
if (displayLanguage != DecompilerLanguage.C_LANGUAGE) {
|
||||||
|
@ -126,6 +129,14 @@ public class PcodeDataTypeManager {
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NameTransformer getNameTransformer() {
|
||||||
|
return nameTransformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNameTransformer(NameTransformer newTransformer) {
|
||||||
|
nameTransformer = newTransformer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a base/built-in data-type with the given name and/or id. If an id is provided and
|
* Find a base/built-in data-type with the given name and/or id. If an id is provided and
|
||||||
* a corresponding data-type exists, this data-type is returned. Otherwise the first
|
* a corresponding data-type exists, this data-type is returned. Otherwise the first
|
||||||
|
@ -954,7 +965,12 @@ public class PcodeDataTypeManager {
|
||||||
((BuiltIn) type).getDecompilerDisplayName(displayLanguage));
|
((BuiltIn) type).getDecompilerDisplayName(displayLanguage));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
String name = type.getName();
|
||||||
|
String displayName = nameTransformer.simplify(name);
|
||||||
encoder.writeString(ATTRIB_NAME, type.getName());
|
encoder.writeString(ATTRIB_NAME, type.getName());
|
||||||
|
if (!name.equals(displayName)) {
|
||||||
|
encoder.writeString(ATTRIB_LABEL, displayName);
|
||||||
|
}
|
||||||
long id = progDataTypes.getID(type);
|
long id = progDataTypes.getID(type);
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
encoder.writeUnsignedInteger(ATTRIB_ID, id);
|
encoder.writeUnsignedInteger(ATTRIB_ID, id);
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* ###
|
||||||
|
* 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.program.model.symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A transformer that never alters its input
|
||||||
|
*/
|
||||||
|
public class IdentityNameTransformer implements NameTransformer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String simplify(String input) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/* ###
|
||||||
|
* 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.program.model.symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace illegal characters in the given name with '_'. The transformer treats the name as a
|
||||||
|
* C++ symbol. Letters and digits are generally legal. '~' is allowed at the start of the symbol.
|
||||||
|
* Template parameters, surrounded by '<' and '>', allow additional special characters. Certain
|
||||||
|
* special characters are allowed after the keyword "operator".
|
||||||
|
*/
|
||||||
|
public class IllegalCharCppTransformer implements NameTransformer {
|
||||||
|
|
||||||
|
private static int[] legalChars = null;
|
||||||
|
private static final int AFTER_FIRST_CHAR = 1; // Legal after the first character
|
||||||
|
private static final int TEMPLATE = 2; // Legal as part of template parameters
|
||||||
|
private static final int OPERATOR = 4; // Legal after the "operator" keyword
|
||||||
|
private static final int FIRST_CHAR = 8; // Legal as the first character
|
||||||
|
|
||||||
|
public IllegalCharCppTransformer() {
|
||||||
|
if (legalChars == null) {
|
||||||
|
legalChars = new int[128];
|
||||||
|
for (int i = 0; i < legalChars.length; ++i) {
|
||||||
|
legalChars[i] = 0;
|
||||||
|
}
|
||||||
|
legalChars['_'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR | FIRST_CHAR;
|
||||||
|
legalChars['0'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['1'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['2'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['3'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['4'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['5'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['6'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['7'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['8'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['9'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||||
|
legalChars['*'] = TEMPLATE | OPERATOR;
|
||||||
|
legalChars[':'] = TEMPLATE;
|
||||||
|
legalChars['('] = TEMPLATE | OPERATOR;
|
||||||
|
legalChars[')'] = TEMPLATE | OPERATOR;
|
||||||
|
legalChars['['] = TEMPLATE | OPERATOR;
|
||||||
|
legalChars[']'] = TEMPLATE | OPERATOR;
|
||||||
|
legalChars[','] = TEMPLATE;
|
||||||
|
legalChars['&'] = TEMPLATE | OPERATOR;
|
||||||
|
legalChars['+'] = OPERATOR;
|
||||||
|
legalChars['-'] = OPERATOR;
|
||||||
|
legalChars['|'] = OPERATOR;
|
||||||
|
legalChars['='] = OPERATOR;
|
||||||
|
legalChars['!'] = OPERATOR;
|
||||||
|
legalChars['/'] = OPERATOR;
|
||||||
|
legalChars['%'] = OPERATOR;
|
||||||
|
legalChars['^'] = OPERATOR;
|
||||||
|
legalChars['~'] = TEMPLATE | OPERATOR | FIRST_CHAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String simplify(String input) {
|
||||||
|
int templateDepth = 0;
|
||||||
|
char[] transform = null;
|
||||||
|
for (int i = 0; i < input.length(); ++i) {
|
||||||
|
char c = input.charAt(i);
|
||||||
|
if (Character.isLetter(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (c == '<') {
|
||||||
|
templateDepth += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (c == '>') {
|
||||||
|
templateDepth -= 1;
|
||||||
|
if (templateDepth < 0) {
|
||||||
|
templateDepth = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (c < 128) {
|
||||||
|
int val = legalChars[c];
|
||||||
|
if (val != 0) {
|
||||||
|
if (((val & AFTER_FIRST_CHAR) != 0) && i > 0) {
|
||||||
|
continue; // Legal after first character
|
||||||
|
}
|
||||||
|
if (((val & FIRST_CHAR) != 0) && i == 0) {
|
||||||
|
continue; // Legal as first character
|
||||||
|
}
|
||||||
|
if (((val & TEMPLATE) != 0) && templateDepth > 0) {
|
||||||
|
continue; // Legal as template parameter
|
||||||
|
}
|
||||||
|
if (((val & OPERATOR) != 0) && i >= 8 && i <= 10) {
|
||||||
|
if (input.startsWith("operator")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we reach here, the character is deemed illegal
|
||||||
|
if (transform == null) {
|
||||||
|
transform = new char[input.length()];
|
||||||
|
input.getChars(0, input.length(), transform, 0);
|
||||||
|
}
|
||||||
|
transform[i] = '_';
|
||||||
|
}
|
||||||
|
if (transform == null) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
return new String(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* ###
|
||||||
|
* 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.program.model.symbol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to transform (shorten, simplify) names of data-types, functions, and name spaces
|
||||||
|
* for display.
|
||||||
|
*/
|
||||||
|
public interface NameTransformer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a transformed version of the given input. If no change is made, the original
|
||||||
|
* String object is returned.
|
||||||
|
* @param input is the name to transform
|
||||||
|
* @return the transformed version
|
||||||
|
*/
|
||||||
|
public String simplify(String input);
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* ###
|
||||||
|
* 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.program.model.symbol;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import generic.test.AbstractGenericTest;
|
||||||
|
|
||||||
|
public class IllegalCharCppTransformerTest extends AbstractGenericTest {
|
||||||
|
|
||||||
|
private IllegalCharCppTransformer transformer = new IllegalCharCppTransformer();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTemplateChars() {
|
||||||
|
assertEquals("foo<bar>", simplify("foo<bar>"));
|
||||||
|
assertEquals("foo<std::bar>", simplify("foo<std::bar>"));
|
||||||
|
assertEquals("map<int,char*>", simplify("map<int,char*>"));
|
||||||
|
assertEquals("pair<vec1,(*)(char[12]),const&val>",
|
||||||
|
simplify("pair<vec1,(*)(char[12]),const&val>"));
|
||||||
|
assertEquals("_basic_string<char,std::char_traits<char>>",
|
||||||
|
simplify("_basic.string<char,std::char_traits<char>>"));
|
||||||
|
assertEquals("_________baz", simplify("*()~[]&:,baz"));
|
||||||
|
assertEquals("foo12___<std::space__::vec>___bar__operator",
|
||||||
|
simplify("foo12 ??<std::space??::vec>_*~bar::operator"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOperatorChars() {
|
||||||
|
assertEquals("operator<<", simplify("operator<<"));
|
||||||
|
assertEquals("operator>>=", simplify("operator>>="));
|
||||||
|
assertEquals("operator++", simplify("operator++"));
|
||||||
|
assertEquals("operator/=", simplify("operator/="));
|
||||||
|
assertEquals("operator%", simplify("operator%"));
|
||||||
|
assertEquals("operator&&", simplify("operator&&"));
|
||||||
|
assertEquals("operator!=", simplify("operator!="));
|
||||||
|
assertEquals("operator__", simplify("operator.?"));
|
||||||
|
assertEquals("operator~", simplify("operator~"));
|
||||||
|
assertEquals("operator^", simplify("operator^"));
|
||||||
|
assertEquals("myoperator__", simplify("myoperator!="));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBadChars() {
|
||||||
|
assertEquals("~destructor_main", simplify("~destructor.main"));
|
||||||
|
assertEquals("~Vector_7", simplify("~Vector~7"));
|
||||||
|
assertEquals("_2foo", simplify("12foo"));
|
||||||
|
assertEquals("std__foo", simplify("std::foo"));
|
||||||
|
assertEquals("bar__1", simplify("bar??1"));
|
||||||
|
assertEquals("_resource_352_", simplify("[resource.352]"));
|
||||||
|
assertEquals("_val_", simplify("!val%"));
|
||||||
|
// Foreign language identifiers
|
||||||
|
assertEquals("\u041d\u0415\u0422", simplify("\u041d\u0415\u0422"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String simplify(String in) {
|
||||||
|
return transformer.simplify(in);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue