mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 21:21:56 +00:00
Merge remote-tracking branch 'origin/GT-2754-dragonmacher' into Ghidra_9.0.3
This commit is contained in:
commit
b520ee2fc4
@ -0,0 +1,69 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.extension.datatype.finder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.app.decompiler.ClangFieldToken;
|
||||||
|
import ghidra.app.decompiler.ClangLine;
|
||||||
|
import ghidra.app.services.DataTypeReference;
|
||||||
|
import ghidra.program.model.data.Composite;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents the use of a field of a {@link Composite} data type <b>where there is
|
||||||
|
* no variable in the Decompiler</b> for that data type. A normal variable access in the
|
||||||
|
* Decompiler may look like so:
|
||||||
|
* <pre>
|
||||||
|
* Foo f;
|
||||||
|
* ...
|
||||||
|
* return f.some_field;
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Alternatively, an anonymous variable access would look like this:
|
||||||
|
* <pre>
|
||||||
|
* Bar b;
|
||||||
|
* ...
|
||||||
|
* return b-><b>foo_array[1].some_field</b>;
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* In this case, <code><b>foo_array[1]</b></code> is a <code>Foo</code>, whose
|
||||||
|
* <code><b>some_field</b></code> is
|
||||||
|
* being accessed anonymously, since there is no variable of <code>Foo</code> declared
|
||||||
|
* in the current function.
|
||||||
|
*/
|
||||||
|
public class AnonymousVariableAccessDR extends DecompilerReference {
|
||||||
|
|
||||||
|
protected AnonymousVariableAccessDR(ClangLine line, ClangFieldToken token) {
|
||||||
|
super(line, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accumulateMatches(DataType dt, String fieldName, List<DataTypeReference> results) {
|
||||||
|
|
||||||
|
ClangFieldToken field = (ClangFieldToken) sourceToken;
|
||||||
|
DataType fieldDt = field.getDataType();
|
||||||
|
if (!isEqual(dt, fieldDt)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.getText().equals(fieldName)) {
|
||||||
|
results.add(new DataTypeReference(fieldDt, fieldName, getFunction(), getAddress(),
|
||||||
|
getContext()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,6 +20,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.IterableUtils;
|
||||||
|
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.decompiler.component.DecompilerUtils;
|
import ghidra.app.decompiler.component.DecompilerUtils;
|
||||||
import ghidra.app.decompiler.parallel.*;
|
import ghidra.app.decompiler.parallel.*;
|
||||||
@ -225,13 +227,13 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||||||
private DataType dataType;
|
private DataType dataType;
|
||||||
private String fieldName;
|
private String fieldName;
|
||||||
|
|
||||||
/** Search for Data Type access only--no field usage */
|
/* Search for Data Type access only--no field usage */
|
||||||
DecompilerDataTypeFinderQCallback(Program program, DataType dataType,
|
DecompilerDataTypeFinderQCallback(Program program, DataType dataType,
|
||||||
Consumer<DataTypeReference> callback) {
|
Consumer<DataTypeReference> callback) {
|
||||||
this(program, dataType, null, callback);
|
this(program, dataType, null, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Search for composite field access */
|
/* Search for composite field access */
|
||||||
DecompilerDataTypeFinderQCallback(Program program, DataType dataType, String fieldName,
|
DecompilerDataTypeFinderQCallback(Program program, DataType dataType, String fieldName,
|
||||||
Consumer<DataTypeReference> callback) {
|
Consumer<DataTypeReference> callback) {
|
||||||
|
|
||||||
@ -336,14 +338,38 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the given line to find variables (also parameters and return types) and any
|
||||||
|
* accesses to them in that line. A given variable may be used directly or, as in
|
||||||
|
* the case with Composite types, may have one of its fields accessed. Each result
|
||||||
|
* found by this method will be at least a variable access and may also itself have
|
||||||
|
* field accesses.
|
||||||
|
*
|
||||||
|
* <p>Sometimes a line is structured such that there are anonymous variable accesses. This
|
||||||
|
* is the case where a Composite is being accessed, but the Composite itself is
|
||||||
|
* not a variable in the current function. See {@link AnonymousVariableAccessDR} for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* @param line the current line being processed from the Decompiler
|
||||||
|
* @param results the accumulator into which matches will be placed
|
||||||
|
*/
|
||||||
private void findVariablesInLine(ClangLine line, List<DecompilerReference> results) {
|
private void findVariablesInLine(ClangLine line, List<DecompilerReference> results) {
|
||||||
|
|
||||||
|
List<ClangToken> allTokens = line.getAllTokens();
|
||||||
|
Iterable<ClangToken> filteredTokens = IterableUtils.filteredIterable(allTokens,
|
||||||
|
token -> {
|
||||||
|
// Only include desirable tokens (this is really just for easier debugging).
|
||||||
|
// Update this filter if the loop below ever needs other types of tokens.
|
||||||
|
return (token instanceof ClangTypeToken) ||
|
||||||
|
(token instanceof ClangVariableToken) || (token instanceof ClangFieldToken);
|
||||||
|
});
|
||||||
|
|
||||||
// gather any casts until we can use them (the type they modify will follow)
|
// gather any casts until we can use them (the type they modify will follow)
|
||||||
List<DecompilerVariable> castsSoFar = new ArrayList<>();
|
List<DecompilerVariable> castsSoFar = new ArrayList<>();
|
||||||
|
|
||||||
VariableDR declaration = null;
|
VariableDR declaration = null;
|
||||||
VariableAccessDR access = null;
|
VariableAccessDR access = null;
|
||||||
for (ClangToken token : line.getAllTokens()) {
|
for (ClangToken token : filteredTokens) {
|
||||||
|
|
||||||
if (token instanceof ClangTypeToken) {
|
if (token instanceof ClangTypeToken) {
|
||||||
|
|
||||||
@ -371,16 +397,15 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||||||
|
|
||||||
//
|
//
|
||||||
// Observations:
|
// Observations:
|
||||||
// 1) 'variableAccess' will be null if we are on a C statement that
|
// 1) 'access' will be null if we are on a C statement that
|
||||||
// is a declaration (parameter or variable). In this case, 'ref' will
|
// is a declaration (parameter or variable). In this case,
|
||||||
// be an instance of VariableDR.
|
// 'declaration' will be an instance of VariableDR.
|
||||||
// 2) 'variableAccess' will be null the first time a variable is used in
|
// 2) 'access' will be null the first time a variable is used in
|
||||||
// a statement.
|
// a statement.
|
||||||
// 3) if 'variableAccess' is non-null, but already has a variable assigned,
|
// 3) if 'access' is non-null, but already has a variable assigned,
|
||||||
// then this means the current ClangVariableToken represents a new
|
// then this means the current ClangVariableToken represents a new
|
||||||
// variable access/usage.
|
// variable access/usage.
|
||||||
//
|
//
|
||||||
|
|
||||||
if (declaration != null) {
|
if (declaration != null) {
|
||||||
declaration.setVariable((ClangVariableToken) token);
|
declaration.setVariable((ClangVariableToken) token);
|
||||||
declaration = null;
|
declaration = null;
|
||||||
@ -415,12 +440,32 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
access.addField((ClangFieldToken) token, casts);
|
ClangFieldToken field = (ClangFieldToken) token;
|
||||||
|
if (typesDoNotMatch(access, field)) {
|
||||||
|
// this can happen when a field is used anonymously, such as directly
|
||||||
|
// after a nested array index operation
|
||||||
|
results.add(new AnonymousVariableAccessDR(line, field));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
access.addField(field, casts);
|
||||||
castsSoFar.clear();
|
castsSoFar.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean typesDoNotMatch(VariableAccessDR access, ClangFieldToken field) {
|
||||||
|
|
||||||
|
DecompilerVariable variable = access.getVariable();
|
||||||
|
if (variable == null) {
|
||||||
|
return false; // should not happen
|
||||||
|
}
|
||||||
|
|
||||||
|
DataType variableDt = variable.getDataType();
|
||||||
|
DataType fieldDt = field.getDataType();
|
||||||
|
return !DecompilerReference.isEqual(variableDt, fieldDt);
|
||||||
|
}
|
||||||
|
|
||||||
private VariableAccessDR getLastAccess(List<DecompilerReference> variables) {
|
private VariableAccessDR getLastAccess(List<DecompilerReference> variables) {
|
||||||
// for now, assume that the last access will be the last item we added
|
// for now, assume that the last access will be the last item we added
|
||||||
if (variables.isEmpty()) {
|
if (variables.isEmpty()) {
|
||||||
|
@ -83,6 +83,10 @@ public abstract class DecompilerReference {
|
|||||||
return var.getAddress();
|
return var.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClangLine getLine() {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
protected String getContext() {
|
protected String getContext() {
|
||||||
String context = getContext(variable);
|
String context = getContext(variable);
|
||||||
return context;
|
return context;
|
||||||
|
@ -52,7 +52,7 @@ public abstract class DecompilerVariable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Note: this is the icky part of the API. How to know from where to get the data type?
|
// Note: this is the icky part of the API. How to know from where to get the data type?
|
||||||
HighVariable highVariable = variable.getHighVariable();
|
HighVariable highVariable = variable.getHighVariable();
|
||||||
if (highVariable != null) {
|
if (highVariable != null) {
|
||||||
return highVariable.getDataType();
|
return highVariable.getDataType();
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ public abstract class DecompilerVariable {
|
|||||||
if (dataType != null) {
|
if (dataType != null) {
|
||||||
return dataType;
|
return dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefer the type of the first input varnode, unless that type is a 'void *'.
|
// Prefer the type of the first input varnode, unless that type is a 'void *'.
|
||||||
// Usually, in that special case, the output varnode has the correct type information.
|
// Usually, in that special case, the output varnode has the correct type information.
|
||||||
PcodeOp op = variable.getPcodeOp();
|
PcodeOp op = variable.getPcodeOp();
|
||||||
@ -104,7 +104,19 @@ public abstract class DecompilerVariable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Varnode output = op.getOutput();
|
Varnode output = op.getOutput();
|
||||||
return output.getHigh().getDataType();
|
if (output == null) {
|
||||||
|
// can happen when a variable in volatile memory is used in a write_volatile
|
||||||
|
// pseudo operation
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HighVariable high = output.getHigh();
|
||||||
|
if (high == null) {
|
||||||
|
// not sure if this can happen; just in case
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return high.getDataType();
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataType getDataType(Varnode varnode) {
|
private DataType getDataType(Varnode varnode) {
|
||||||
|
Loading…
Reference in New Issue
Block a user