GP-2717 Symbol attached to variable declarations

This commit is contained in:
caheckman
2023-02-24 17:32:26 -05:00
parent b4de95f4f5
commit a5ba9e390c
27 changed files with 315 additions and 219 deletions
@@ -17,6 +17,9 @@ package ghidra.app.decompiler;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/**
* A line break in source code plus the indenting for the following line.
*/
public class ClangBreak extends ClangToken { public class ClangBreak extends ClangToken {
private int indent; // Number of characters of indent private int indent; // Number of characters of indent
@@ -31,6 +34,9 @@ public class ClangBreak extends ClangToken {
this.indent = indent; this.indent = indent;
} }
/**
* @return the number of indent levels following this line break
*/
public int getIndent() { public int getIndent() {
return indent; return indent;
} }
@@ -19,6 +19,9 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/**
* A token in source code representing (part of) a comment.
*/
public class ClangCommentToken extends ClangToken { public class ClangCommentToken extends ClangToken {
private Address srcaddr; // source address of the comment private Address srcaddr; // source address of the comment
@@ -21,8 +21,7 @@ import ghidra.program.model.data.DataType;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
* A C code token representing a structure field. * A source code token representing a structure field.
*
*/ */
public class ClangFieldToken extends ClangToken { public class ClangFieldToken extends ClangToken {
private DataType datatype; // Structure from which this field is a part private DataType datatype; // Structure from which this field is a part
@@ -19,10 +19,8 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
* * A source code token representing a function name.
* * It contains a link back to the p-code function object represented by the name
* A C code token representing a function name
* It contains a link back to the pcode function object represented by the name
*/ */
public class ClangFuncNameToken extends ClangToken { public class ClangFuncNameToken extends ClangToken {
private HighFunction hfunc; // Overall reference to function private HighFunction hfunc; // Overall reference to function
@@ -34,6 +32,9 @@ public class ClangFuncNameToken extends ClangToken {
op = null; op = null;
} }
/**
* @return the HighFunction object associated with this name
*/
public HighFunction getHighFunction() { public HighFunction getHighFunction() {
return hfunc; return hfunc;
} }
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,20 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jun 12, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
/** /**
* * A grouping of source code tokens representing a function prototype
*
* The C code syntax for a function prototype
*/ */
public class ClangFuncProto extends ClangTokenGroup { public class ClangFuncProto extends ClangTokenGroup {
public ClangFuncProto(ClangNode par) { super(par); } public ClangFuncProto(ClangNode par) {
super(par);
}
} }
@@ -13,19 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jul 9, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.pcode.HighFunction; import ghidra.program.model.pcode.HighFunction;
/** /**
* All the tokens making up one function in the display * A grouping of source code tokens representing an entire function
*/ */
public class ClangFunction extends ClangTokenGroup { public class ClangFunction extends ClangTokenGroup {
private final HighFunction hfunc; private final HighFunction hfunc;
@@ -40,6 +33,9 @@ public class ClangFunction extends ClangTokenGroup {
return this; return this;
} }
/**
* @return the HighFunction object represented by this source code
*/
public HighFunction getHighFunction() { public HighFunction getHighFunction() {
return hfunc; return hfunc;
} }
@@ -19,8 +19,11 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/**
* A source code token representing a control-flow label.
*/
public class ClangLabelToken extends ClangToken { public class ClangLabelToken extends ClangToken {
private Address blockaddr; // Address this is labelling private Address blockaddr; // Address this is labeling
public ClangLabelToken(ClangNode par) { public ClangLabelToken(ClangNode par) {
super(par); super(par);
@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jun 18, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,32 +13,67 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jul 7, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.address.Address;
import java.awt.Color; import java.awt.Color;
import java.util.List; import java.util.List;
import ghidra.program.model.address.Address;
/** /**
* * A collection of source code text elements, with associated attributes, grouped in
* * a tree structure.
* Generic tree interface
*/ */
public interface ClangNode { public interface ClangNode {
/**
* Get the immediate grouping (parent) containing this text element. If this is a
* complete document, null is returned.
* @return the parent grouping or null
*/
public ClangNode Parent(); public ClangNode Parent();
/**
* Get the smallest Program address associated with the code that this text represents
* @return the smallest Address
*/
public Address getMinAddress(); public Address getMinAddress();
/**
* Get the biggest Program address associated with the code that this text represents
* @return the biggest Address
*/
public Address getMaxAddress(); public Address getMaxAddress();
/**
* Set a highlighting background color for all text elements
* @param c is the color to set
*/
public void setHighlight(Color c); public void setHighlight(Color c);
public int numChildren();
/**
* Return the number of immediate groupings this text breaks up into
* @return the number of child groupings
*/
public int numChildren();
/**
* Get the i-th child grouping
* @param i is the index selecting the grouping
* @return the selected grouping
*/
public ClangNode Child(int i); public ClangNode Child(int i);
/**
* Get the text representing an entire function of which this is part.
* @return text for the whole function
*/
public ClangFunction getClangFunction(); public ClangFunction getClangFunction();
/**
* Flatten this text into a list of tokens (see ClangToken)
* @param list is the container that will contain the tokens
*/
public void flatten(List<ClangNode> list); public void flatten(List<ClangNode> list);
} }
@@ -19,11 +19,9 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
* * A token representing a source code "operation". This could be a keyword like
* * "if" or "while" but could also be an operator like '+' or '*'.
* Token representing an operation in C code text. This could be a keyword like * The token may contain an id for the p-code object representing the operation.
* "if" or "while" but could also be an operator like '+' or '*'
* The token may contain an id for the pcode object representing the operation
*/ */
public class ClangOpToken extends ClangToken { public class ClangOpToken extends ClangToken {
private PcodeOp op; private PcodeOp op;
@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jun 12, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
@@ -26,9 +20,7 @@ import ghidra.program.model.pcode.*;
import ghidra.util.Msg; import ghidra.util.Msg;
/** /**
* * A grouping of source code tokens representing the "return type" of a function,
*
* A group of C code tokens representing the return type of a function
* as at the beginning of a function prototype. * as at the beginning of a function prototype.
*/ */
public class ClangReturnType extends ClangTokenGroup { public class ClangReturnType extends ClangTokenGroup {
@@ -41,10 +33,16 @@ public class ClangReturnType extends ClangTokenGroup {
datatype = null; datatype = null;
} }
/**
* @return the data-type represented by this text
*/
public DataType getDataType() { public DataType getDataType() {
return datatype; return datatype;
} }
/**
* @return a Varnode representing the return value in the function's data-flow
*/
public Varnode getVarnode() { public Varnode getVarnode() {
return varnode; return varnode;
} }
@@ -13,21 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jun 12, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
* * A source code statement (as typically terminated by ';' in C)
* * A statement must have a p-code operation associated with it. In the case of conditional
* A C code statement. What typically appears between the ';' '{' and '}' characters.
* A statement must have a pcode operation associated with it. In the case of conditional
* flow control operations, there are usually two lines associated with the statement one * flow control operations, there are usually two lines associated with the statement one
* containing the '{' and one containing '}'. The one containing the actual conditional branch * containing the '{' and one containing '}'. The one containing the actual conditional branch
* is considered a C statement, while the other one is just considered a blank line. * is considered a C statement, while the other one is just considered a blank line.
@@ -43,6 +35,9 @@ public class ClangStatement extends ClangTokenGroup {
op = null; op = null;
} }
/**
* @return the (final) p-code operation associated with the statement.
*/
public PcodeOp getPcodeOp() { public PcodeOp getPcodeOp() {
return op; return op;
} }
@@ -13,21 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jun 12, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
* * A source code token which is not an operation, variable, function name, or type. Like '(' or ','.
* * A SyntaxToken may be or may include spacing. As a special case, the token can be part of
* A C code token which is not an operation, variable, function name, or type. Like '(' or ',' * an enclosing pair of tokens, as with '(' and ')' or '{' and '}'. In this case, the token
* A SyntaxToken may be or may include spacing * is either opening or closing and contains an id that matches it with its pair token.
*/ */
public class ClangSyntaxToken extends ClangToken { public class ClangSyntaxToken extends ClangToken {
private int open, close; private int open, close;
@@ -73,10 +67,16 @@ public class ClangSyntaxToken extends ClangToken {
super.decode(decoder, pfactory); super.decode(decoder, pfactory);
} }
/**
* @return the pair id if this is an opening token, -1 otherwise
*/
public int getOpen() { public int getOpen() {
return open; return open;
} }
/**
* @return the pair id if this is a closing token, -1 otherwise
*/
public int getClose() { public int getClose() {
return close; return close;
} }
@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jun 12, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import static ghidra.program.model.pcode.AttributeId.*; import static ghidra.program.model.pcode.AttributeId.*;
@@ -32,10 +26,8 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
* * Class representing a source code language token.
* * A token has numerous display attributes and may link to the data-flow analysis
* Class representing a C code language token
* May contain links back to pcode object
*/ */
public class ClangToken implements ClangNode { public class ClangToken implements ClangNode {
public final static int KEYWORD_COLOR = 0; // Constants must match Decompiler syntax_highlight public final static int KEYWORD_COLOR = 0; // Constants must match Decompiler syntax_highlight
@@ -85,10 +77,18 @@ public class ClangToken implements ClangNode {
return parent; return parent;
} }
/**
* Get the element representing an entire line of text that contains this element
* @return the containing ClangLine
*/
public ClangLine getLineParent() { public ClangLine getLineParent() {
return lineparent; return lineparent;
} }
/**
* Set (change) the line which this text element part of.
* @param line is the new ClangLine
*/
public void setLineParent(ClangLine line) { public void setLineParent(ClangLine line) {
lineparent = line; lineparent = line;
} }
@@ -126,38 +126,74 @@ public class ClangToken implements ClangNode {
highlight = val; highlight = val;
} }
/**
* Get the background highlight color used to render this token, or null if not highlighted
* @return the Color or null
*/
public Color getHighlight() { public Color getHighlight() {
return highlight; return highlight;
} }
/**
* Set whether or not additional "matching" highlighting is applied to this token.
* Currently this means a bounding box is drawn around the token.
* @param matchingToken is true to enable highlighting, false to disable
*/
public void setMatchingToken(boolean matchingToken) { public void setMatchingToken(boolean matchingToken) {
this.matchingToken = matchingToken; this.matchingToken = matchingToken;
} }
/**
* @return true if this token should be displayed with "matching" highlighting
*/
public boolean isMatchingToken() { public boolean isMatchingToken() {
return matchingToken; return matchingToken;
} }
/**
* @return true if this token represents a variable (in source code)
*/
public boolean isVariableRef() { public boolean isVariableRef() {
return false; return false;
} }
/**
* Get the "syntax" type (color) associated with this token (keyword, type, etc)
* @return the color code
*/
public int getSyntaxType() { public int getSyntaxType() {
return syntax_type; return syntax_type;
} }
/**
* Set the "syntax" type (color) associated with this token
* @param syntax_type is the color code to set
*/
void setSyntaxType(int syntax_type) { void setSyntaxType(int syntax_type) {
this.syntax_type = syntax_type; this.syntax_type = syntax_type;
} }
/**
* @return this token's display text as a string
*/
public String getText() { public String getText() {
return text; return text;
} }
/**
* Set this token's display text.
* @param text is the string to set
*/
void setText(String text) { void setText(String text) {
this.text = text; this.text = text;
} }
/**
* Decode this token from the current position in an encoded stream
* @param decoder is the decoder for the stream
* @param pfactory is used to look up p-code objects associated with the token
* @throws DecoderException for problems decoding the stream
*/
public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
syntax_type = DEFAULT_COLOR; syntax_type = DEFAULT_COLOR;
for (;;) { for (;;) {
@@ -181,6 +217,16 @@ public class ClangToken implements ClangNode {
list.add(this); list.add(this);
} }
/**
* Decode one specialized token from the current position in an encoded stream. This
* serves as a factory for allocating the various objects derived from ClangToken
* @param node is the particular token type (already) decoded from the stream
* @param par is the text grouping which will contain the token
* @param decoder is the decoder for the stream
* @param pfactory is used to look up p-code objects associated with tokens
* @return the new ClangToken
* @throws DecoderException for problems decoding the stream
*/
static public ClangToken buildToken(int node, ClangNode par, Decoder decoder, static public ClangToken buildToken(int node, ClangNode par, Decoder decoder,
PcodeFactory pfactory) throws DecoderException { PcodeFactory pfactory) throws DecoderException {
ClangToken token = null; ClangToken token = null;
@@ -218,6 +264,13 @@ public class ClangToken implements ClangNode {
return token; return token;
} }
/**
* Add a spacer token to the given text grouping
* @param par is the text grouping
* @param indent is the number of levels to indent
* @param indentStr is a string representing containg the number of spaces in one indent level
* @return the new spacer token
*/
static public ClangToken buildSpacer(ClangNode par, int indent, String indentStr) { static public ClangToken buildSpacer(ClangNode par, int indent, String indentStr) {
String spacing = new String(); String spacing = new String();
for (int i = 0; i < indent; ++i) { for (int i = 0; i < indent; ++i) {
@@ -237,9 +290,17 @@ public class ClangToken implements ClangNode {
* @return HighVariable * @return HighVariable
*/ */
public HighVariable getHighVariable() { public HighVariable getHighVariable() {
if (Parent() instanceof ClangVariableDecl) { return null;
return ((ClangVariableDecl) Parent()).getHighVariable(); }
}
/**
* Get the symbol associated with this token or null otherwise.
* This token may be directly associated with the symbol or a reference, in which
* case the symbol is looked up in the containing HighFunction
* @param highFunction is the function
* @return HighSymbol
*/
public HighSymbol getHighSymbol(HighFunction highFunction) {
return null; return null;
} }
@@ -25,7 +25,8 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
* A node in a tree of C code tokens. * A sequence of tokens that form a meaningful group in source code. This group may
* break up into subgroups and may be part of a larger group.
*/ */
public class ClangTokenGroup implements ClangNode, Iterable<ClangNode> { public class ClangTokenGroup implements ClangNode, Iterable<ClangNode> {
private ClangNode parent; private ClangNode parent;
@@ -49,6 +50,10 @@ public class ClangTokenGroup implements ClangNode, Iterable<ClangNode> {
return maxaddress; return maxaddress;
} }
/**
* Add additional text to this group
* @param obj is the additional text
*/
public void AddTokenGroup(ClangNode obj) { public void AddTokenGroup(ClangNode obj) {
Address minaddr = obj.getMinAddress(); Address minaddr = obj.getMinAddress();
Address maxaddr = obj.getMaxAddress(); Address maxaddr = obj.getMaxAddress();
@@ -106,6 +111,12 @@ public class ClangTokenGroup implements ClangNode, Iterable<ClangNode> {
} }
} }
/**
* Decode this text from an encoded stream.
* @param decoder is the decoder for the stream
* @param pfactory is used to look up p-code attributes to associate with tokens
* @throws DecoderException for problems decoding the stream
*/
public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
for (;;) { for (;;) {
int elem = decoder.openElement(); int elem = decoder.openElement();
@@ -145,7 +156,11 @@ public class ClangTokenGroup implements ClangNode, Iterable<ClangNode> {
} }
} }
private boolean isLetterDigitOrUnderscore(char c) { /**
* @param c is a character
* @return true if the given character is a letter, digit, or underscore
*/
private static boolean isLetterDigitOrUnderscore(char c) {
return Character.isLetterOrDigit(c) || c == '_'; return Character.isLetterOrDigit(c) || c == '_';
} }
@@ -13,22 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jun 12, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
* * A source code token representing a data-type. This does not include qualifiers on the data-type
* * like '*' (pointer to) or '[]' (array of). There should be no whitespace in the name.
* A C code token representing a data type. This does not include qualifiers on the type
* like '*' (pointer to) or '[]' (array of). There should be no whitespace in the name
*/ */
public class ClangTypeToken extends ClangToken { public class ClangTypeToken extends ClangToken {
private DataType datatype; private DataType datatype;
@@ -46,6 +38,9 @@ public class ClangTypeToken extends ClangToken {
return false; return false;
} }
/**
* @return the data-type associated with this token
*/
public DataType getDataType() { public DataType getDataType() {
return datatype; return datatype;
} }
@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
* Created on Jun 12, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
@@ -26,40 +20,53 @@ import ghidra.program.model.pcode.*;
import ghidra.util.Msg; import ghidra.util.Msg;
/** /**
* * A grouping of source code tokens representing a variable declaration.
*
* A group of C code tokens forming a variable declaration.
* This can be for a one line declaration (as for local variables) or * This can be for a one line declaration (as for local variables) or
* as part of a function prototype declaring a parameter * as part of a function prototype declaring a parameter.
*/ */
public class ClangVariableDecl extends ClangTokenGroup { public class ClangVariableDecl extends ClangTokenGroup {
private DataType datatype; private DataType datatype;
private HighVariable typevar; private HighSymbol symbol;
public ClangVariableDecl(ClangNode par) { public ClangVariableDecl(ClangNode par) {
super(par); super(par);
datatype = null; datatype = null;
typevar = null; symbol = null;
} }
/**
* @return the data-type of the variable being declared
*/
public DataType getDataType() { public DataType getDataType() {
return datatype; return datatype;
} }
/**
* @return the HighVariable (collection of Varnodes) associated with the variable
*/
public HighVariable getHighVariable() { public HighVariable getHighVariable() {
return typevar; if (symbol != null) {
return symbol.getHighVariable();
}
return null;
}
/**
* @return the symbol defined by this variable declaration
*/
public HighSymbol getHighSymbol() {
return symbol;
} }
@Override @Override
public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException { public void decode(Decoder decoder, PcodeFactory pfactory) throws DecoderException {
long symref = decoder.readUnsignedInteger(AttributeId.ATTRIB_SYMREF); long symref = decoder.readUnsignedInteger(AttributeId.ATTRIB_SYMREF);
super.decode(decoder, pfactory); super.decode(decoder, pfactory);
HighSymbol sym = pfactory.getSymbol(symref); symbol = pfactory.getSymbol(symref);
if (sym == null) { if (symbol == null) {
Msg.error(this, "Invalid symbol reference: " + symref + " in " + Parent()); Msg.error(this, "Invalid symbol reference: " + symref + " in " + Parent());
return; return;
} }
typevar = sym.getHighVariable(); datatype = symbol.getDataType();
datatype = sym.getDataType();
} }
} }
@@ -16,6 +16,7 @@
package ghidra.app.decompiler; package ghidra.app.decompiler;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.pcode.*; import ghidra.program.model.pcode.*;
/** /**
@@ -76,7 +77,39 @@ public class ClangVariableToken extends ClangToken {
} }
return inst.getHigh(); return inst.getHigh();
} }
return super.getHighVariable(); ClangNode parent = Parent();
if (parent instanceof ClangVariableDecl) {
return ((ClangVariableDecl) parent).getHighVariable();
}
return null;
}
@Override
public HighSymbol getHighSymbol(HighFunction highFunction) {
Varnode inst = getVarnode();
if (inst != null) {
HighVariable hvar = inst.getHigh();
if (hvar != null) {
HighSymbol symbol = hvar.getSymbol();
if (symbol != null) {
return symbol;
}
}
}
ClangNode parent = Parent();
if (parent instanceof ClangVariableDecl) {
return ((ClangVariableDecl) parent).getHighSymbol();
}
if (highFunction == null) {
return null;
}
// Token may be from a variable reference, in which case we have to dig to find the actual symbol
Address storageAddress = getStorageAddress(highFunction.getAddressFactory());
if (storageAddress == null) {
return null;
}
return findHighSymbol(storageAddress, highFunction); // Find symbol via the reference
} }
@Override @Override
@@ -98,4 +131,41 @@ public class ClangVariableToken extends ClangToken {
decoder.rewindAttributes(); decoder.rewindAttributes();
super.decode(decoder, pfactory); super.decode(decoder, pfactory);
} }
/**
* Get the storage address of the variable, if any.
* The variable may be directly referenced by this token, or indirectly referenced as a point.
* @param addrFactory is the factory used to construct the Address
* @return the storage Address or null if there is no variable attached
*/
private Address getStorageAddress(AddressFactory addrFactory) {
Address storageAddress = null;
if (varnode != null) {
storageAddress = varnode.getAddress();
}
// op could be a PTRSUB, need to dig it out...
else {
storageAddress = HighFunctionDBUtil.getSpacebaseReferenceAddress(addrFactory, op);
}
return storageAddress;
}
/**
* Find the HighSymbol the decompiler associates with a specific address.
* @param addr is the specific address
* @param highFunction is the decompiler results in which to search for the symbol
* @return the matching symbol or null if no symbol exists
*/
private static HighSymbol findHighSymbol(Address addr, HighFunction highFunction) {
HighSymbol highSymbol = null;
if (addr.isStackAddress()) {
LocalSymbolMap lsym = highFunction.getLocalSymbolMap();
highSymbol = lsym.findLocal(addr, null);
}
else {
GlobalSymbolMap gsym = highFunction.getGlobalSymbolMap();
highSymbol = gsym.getSymbol(addr);
}
return highSymbol;
}
} }
@@ -75,77 +75,6 @@ public abstract class AbstractDecompilerAction extends DockingAction {
}); });
} }
/**
* Find the HighSymbol the decompiler associates with a specific address.
* @param addr is the specific address
* @param highFunction is the decompiler results in which to search for the symbol
* @return the matching symbol or null if no symbol exists
*/
private static HighSymbol findHighSymbol(Address addr, HighFunction highFunction) {
HighSymbol highSymbol = null;
if (addr.isStackAddress()) {
LocalSymbolMap lsym = highFunction.getLocalSymbolMap();
highSymbol = lsym.findLocal(addr, null);
}
else {
GlobalSymbolMap gsym = highFunction.getGlobalSymbolMap();
highSymbol = gsym.getSymbol(addr);
}
return highSymbol;
}
/**
* Track down the HighSymbol associated with a particular token. The token may be directly attached to
* the symbol, or it may be a reference that needs to be looked up.
* @param token is the given token
* @param highFunction is the decompiler model of the function
* @return the associated HighSymbol or null if one can't be found
*/
public static HighSymbol findHighSymbolFromToken(ClangToken token, HighFunction highFunction) {
if (highFunction == null) {
return null;
}
HighVariable variable = token.getHighVariable();
HighSymbol highSymbol = null;
if (variable == null) {
// Token may be from a variable reference, in which case we have to dig to find the actual symbol
Function function = highFunction.getFunction();
if (function == null) {
return null;
}
Address storageAddress = getStorageAddress(token, function.getProgram());
if (storageAddress == null) {
return null;
}
highSymbol = findHighSymbol(storageAddress, highFunction);
}
else {
highSymbol = variable.getSymbol();
}
return highSymbol;
}
/**
* Get the storage address of the variable attached to the given token, if any.
* The variable may be directly referenced by the token, or indirectly referenced as a point.
* @param tokenAtCursor is the given token
* @param program is the Program
* @return the storage Address or null if there is no variable attached
*/
private static Address getStorageAddress(ClangToken tokenAtCursor, Program program) {
Varnode vnode = tokenAtCursor.getVarnode();
Address storageAddress = null;
if (vnode != null) {
storageAddress = vnode.getAddress();
}
// op could be a PTRSUB, need to dig it out...
else if (tokenAtCursor instanceof ClangVariableToken) {
PcodeOp op = ((ClangVariableToken) tokenAtCursor).getPcodeOp();
storageAddress = HighFunctionDBUtil.getSpacebaseReferenceAddress(program, op);
}
return storageAddress;
}
/** /**
* Get the structure/union associated with a field token * Get the structure/union associated with a field token
* @param tok is the token representing a field * @param tok is the token representing a field
@@ -243,7 +172,7 @@ public abstract class AbstractDecompilerAction extends DockingAction {
f = DecompilerUtils.getFunction(context.getProgram(), (ClangFuncNameToken) token); f = DecompilerUtils.getFunction(context.getProgram(), (ClangFuncNameToken) token);
} }
else { else {
HighSymbol highSymbol = findHighSymbolFromToken(token, context.getHighFunction()); HighSymbol highSymbol = token.getHighSymbol(context.getHighFunction());
if (highSymbol instanceof HighFunctionShellSymbol) { if (highSymbol instanceof HighFunctionShellSymbol) {
f = (Function) highSymbol.getSymbol().getObject(); f = (Function) highSymbol.getSymbol().getObject();
} }
@@ -65,7 +65,7 @@ public class FindReferencesToHighSymbolAction extends AbstractDecompilerAction {
if (token == null) { if (token == null) {
return false; return false;
} }
HighSymbol highSymbol = findHighSymbolFromToken(token, context.getHighFunction()); HighSymbol highSymbol = token.getHighSymbol(context.getHighFunction());
if (highSymbol == null || highSymbol.getStorage().isBadStorage() || if (highSymbol == null || highSymbol.getStorage().isBadStorage() ||
!highSymbol.isGlobal()) { !highSymbol.isGlobal()) {
@@ -92,7 +92,7 @@ public class FindReferencesToHighSymbolAction extends AbstractDecompilerAction {
} }
else { else {
HighSymbol highSymbol = HighSymbol highSymbol =
findHighSymbolFromToken(context.getTokenAtCursor(), context.getHighFunction()); context.getTokenAtCursor().getHighSymbol(context.getHighFunction());
location = new LabelFieldLocation(context.getProgram(), location = new LabelFieldLocation(context.getProgram(),
highSymbol.getStorage().getMinAddress(), highSymbol.getName()); highSymbol.getStorage().getMinAddress(), highSymbol.getName());
} }
@@ -27,9 +27,7 @@ import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.pcode.HighCodeSymbol; import ghidra.program.model.pcode.*;
import ghidra.program.model.pcode.HighFunctionShellSymbol;
import ghidra.program.model.pcode.HighSymbol;
import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable; import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.*; import ghidra.util.*;
@@ -62,7 +60,7 @@ public class RenameGlobalAction extends AbstractDecompilerAction {
if (tokenAtCursor instanceof ClangFieldToken) { if (tokenAtCursor instanceof ClangFieldToken) {
return false; return false;
} }
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = tokenAtCursor.getHighSymbol(context.getHighFunction());
if (highSymbol == null || highSymbol instanceof HighFunctionShellSymbol) { if (highSymbol == null || highSymbol instanceof HighFunctionShellSymbol) {
return false; return false;
} }
@@ -73,7 +71,7 @@ public class RenameGlobalAction extends AbstractDecompilerAction {
protected void decompilerActionPerformed(DecompilerActionContext context) { protected void decompilerActionPerformed(DecompilerActionContext context) {
PluginTool tool = context.getTool(); PluginTool tool = context.getTool();
final ClangToken tokenAtCursor = context.getTokenAtCursor(); final ClangToken tokenAtCursor = context.getTokenAtCursor();
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = tokenAtCursor.getHighSymbol(context.getHighFunction());
Symbol symbol = null; Symbol symbol = null;
if (highSymbol instanceof HighCodeSymbol) { if (highSymbol instanceof HighCodeSymbol) {
symbol = ((HighCodeSymbol) highSymbol).getCodeSymbol(); symbol = ((HighCodeSymbol) highSymbol).getCodeSymbol();
@@ -67,7 +67,7 @@ public class RenameLocalAction extends AbstractDecompilerAction {
if (tokenAtCursor instanceof ClangFieldToken) { if (tokenAtCursor instanceof ClangFieldToken) {
return false; return false;
} }
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = tokenAtCursor.getHighSymbol(context.getHighFunction());
if (highSymbol == null) { if (highSymbol == null) {
return false; return false;
} }
@@ -78,7 +78,7 @@ public class RenameLocalAction extends AbstractDecompilerAction {
protected void decompilerActionPerformed(DecompilerActionContext context) { protected void decompilerActionPerformed(DecompilerActionContext context) {
PluginTool tool = context.getTool(); PluginTool tool = context.getTool();
final ClangToken tokenAtCursor = context.getTokenAtCursor(); final ClangToken tokenAtCursor = context.getTokenAtCursor();
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = tokenAtCursor.getHighSymbol(context.getHighFunction());
RenameVariableTask nameTask = new RenameVariableTask(tool, context.getProgram(), RenameVariableTask nameTask = new RenameVariableTask(tool, context.getProgram(),
context.getComponentProvider(), tokenAtCursor, highSymbol, SourceType.USER_DEFINED); context.getComponentProvider(), tokenAtCursor, highSymbol, SourceType.USER_DEFINED);
@@ -71,7 +71,7 @@ public class RetypeGlobalAction extends AbstractDecompilerAction {
if (!tokenAtCursor.isVariableRef()) { if (!tokenAtCursor.isVariableRef()) {
return false; return false;
} }
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = tokenAtCursor.getHighSymbol(context.getHighFunction());
if (highSymbol == null) { if (highSymbol == null) {
return false; return false;
} }
@@ -85,7 +85,7 @@ public class RetypeGlobalAction extends AbstractDecompilerAction {
ClangToken tokenAtCursor = context.getTokenAtCursor(); ClangToken tokenAtCursor = context.getTokenAtCursor();
DataType dataType = null; DataType dataType = null;
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = tokenAtCursor.getHighSymbol(context.getHighFunction());
if (highSymbol == null) { if (highSymbol == null) {
return; return;
} }
@@ -144,7 +144,7 @@ public class RetypeLocalAction extends AbstractDecompilerAction {
if (!tokenAtCursor.isVariableRef()) { if (!tokenAtCursor.isVariableRef()) {
return false; return false;
} }
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = tokenAtCursor.getHighSymbol(context.getHighFunction());
if (highSymbol == null) { if (highSymbol == null) {
return false; return false;
} }
@@ -158,7 +158,7 @@ public class RetypeLocalAction extends AbstractDecompilerAction {
ClangToken tokenAtCursor = context.getTokenAtCursor(); ClangToken tokenAtCursor = context.getTokenAtCursor();
DataType dataType = null; DataType dataType = null;
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = tokenAtCursor.getHighSymbol(context.getHighFunction());
if (highSymbol == null) { if (highSymbol == null) {
return; return;
} }
@@ -32,6 +32,7 @@ import ghidra.app.plugin.core.decompile.actions.RenameVariableTask;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.database.symbol.CodeSymbol; import ghidra.program.database.symbol.CodeSymbol;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Undefined; import ghidra.program.model.data.Undefined;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@@ -82,9 +83,8 @@ public class HighSymbolTest extends AbstractDecompilerTest {
} }
private void renameVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) { private void renameVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
RenameVariableTask rename = RenameVariableTask rename = new RenameVariableTask(provider.getTool(),
new RenameVariableTask(provider.getTool(), highSymbol.getProgram(), highSymbol.getProgram(), provider, tokenAtCursor, highSymbol, SourceType.USER_DEFINED);
provider, tokenAtCursor, highSymbol, SourceType.USER_DEFINED);
assertTrue(rename.isValid(newName)); assertTrue(rename.isValid(newName));
modifyProgram(p -> { modifyProgram(p -> {
rename.commit(); rename.commit();
@@ -93,8 +93,8 @@ public class HighSymbolTest extends AbstractDecompilerTest {
} }
private void isolateVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) { private void isolateVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
IsolateVariableTask isolate = new IsolateVariableTask(provider.getTool(), program, IsolateVariableTask isolate = new IsolateVariableTask(provider.getTool(), program, provider,
provider, tokenAtCursor, highSymbol, SourceType.USER_DEFINED); tokenAtCursor, highSymbol, SourceType.USER_DEFINED);
assertTrue(isolate.isValid(newName)); assertTrue(isolate.isValid(newName));
modifyProgram(p -> { modifyProgram(p -> {
isolate.commit(); isolate.commit();
@@ -223,7 +223,8 @@ public class HighSymbolTest extends AbstractDecompilerTest {
assertTrue(token instanceof ClangVariableToken); assertTrue(token instanceof ClangVariableToken);
assertNull(token.getHighVariable()); // No HighVariable associated with the token assertNull(token.getHighVariable()); // No HighVariable associated with the token
PcodeOp op = ((ClangVariableToken) token).getPcodeOp(); PcodeOp op = ((ClangVariableToken) token).getPcodeOp();
Address addr = HighFunctionDBUtil.getSpacebaseReferenceAddress(provider.getProgram(), op); AddressFactory addrFactory = provider.getProgram().getAddressFactory();
Address addr = HighFunctionDBUtil.getSpacebaseReferenceAddress(addrFactory, op);
HighFunction highFunction = getHighFunction(); HighFunction highFunction = getHighFunction();
LocalSymbolMap lsym = highFunction.getLocalSymbolMap(); LocalSymbolMap lsym = highFunction.getLocalSymbolMap();
HighSymbol highSymbol = lsym.findLocal(addr, null); HighSymbol highSymbol = lsym.findLocal(addr, null);
@@ -111,7 +111,8 @@ public class HighConstant extends HighVariable {
symbol = globalMap.populateSymbol(symref, null, -1); symbol = globalMap.populateSymbol(symref, null, -1);
if (symbol == null) { if (symbol == null) {
PcodeOp op = ((VarnodeAST) represent).getLoneDescend(); PcodeOp op = ((VarnodeAST) represent).getLoneDescend();
Address addr = HighFunctionDBUtil.getSpacebaseReferenceAddress(program, op); Address addr = HighFunctionDBUtil
.getSpacebaseReferenceAddress(program.getAddressFactory(), op);
if (addr != null) { if (addr != null) {
Data data = program.getListing().getDataAt(addr); Data data = program.getListing().getDataAt(addr);
DataType dt = data == null ? DataType.DEFAULT : data.getDataType(); DataType dt = data == null ? DataType.DEFAULT : data.getDataType();
@@ -734,11 +734,11 @@ public class HighFunctionDBUtil {
* Get the Address referred to by a spacebase reference. Address-of references are encoded in * Get the Address referred to by a spacebase reference. Address-of references are encoded in
* the p-code syntax tree as: {@code vn = PTRSUB(<spacebase>, #const)}. This decodes the reference and * the p-code syntax tree as: {@code vn = PTRSUB(<spacebase>, #const)}. This decodes the reference and
* returns the Address * returns the Address
* @param program is the program containing the Address * @param addrFactory is the factory used to construct the Address
* @param op is the PTRSUB op encoding the reference * @param op is the PTRSUB op encoding the reference
* @return the recovered Address (or null if not correct form) * @return the recovered Address (or null if not correct form)
*/ */
public static Address getSpacebaseReferenceAddress(Program program, PcodeOp op) { public static Address getSpacebaseReferenceAddress(AddressFactory addrFactory, PcodeOp op) {
Address storageAddress = null; Address storageAddress = null;
if (op == null) { if (op == null) {
return storageAddress; return storageAddress;
@@ -747,13 +747,13 @@ public class HighFunctionDBUtil {
Varnode vnode = op.getInput(0); Varnode vnode = op.getInput(0);
Varnode cnode = op.getInput(1); Varnode cnode = op.getInput(1);
if (vnode.isRegister()) { if (vnode.isRegister()) {
AddressSpace stackspace = program.getAddressFactory().getStackSpace(); AddressSpace stackspace = addrFactory.getStackSpace();
if (stackspace != null) { if (stackspace != null) {
storageAddress = stackspace.getAddress(cnode.getOffset()); storageAddress = stackspace.getAddress(cnode.getOffset());
} }
} }
else { else {
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace(); AddressSpace space = addrFactory.getDefaultAddressSpace();
if (space instanceof SegmentedAddressSpace) { if (space instanceof SegmentedAddressSpace) {
// Assume this is a "full" encoding of the offset // Assume this is a "full" encoding of the offset
int innersize = space.getPointerSize(); int innersize = space.getPointerSize();