mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Test debug
This commit is contained in:
parent
105f9ef570
commit
3e240563ab
4 changed files with 66 additions and 53 deletions
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -130,7 +130,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
}
|
||||
|
||||
results.addAll(callers);
|
||||
|
||||
|
||||
// Add any callers to external function that use any form of the data type
|
||||
it = listing.getExternalFunctions();
|
||||
callers = new HashSet<>();
|
||||
|
@ -142,7 +142,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
callers.addAll(callingFunctions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
results.addAll(callers);
|
||||
|
||||
return results;
|
||||
|
@ -298,16 +298,12 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
private DataType dataType;
|
||||
private FieldMatcher fieldMatcher;
|
||||
|
||||
private String dbgPrefix;
|
||||
|
||||
DecompilerDataTypeFinder(DecompileResults results, Function function, DataType dataType,
|
||||
FieldMatcher fieldMatcher) {
|
||||
this.decompilation = results;
|
||||
this.function = function;
|
||||
this.dataType = dataType;
|
||||
this.fieldMatcher = fieldMatcher;
|
||||
|
||||
this.dbgPrefix = "f: " + function + "\n\t";
|
||||
}
|
||||
|
||||
List<DataTypeReference> findUsage() {
|
||||
|
@ -331,16 +327,16 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
return;
|
||||
}
|
||||
|
||||
DtrfDbg.println(dbgPrefix + "checking vars...");
|
||||
DtrfDbg.println(function, "checking vars...");
|
||||
List<DecompilerReference> variables = findVariableReferences(tokens);
|
||||
DtrfDbg.println(dbgPrefix + "DONE searching decompilation\nMatching results");
|
||||
DtrfDbg.println(function, "DONE searching decompilation\nMatching results");
|
||||
|
||||
variables.forEach(v -> matchUsage(v, results));
|
||||
}
|
||||
|
||||
/** Finds any search input match in the given reference */
|
||||
private void matchUsage(DecompilerReference reference, List<DataTypeReference> results) {
|
||||
DtrfDbg.println("Checking " + reference);
|
||||
DtrfDbg.println(function, "Checking " + reference);
|
||||
reference.accumulateMatches(dataType, fieldMatcher, results);
|
||||
}
|
||||
|
||||
|
@ -388,12 +384,12 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
VariableAccessDR access = null;
|
||||
for (ClangToken token : filteredTokens) {
|
||||
|
||||
DtrfDbg.println(dbgPrefix + "checking token: " + token);
|
||||
DtrfDbg.println(function, "checking token: " + token);
|
||||
|
||||
if (token instanceof ClangTypeToken) {
|
||||
|
||||
if (token.Parent() instanceof ClangReturnType) {
|
||||
DtrfDbg.println(dbgPrefix + "\treturn type: " + line);
|
||||
DtrfDbg.println(function, "\treturn type: " + line);
|
||||
|
||||
results.add(new ReturnTypeDR(line, (ClangTypeToken) token));
|
||||
}
|
||||
|
@ -401,13 +397,13 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
// Note: variable refs will get their variable in an upcoming token
|
||||
if (isFunctionPrototype(token.Parent())) {
|
||||
|
||||
DtrfDbg.println(dbgPrefix + "\tparameter: " + line);
|
||||
DtrfDbg.println(function, "\tparameter: " + line);
|
||||
|
||||
declaration = new ParameterDR(line, (ClangTypeToken) token);
|
||||
}
|
||||
else {
|
||||
|
||||
DtrfDbg.println(dbgPrefix + "\tlocal var: " + line);
|
||||
DtrfDbg.println(function, "\tlocal var: " + line);
|
||||
|
||||
declaration = new LocalVariableDR(line, (ClangTypeToken) token);
|
||||
}
|
||||
|
@ -416,7 +412,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
}
|
||||
else {
|
||||
|
||||
DtrfDbg.println(dbgPrefix + "\tadding a cast");
|
||||
DtrfDbg.println(function, "\tadding a cast");
|
||||
|
||||
// Assumption: this is a cast inside of a ClangStatement
|
||||
// Assumption: there can be multiple casts concatenated
|
||||
|
@ -438,7 +434,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
//
|
||||
if (declaration != null) {
|
||||
|
||||
DtrfDbg.println(dbgPrefix + "\thave declaration - " + declaration);
|
||||
DtrfDbg.println(function, "\thave declaration - " + declaration);
|
||||
|
||||
declaration.setVariable((ClangVariableToken) token);
|
||||
declaration = null;
|
||||
|
@ -446,7 +442,7 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
else {
|
||||
if (access == null || access.getVariable() != null) {
|
||||
|
||||
DtrfDbg.println(dbgPrefix + "\tcreating variable access: " + line);
|
||||
DtrfDbg.println(function, "\tcreating variable access: " + line);
|
||||
|
||||
access = new VariableAccessDR(line);
|
||||
results.add(access);
|
||||
|
@ -479,8 +475,8 @@ public class DecompilerDataTypeReferenceFinder implements DataTypeReferenceFinde
|
|||
ClangFieldToken field = (ClangFieldToken) token;
|
||||
if (typesDoNotMatch(access, field)) {
|
||||
|
||||
DtrfDbg.println(
|
||||
dbgPrefix + "\tcreating an anonymous variable access: " + line);
|
||||
DtrfDbg.println(function,
|
||||
"\tcreating an anonymous variable access: " + line);
|
||||
|
||||
// this can happen when a field is used anonymously, such as directly
|
||||
// after a nested array index operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -18,10 +18,12 @@ package ghidra.app.extension.datatype.finder;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import generic.io.NullPrintWriter;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
|
@ -36,6 +38,8 @@ class DtrfDbg {
|
|||
|
||||
private static List<String> clientFilters = new ArrayList<>();
|
||||
|
||||
private static Map<Function, List<String>> linesByFunction = new HashMap<>();
|
||||
|
||||
DtrfDbg() {
|
||||
// static class
|
||||
}
|
||||
|
@ -57,6 +61,16 @@ class DtrfDbg {
|
|||
return;
|
||||
}
|
||||
|
||||
Set<Entry<Function, List<String>>> entries = linesByFunction.entrySet();
|
||||
for (Entry<Function, List<String>> entry : entries) {
|
||||
Function function = entry.getKey();
|
||||
List<String> lines = entry.getValue();
|
||||
debugWriter.println("\n\nFunction Debug: " + function.getName());
|
||||
for (String line : lines) {
|
||||
debugWriter.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
debugWriter.flush();
|
||||
String output = debugBytes.toString();
|
||||
if (!StringUtils.isBlank(output)) {
|
||||
|
@ -76,16 +90,16 @@ class DtrfDbg {
|
|||
clientFilters.addAll(Arrays.asList(filters));
|
||||
}
|
||||
|
||||
static void println(String s) {
|
||||
debugWriter.println(s);
|
||||
static void println(Function f, String s) {
|
||||
linesByFunction.computeIfAbsent(f, ff -> new ArrayList<>()).add(s);
|
||||
}
|
||||
|
||||
static void println(Object client, String s) {
|
||||
static void println(Function f, Object client, String s) {
|
||||
if (!passesFilter(client)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debugWriter.println(s);
|
||||
linesByFunction.computeIfAbsent(f, ff -> new ArrayList<>()).add(s);
|
||||
}
|
||||
|
||||
private static boolean passesFilter(Object client) {
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -25,7 +25,6 @@ import ghidra.app.services.FieldMatcher;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.pcode.HighGlobal;
|
||||
import ghidra.program.model.pcode.HighVariable;
|
||||
import ghidra.util.StringUtilities;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
@ -106,7 +105,7 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
private DecompilerVariable getMatch(DataType dt, FieldMatcher fieldMatcher,
|
||||
DecompilerVariable var, DecompilerVariable potentialField) {
|
||||
|
||||
String indent = "\t\t";
|
||||
String indent = "\t\t\t";
|
||||
|
||||
// Note: for now, I ignore the precedence of casting; if any cast type is a match, then
|
||||
// signal hooray
|
||||
|
@ -114,19 +113,21 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
DecompilerVariable fieldVar = searchForField ? potentialField : null;
|
||||
DecompilerVariable match = getMatchingVarialbe(dt, var, fieldVar);
|
||||
if (match == null) {
|
||||
DtrfDbg.println(this, indent + "NO MATCHING VARIABLE");
|
||||
DtrfDbg.println(getFunction(), this, indent + "NO MATCHING VARIABLE");
|
||||
return null; // wrong type, nothing to do
|
||||
}
|
||||
|
||||
// Matches on the type, does the field match?
|
||||
if (fieldMatcher.isIgnored()) {
|
||||
DtrfDbg.println(this, indent + "field macher is ignored; returning match");
|
||||
DtrfDbg.println(getFunction(), this,
|
||||
indent + "field macher is ignored; returning match");
|
||||
return match; // no field to match
|
||||
}
|
||||
|
||||
if (potentialField == null) {
|
||||
|
||||
DtrfDbg.println(this, indent + "No potential field to match; name / offset match?");
|
||||
DtrfDbg.println(getFunction(), this,
|
||||
indent + "No potential field to match; name / offset match?");
|
||||
|
||||
// check for the case where we have not been passed a 'potential field', but the given
|
||||
// 'var' is itself may be the field we seek, such as in an if statement like this:
|
||||
|
@ -135,23 +136,25 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
String name = var.getName();
|
||||
int offset = var.getOffset();
|
||||
if (fieldMatcher.matches(name, offset)) {
|
||||
DtrfDbg.println(this, indent + "\tfield matcher matched on variable: " + var);
|
||||
StringUtilities.indentLines(var.toString(), indent + '\t');
|
||||
DtrfDbg.println(getFunction(), this,
|
||||
indent + "\tfield matcher matched on variable: " + var);
|
||||
return var;
|
||||
}
|
||||
|
||||
DtrfDbg.println(this, indent + "\tNO FIELD MATCHER MATCH");
|
||||
DtrfDbg.println(getFunction(), this, indent + "\tNO FIELD MATCHER MATCH");
|
||||
return null; // we seek a field, but there is none
|
||||
}
|
||||
|
||||
DtrfDbg.println(this, indent + "Checking 'potential field' match...");
|
||||
DtrfDbg.println(getFunction(), this, indent + "Checking 'potential field' match...");
|
||||
|
||||
String name = potentialField.getName();
|
||||
int offset = potentialField.getOffset();
|
||||
if (fieldMatcher.matches(name, offset)) {
|
||||
DtrfDbg.println(this, indent + "\tMATCHED");
|
||||
DtrfDbg.println(getFunction(), this, indent + "\tMATCHED");
|
||||
return match;
|
||||
}
|
||||
DtrfDbg.println(this, indent + "\tNO MATCH");
|
||||
DtrfDbg.println(getFunction(), this, indent + "\tNO MATCH");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -160,26 +163,27 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
|
||||
String indent = "\t\t\t";
|
||||
|
||||
DtrfDbg.println(this, indent + "Checking for matching variable; any casts?");
|
||||
DtrfDbg.println(getFunction(), this, indent + "Checking for matching variable; any casts?");
|
||||
List<DecompilerVariable> castVariables = var.getCasts();
|
||||
for (DecompilerVariable cast : castVariables) {
|
||||
if (matchesType(cast, dt)) {
|
||||
DtrfDbg.println(this, indent + "MATCHED cast: " + cast);
|
||||
DtrfDbg.println(getFunction(), this, indent + "MATCHED cast: " + cast);
|
||||
return cast;
|
||||
}
|
||||
}
|
||||
|
||||
String dtString = dt == null ? "null" : dt.toString();
|
||||
DtrfDbg.println(this,
|
||||
DtrfDbg.println(getFunction(), this,
|
||||
indent + "No matched casts; checking type against var:\n" +
|
||||
StringUtilities.indentLines("type: " + dtString, indent + "\t") + "\n" +
|
||||
StringUtilities.indentLines("var: " + var.toString(), indent + "\t"));
|
||||
if (matchesType(var, dt)) {
|
||||
DtrfDbg.println(this, indent + "MATCHED type: ");
|
||||
DtrfDbg.println(getFunction(), this, indent + "MATCHED type: ");
|
||||
return var;
|
||||
}
|
||||
|
||||
DtrfDbg.println(this, indent + "Type did not match; checking High Variable: ");
|
||||
DtrfDbg.println(getFunction(), this,
|
||||
indent + "Type did not match; checking High Variable: ");
|
||||
|
||||
//
|
||||
// Unusual Code Alert!
|
||||
|
@ -194,12 +198,12 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
HighVariable highVariable = var.variable.getHighVariable();
|
||||
if (highVariable != null) {
|
||||
if (matchesParentType(potentialField, dt)) {
|
||||
DtrfDbg.println(this, indent + "MATCHED on parent type: " + dt);
|
||||
DtrfDbg.println(getFunction(), this, indent + "MATCHED on parent type: " + dt);
|
||||
return potentialField;
|
||||
}
|
||||
}
|
||||
|
||||
DtrfDbg.println(this, indent + "NOT MATCHED");
|
||||
DtrfDbg.println(getFunction(), this, indent + "NOT MATCHED");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -218,7 +222,7 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
String indent = "\t\t\t\t";
|
||||
|
||||
if (var == null) {
|
||||
DtrfDbg.println(this, indent + "Types Match? no variable to check");
|
||||
DtrfDbg.println(getFunction(), this, indent + "Types Match? no variable to check");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -226,7 +230,7 @@ public class VariableAccessDR extends DecompilerReference {
|
|||
if (varType == null) {
|
||||
// it seems odd to me that there is no type, but I have seen this in the case
|
||||
// statement of a switch
|
||||
DtrfDbg.println(this, indent + "ypes Match? no variable TYPE to check");
|
||||
DtrfDbg.println(getFunction(), this, indent + "ypes Match? no variable TYPE to check");
|
||||
return false;
|
||||
}
|
||||
boolean matches = isEqual(varType, dt);
|
||||
|
|
|
@ -16,12 +16,10 @@
|
|||
package generic.test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.timer.GTimer;
|
||||
import ghidra.util.timer.GTimerMonitor;
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
@ -204,10 +202,11 @@ public class ConcurrentTestExceptionStatement extends Statement {
|
|||
return;
|
||||
}
|
||||
|
||||
if (SystemUtilities.isInDevelopmentMode()) {
|
||||
throw new AssertionFailedError("Test timeout after " +
|
||||
TimeUnit.MINUTES.convert(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) + " mins");
|
||||
}
|
||||
// Not sure why we were doing this before
|
||||
// if (SystemUtilities.isInDevelopmentMode()) {
|
||||
// throw new AssertionFailedError("Test timeout after " +
|
||||
// TimeUnit.MINUTES.convert(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS) + " mins");
|
||||
// }
|
||||
|
||||
String vmTrace = AbstractGenericTest.createStackTraceForAllThreads();
|
||||
Msg.error(ConcurrentTestExceptionStatement.class,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue