Test debug

This commit is contained in:
dragonmacher 2025-08-19 16:49:40 -04:00
parent 105f9ef570
commit 3e240563ab
4 changed files with 66 additions and 53 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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);

View file

@ -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,