GP-5800: Delete asm debug logging altogether

This commit is contained in:
Dan 2025-07-03 13:23:17 +00:00
parent 3e50533187
commit 0e3beed22a
27 changed files with 235 additions and 821 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.
@ -27,7 +27,6 @@ import ghidra.app.plugin.assembler.sleigh.parse.*;
import ghidra.app.plugin.assembler.sleigh.sem.*;
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyNumericSymbols;
import ghidra.app.plugin.assembler.sleigh.tree.AssemblyParseBranch;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.framework.model.DomainObjectChangedEvent;
import ghidra.framework.model.DomainObjectListener;
@ -43,7 +42,6 @@ import ghidra.util.task.TaskMonitor;
public abstract class AbstractSleighAssembler<RP extends AssemblyResolvedPatterns>
implements GenericAssembler<RP> {
protected static final DbgTimer dbg = DbgTimer.INACTIVE;
protected class ListenerForSymbolsRefresh implements DomainObjectListener {
@Override
@ -150,7 +148,6 @@ public abstract class AbstractSleighAssembler<RP extends AssemblyResolvedPattern
for (String part : assembly) {
for (String line : part.split("\n")) {
RegisterValue rv = program.getProgramContext().getDisassemblyContext(at);
dbg.println(rv);
AssemblyPatternBlock ctx = AssemblyPatternBlock.fromRegisterValue(rv);
ctx = ctx.fillMask();
byte[] insbytes = assembleLine(at, line, ctx);

View file

@ -27,8 +27,6 @@ import ghidra.app.plugin.assembler.sleigh.grammars.AssemblySentential;
import ghidra.app.plugin.assembler.sleigh.parse.AssemblyParser;
import ghidra.app.plugin.assembler.sleigh.sem.*;
import ghidra.app.plugin.assembler.sleigh.symbol.*;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.DbgCtx;
import ghidra.app.plugin.languages.sleigh.SleighLanguages;
import ghidra.app.plugin.languages.sleigh.SubtableEntryVisitor;
import ghidra.app.plugin.processors.sleigh.*;
@ -38,13 +36,10 @@ import ghidra.app.plugin.processors.sleigh.template.ConstructTpl;
import ghidra.app.plugin.processors.sleigh.template.HandleTpl;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.listing.Program;
import ghidra.util.SystemUtilities;
public abstract class AbstractSleighAssemblerBuilder< //
RP extends AssemblyResolvedPatterns, A extends GenericAssembler<RP>>
implements GenericAssemblerBuilder<RP, A> {
protected static final DbgTimer dbg =
SystemUtilities.isInTestingBatchMode() ? DbgTimer.INACTIVE : DbgTimer.ACTIVE;
protected final SleighLanguage lang;
protected final AbstractAssemblyResolutionFactory<RP, ?> factory;
@ -319,41 +314,39 @@ public abstract class AbstractSleighAssemblerBuilder< //
* Build the full grammar for the language
*/
protected void buildGrammar() {
try (DbgCtx dc = dbg.start("Building grammar")) {
grammar = new AssemblyGrammar(factory);
for (Symbol sym : lang.getSymbolTable().getSymbolList()) {
if (sym instanceof SubtableSymbol) {
SubtableSymbol subtable = (SubtableSymbol) sym;
grammar.combine(buildSubGrammar(subtable));
}
else if (sym instanceof VarnodeSymbol) {
// Ignore. This just becomes a string terminal
}
else if (sym instanceof StartSymbol) {
// Ignore. We handle inst_start in semantic processing
}
else if (sym instanceof EndSymbol) {
// Ignore. We handle inst_next in semantic processing
}
else if (sym instanceof Next2Symbol) {
// Ignore. We handle inst_next2 in semantic processing
}
else if (sym instanceof UseropSymbol) {
// Ignore. We don't do pcode.
}
else if (sym instanceof OperandSymbol) {
// Ignore. These are terminals, or will be produced by their defining symbols
}
else if (sym instanceof ValueSymbol) {
// Ignore. These are now terminals
}
else {
throw new RuntimeException("Unexpected type: " + sym.getClass());
}
grammar = new AssemblyGrammar(factory);
for (Symbol sym : lang.getSymbolTable().getSymbolList()) {
if (sym instanceof SubtableSymbol) {
SubtableSymbol subtable = (SubtableSymbol) sym;
grammar.combine(buildSubGrammar(subtable));
}
else if (sym instanceof VarnodeSymbol) {
// Ignore. This just becomes a string terminal
}
else if (sym instanceof StartSymbol) {
// Ignore. We handle inst_start in semantic processing
}
else if (sym instanceof EndSymbol) {
// Ignore. We handle inst_next in semantic processing
}
else if (sym instanceof Next2Symbol) {
// Ignore. We handle inst_next2 in semantic processing
}
else if (sym instanceof UseropSymbol) {
// Ignore. We don't do pcode.
}
else if (sym instanceof OperandSymbol) {
// Ignore. These are terminals, or will be produced by their defining symbols
}
else if (sym instanceof ValueSymbol) {
// Ignore. These are now terminals
}
else {
throw new RuntimeException("Unexpected type: " + sym.getClass());
}
grammar.setStartName("instruction");
}
grammar.setStartName("instruction");
}
/**
@ -367,18 +360,14 @@ public abstract class AbstractSleighAssemblerBuilder< //
* Build the context transition graph for the language
*/
protected void buildContextGraph() {
try (DbgCtx dc = dbg.start("Building context graph")) {
ctxGraph = new AssemblyContextGraph(factory, lang, grammar);
}
ctxGraph = new AssemblyContextGraph(factory, lang, grammar);
}
/**
* Build the parser for the language
*/
protected void buildParser() {
try (DbgCtx dc = dbg.start("Building parser")) {
parser = new AssemblyParser(grammar);
}
parser = new AssemblyParser(grammar);
}
/**

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.
@ -42,15 +42,9 @@ public abstract class AbstractBinaryExpressionSolver<T extends BinaryExpression>
MaskedLong rval = solver.getValue(exp.getRight(), vals, cur);
if (lval != null && !lval.isFullyDefined()) {
if (!lval.isFullyUndefined()) {
dbg.println("Partially-defined left value for binary solver: " + lval);
}
lval = null;
}
if (rval != null && !rval.isFullyDefined()) {
if (!rval.isFullyUndefined()) {
dbg.println("Partially-defined right value for binary solver: " + rval);
}
rval = null;
}
@ -80,7 +74,6 @@ public abstract class AbstractBinaryExpressionSolver<T extends BinaryExpression>
return factory.newErrorBuilder().error(e.getMessage()).description(description).build();
}
catch (AssertionError e) {
dbg.println("While solving: " + exp + " (" + description + ")");
throw e;
}
}

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.
@ -19,7 +19,6 @@ import java.util.Map;
import java.util.Set;
import ghidra.app.plugin.assembler.sleigh.sem.*;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
/**
@ -31,8 +30,6 @@ public abstract class AbstractExpressionSolver<T extends PatternExpression> {
private Class<T> tcls;
protected RecursiveDescentSolver solver;
protected final DbgTimer dbg = DbgTimer.INACTIVE;
/**
* Construct a solver that can solve expression of the given type
*

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.
@ -53,7 +53,6 @@ public abstract class AbstractUnaryExpressionSolver<T extends UnaryExpression>
* AssemblyResolvedConstructor.error(e.getMessage(), description, null); }
*/
catch (AssertionError e) {
dbg.println("While solving: " + exp + " (" + description + ")");
throw e;
}
}

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.
@ -19,7 +19,6 @@ import java.util.*;
import ghidra.app.plugin.assembler.sleigh.expr.match.ExpressionMatcher;
import ghidra.app.plugin.assembler.sleigh.sem.*;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.DbgCtx;
import ghidra.app.plugin.processors.sleigh.expression.*;
import ghidra.util.Msg;
@ -70,31 +69,26 @@ public class OrExpressionSolver extends AbstractBinaryExpressionSolver<OrExpress
long lo = 0;
PatternExpression fieldExp = null;
AssemblyResolvedPatterns result = factory.nop(description);
try (DbgCtx dc = dbg.start("Trying solution of field catenation")) {
dbg.println("Original: " + goal + ":= " + exp);
for (Map.Entry<Long, PatternExpression> ent : fields.entrySet()) {
long hi = ent.getKey();
if (hi == 0) {
fieldExp = ent.getValue();
continue;
}
dbg.println("Part(" + hi + ":" + lo + "]:= " + fieldExp);
MaskedLong part = goal.shiftLeft(64 - hi).shiftRightPositional(64 - hi + lo);
dbg.println("Solving: " + part + ":= " + fieldExp);
AssemblyResolution sol = solver.solve(factory, fieldExp, part, vals, cur, hints,
description + " with shift " + lo);
if (sol.isError()) {
return sol;
}
result = result.combine((AssemblyResolvedPatterns) sol);
if (result == null) {
throw new SolverException("Solutions to individual fields produced conflict");
}
lo = hi;
for (Map.Entry<Long, PatternExpression> ent : fields.entrySet()) {
long hi = ent.getKey();
if (hi == 0) {
fieldExp = ent.getValue();
continue;
}
MaskedLong part = goal.shiftLeft(64 - hi).shiftRightPositional(64 - hi + lo);
AssemblyResolution sol = solver.solve(factory, fieldExp, part, vals, cur, hints,
description + " with shift " + lo);
if (sol.isError()) {
return sol;
}
result = result.combine((AssemblyResolvedPatterns) sol);
if (result == null) {
throw new SolverException("Solutions to individual fields produced conflict");
}
lo = hi;
fieldExp = ent.getValue();
}
return result;
}
@ -166,8 +160,6 @@ public class OrExpressionSolver extends AbstractBinaryExpressionSolver<OrExpress
}
// At this point, I know it's a circular shift
dbg.println("Identified circular shift: value:= " + expValu1 + ", shift:= " + expShift +
", size:= " + size + ", dir:= " + (dir == 1 ? "right" : "left"));
return solveLeftCircularShift(factory, expValu1, expShift, size, dir, goal, vals, cur,
hints, description);
}
@ -181,15 +173,9 @@ public class OrExpressionSolver extends AbstractBinaryExpressionSolver<OrExpress
MaskedLong valShift = solver.getValue(expShift, vals, cur);
if (valValue != null && !valValue.isFullyDefined()) {
if (!valValue.isFullyUndefined()) {
dbg.println("Partially-defined f for left circular shift solver: " + valValue);
}
valValue = null;
}
if (valShift != null && valShift.isFullyDefined()) {
if (!valShift.isFullyUndefined()) {
dbg.println("Partially-defined g for left circular shift solver: " + valShift);
}
valShift = null;
}
@ -278,16 +264,14 @@ public class OrExpressionSolver extends AbstractBinaryExpressionSolver<OrExpress
return tryCatenationExpression(factory, exp, goal, vals, cur, hints, description);
}
catch (Exception e) {
dbg.println("while solving: " + goal + "=:" + exp);
dbg.println(e.getMessage());
// Will be reported later
}
try {
return tryCircularShiftExpression(factory, exp, goal, vals, cur, hints, description);
}
catch (Exception e) {
dbg.println("while solving: " + goal + "=:" + exp);
dbg.println(e.getMessage());
// Will be reported later
}
Map<ExpressionMatcher<?>, PatternExpression> match = MATCHERS.neqConst.match(exp);

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,7 +18,6 @@ package ghidra.app.plugin.assembler.sleigh.expr;
import java.util.*;
import ghidra.app.plugin.assembler.sleigh.sem.*;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
/**
@ -39,7 +38,6 @@ import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
* {@link PatternExpression}.
*/
public class RecursiveDescentSolver {
protected static final DbgTimer DBG = DbgTimer.INACTIVE;
private static final RecursiveDescentSolver INSTANCE = new RecursiveDescentSolver();
// A mapping from each subclass of PatternExpression to the appropriate solver
@ -118,14 +116,8 @@ public class RecursiveDescentSolver {
PatternExpression exp, MaskedLong goal, Map<String, Long> vals,
AssemblyResolvedPatterns cur, Set<SolverHint> hints, String description)
throws NeedsBackfillException {
try {
return getRegistered(exp.getClass()).solve(factory, exp, goal, vals, cur, hints,
description);
}
catch (UnsupportedOperationException e) {
DBG.println("Error solving " + exp + " = " + goal);
throw e;
}
return getRegistered(exp.getClass()).solve(factory, exp, goal, vals, cur, hints,
description);
}
/**
@ -170,7 +162,6 @@ public class RecursiveDescentSolver {
protected <T extends PatternExpression> MaskedLong getValue(T exp, Map<String, Long> vals,
AssemblyResolvedPatterns cur) throws NeedsBackfillException {
MaskedLong value = getRegistered(exp.getClass()).getValue(exp, vals, cur);
DBG.println("Expression: " + value + " =: " + exp);
return value;
}

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,8 +25,6 @@ import ghidra.app.plugin.assembler.sleigh.parse.AssemblyParseActionGotoTable.*;
import ghidra.app.plugin.assembler.sleigh.symbol.*;
import ghidra.app.plugin.assembler.sleigh.tree.*;
import ghidra.app.plugin.assembler.sleigh.util.AsmUtil;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.DbgCtx;
/**
* A class that implements the LALR(1) parsing algorithm
@ -75,8 +73,6 @@ public class AssemblyParseMachine implements Comparable<AssemblyParseMachine> {
static int nextMachineId = 0;
static final DbgTimer DBG = DbgTimer.INACTIVE;
/**
* Construct a new parse state
*
@ -206,7 +202,6 @@ public class AssemblyParseMachine implements Comparable<AssemblyParseMachine> {
c.accepted = accepted;
c.error = error;
DBG.println("Copied " + id + " to " + c.id);
return c;
}
@ -224,41 +219,37 @@ public class AssemblyParseMachine implements Comparable<AssemblyParseMachine> {
*/
protected void doAction(Action a, AssemblyParseToken tok, Set<AssemblyParseMachine> results,
Deque<AssemblyParseMachine> visited) {
try (DbgCtx dc = DBG.start("Action: " + a)) {
if (a instanceof ShiftAction) {
AssemblyParseMachine m = copy();
m.stack.push(((ShiftAction) a).newStateNum);
m.treeStack.push(tok);
m.lastTok = tok;
m.pos += tok.getString().length();
m.exhaust(results, visited);
if (a instanceof ShiftAction) {
AssemblyParseMachine m = copy();
m.stack.push(((ShiftAction) a).newStateNum);
m.treeStack.push(tok);
m.lastTok = tok;
m.pos += tok.getString().length();
m.exhaust(results, visited);
}
else if (a instanceof ReduceAction) {
AssemblyProduction prod = ((ReduceAction) a).prod;
AssemblyParseBranch branch = new AssemblyParseBranch(parser.grammar, prod);
AssemblyParseMachine m = copy();
m.output.add(prod.getIndex());
for (@SuppressWarnings("unused")
AssemblySymbol sym : prod.getRHS()) {
m.stack.pop();
branch.addChild(m.treeStack.pop());
}
else if (a instanceof ReduceAction) {
AssemblyProduction prod = ((ReduceAction) a).prod;
AssemblyParseBranch branch = new AssemblyParseBranch(parser.grammar, prod);
AssemblyParseMachine m = copy();
m.output.add(prod.getIndex());
DBG.println("Prod: " + prod);
for (@SuppressWarnings("unused")
AssemblySymbol sym : prod.getRHS()) {
m.stack.pop();
branch.addChild(m.treeStack.pop());
}
for (Action aa : m.parser.actions.get(m.stack.peek(), prod.getLHS())) {
GotoAction ga = (GotoAction) aa;
DBG.println("Goto: " + ga);
AssemblyParseMachine n = m.copy();
n.stack.push(ga.newStateNum);
n.treeStack.push(branch);
n.exhaust(results, visited);
}
}
else if (a instanceof AcceptAction) {
AssemblyParseMachine m = copy();
m.accepted = true;
results.add(m);
for (Action aa : m.parser.actions.get(m.stack.peek(), prod.getLHS())) {
GotoAction ga = (GotoAction) aa;
AssemblyParseMachine n = m.copy();
n.stack.push(ga.newStateNum);
n.treeStack.push(branch);
n.exhaust(results, visited);
}
}
else if (a instanceof AcceptAction) {
AssemblyParseMachine m = copy();
m.accepted = true;
results.add(m);
}
}
/**
@ -271,13 +262,10 @@ public class AssemblyParseMachine implements Comparable<AssemblyParseMachine> {
*/
protected void consume(AssemblyTerminal t, AssemblyParseToken tok,
Set<AssemblyParseMachine> results, Deque<AssemblyParseMachine> visited) {
try (DbgCtx dc = DBG.start("Matched " + t + " " + tok)) {
Collection<Action> as = parser.actions.get(stack.peek(), t);
assert !as.isEmpty();
DBG.println("Actions: " + as);
for (Action a : as) {
doAction(a, tok, results, visited);
}
Collection<Action> as = parser.actions.get(stack.peek(), t);
assert !as.isEmpty();
for (Action a : as) {
doAction(a, tok, results, visited);
}
}
@ -320,54 +308,47 @@ public class AssemblyParseMachine implements Comparable<AssemblyParseMachine> {
* @param visited a collection of machine states already visited
*/
protected void exhaust(Set<AssemblyParseMachine> results, Deque<AssemblyParseMachine> visited) {
try (DbgCtx dc = DBG.start("Exhausting machine " + id)) {
DBG.println("Machine: " + this);
AssemblyParseMachine loop = findLoop(this, visited);
if (loop != null) {
DBG.println("Pruned. Loop of " + loop.id);
return;
AssemblyParseMachine loop = findLoop(this, visited);
if (loop != null) {
return;
}
try (DequePush<?> push = DequePush.push(visited, this)) {
if (error != ERROR_NONE) {
throw new AssertionError("INTERNAL: Tried to step a machine with errors");
}
try (DequePush<?> push = DequePush.push(visited, this)) {
if (error != ERROR_NONE) {
throw new AssertionError("INTERNAL: Tried to step a machine with errors");
if (accepted) {
// Gratuitous inputs should be detected by getTree
throw new AssertionError("INTERNAL: Tried to step an accepted machine");
}
Collection<AssemblyTerminal> terms = parser.actions.getExpected(stack.peek());
if (terms.isEmpty()) {
throw new RuntimeException("Encountered a state with no actions");
}
Set<AssemblyTerminal> unmatched = new TreeSet<>(terms);
for (AssemblyTerminal t : terms) {
for (AssemblyParseToken tok : t.match(buffer, pos, parser.grammar, symbols)) {
unmatched.remove(t);
assert buffer.regionMatches(pos, tok.getString(), 0,
tok.getString().length());
consume(t, tok, results, visited);
}
if (accepted) {
// Gratuitous inputs should be detected by getTree
throw new AssertionError("INTERNAL: Tried to step an accepted machine");
}
if (!unmatched.isEmpty()) {
AssemblyParseMachine m = copy();
final Collection<AssemblyTerminal> newExpected;
if (m.lastTok == null ||
!(m.lastTok instanceof TruncatedWhiteSpaceParseToken)) {
newExpected = unmatched;
}
Collection<AssemblyTerminal> terms = parser.actions.getExpected(stack.peek());
if (terms.isEmpty()) {
throw new RuntimeException("Encountered a state with no actions");
}
Set<AssemblyTerminal> unmatched = new TreeSet<>(terms);
for (AssemblyTerminal t : terms) {
for (AssemblyParseToken tok : t.match(buffer, pos, parser.grammar, symbols)) {
unmatched.remove(t);
assert buffer.regionMatches(pos, tok.getString(), 0,
tok.getString().length());
consume(t, tok, results, visited);
}
}
if (!unmatched.isEmpty()) {
AssemblyParseMachine m = copy();
final Collection<AssemblyTerminal> newExpected;
if (m.lastTok == null ||
!(m.lastTok instanceof TruncatedWhiteSpaceParseToken)) {
newExpected = unmatched;
}
else {
newExpected = new TreeSet<>();
newExpected.add(AssemblySentential.WHITE_SPACE);
}
DBG.println("Syntax Error: ");
DBG.println(" Expected: " + newExpected);
DBG.println(" Got: " + buffer.substring(pos));
m.error = ERROR_SYNTAX;
m.got = buffer.substring(pos);
m.expected = newExpected;
results.add(m);
return;
else {
newExpected = new TreeSet<>();
newExpected.add(AssemblySentential.WHITE_SPACE);
}
m.error = ERROR_SYNTAX;
m.got = buffer.substring(pos);
m.expected = newExpected;
results.add(m);
return;
}
}
}

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.
@ -24,8 +24,6 @@ import org.apache.commons.lang3.StringUtils;
import ghidra.app.plugin.assembler.sleigh.grammars.*;
import ghidra.app.plugin.assembler.sleigh.symbol.*;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.DbgCtx;
import ghidra.app.plugin.assembler.sleigh.util.TableEntry;
/**
@ -65,12 +63,6 @@ public class AssemblyParser {
// the LALR(1) Action/Goto table
protected AssemblyParseActionGotoTable actions;
/**
* Change this to {@link DbgTimer#ACTIVE} for verbose diagnostics
*/
protected static final DbgTimer DBG = DbgTimer.INACTIVE;
protected static final boolean DBG_DETAIL = false;
/**
* Construct a LALR(1) parser from the given grammar
*
@ -90,41 +82,11 @@ public class AssemblyParser {
grammar.addProduction(start, new AssemblySentential<>(grammar.getStart(), AssemblyEOI.EOI));
grammar.setStart(start);
try (DbgCtx dc = DBG.start("Computing First/Follow for General Grammar")) {
this.ff = new AssemblyFirstFollow(grammar);
if (DBG_DETAIL) {
printGeneralFF(DBG);
}
}
try (DbgCtx dc = DBG.start("Computing LR0 States and Transition Table")) {
buildLR0Machine();
if (DBG_DETAIL) {
printLR0States(DBG);
printLR0TransitionTable(DBG);
}
}
try (DbgCtx dc = DBG.start("Computing Extended Grammar")) {
buildExtendedGrammar();
if (DBG_DETAIL) {
printExtendedGrammar(DBG);
}
}
try (DbgCtx dc = DBG.start("Computing First/Follow for Extended Grammar")) {
this.extff = new AssemblyFirstFollow(extendedGrammar);
if (DBG_DETAIL) {
printExtendedFF(DBG);
}
}
try (DbgCtx dc = DBG.start("Computing Parse Table")) {
buildActionGotoTable();
if (DBG_DETAIL) {
printParseTable(DBG);
}
}
this.ff = new AssemblyFirstFollow(grammar);
buildLR0Machine();
buildExtendedGrammar();
this.extff = new AssemblyFirstFollow(extendedGrammar);
buildActionGotoTable();
}
protected void buildLR0Machine() {

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.
@ -19,13 +19,10 @@ import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
/**
* Base for a node in an assembly prototype
*/
public abstract class AbstractAssemblyState {
protected static final DbgTimer DBG = AbstractAssemblyTreeResolver.DBG;
protected final AbstractAssemblyTreeResolver<?> resolver;
protected final AbstractAssemblyResolutionFactory<?, ?> factory;

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.
@ -21,7 +21,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import ghidra.app.plugin.assembler.sleigh.tree.AssemblyParseTreeNode;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
/**
* Base class for generating prototype nodes ("states") from a parse tree node
@ -29,7 +28,6 @@ import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
* @param <N> the type of parse tree node to process
*/
public abstract class AbstractAssemblyStateGenerator<N extends AssemblyParseTreeNode> {
protected static final DbgTimer DBG = AbstractAssemblyTreeResolver.DBG;
/**
* Context to pass along as states are generated
@ -73,15 +71,6 @@ public abstract class AbstractAssemblyStateGenerator<N extends AssemblyParseTree
path.add(cons);
return new GeneratorContext(path, this.shift + shift);
}
/**
* Print a debug line
*
* @param string the message
*/
public void dbg(String string) {
DBG.println(pathToString(path) + ":" + string);
}
}
protected final AbstractAssemblyTreeResolver<?> resolver;

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.
@ -27,8 +27,6 @@ import ghidra.app.plugin.assembler.sleigh.sem.AbstractAssemblyStateGenerator.Gen
import ghidra.app.plugin.assembler.sleigh.sem.AssemblyResolutionResults.Applicator;
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyNonTerminal;
import ghidra.app.plugin.assembler.sleigh.tree.*;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.DbgCtx;
import ghidra.app.plugin.processors.sleigh.*;
import ghidra.app.plugin.processors.sleigh.symbol.*;
import ghidra.program.model.address.Address;
@ -45,11 +43,11 @@ import ghidra.program.model.mem.MemBuffer;
* attempts to determine possible encodings using the semantics associated with each branch of the
* given parse tree. Details of this process are described in {@link SleighAssemblerBuilder}.
*
* @param <RP> the type for resolved assembly patterns
* @see SleighAssemblerBuilder
*/
public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPatterns> {
protected static final RecursiveDescentSolver SOLVER = RecursiveDescentSolver.getSolver();
protected static final DbgTimer DBG = DbgTimer.INACTIVE;
public static final String INST_START = "inst_start";
public static final String INST_NEXT = "inst_next";
@ -67,7 +65,8 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
/**
* Construct a resolver for the given parse tree
*
* @param lang
* @param factory a factory for assembly results
* @param lang the language
* @param at the address where the instruction will start
* @param tree the parse tree
* @param context the context expected at {@code instStart}
@ -86,6 +85,9 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
this.ctxGraph = ctxGraph;
}
/**
* {@return the factory for assembly results}
*/
public AbstractAssemblyResolutionFactory<RP, ?> getFactory() {
return factory;
}
@ -104,15 +106,6 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
Stream<AssemblyGeneratedPrototype> protStream =
rootGen.generate(new GeneratorContext(List.of(), 0));
if (DBG == DbgTimer.ACTIVE) {
try (DbgCtx dc = DBG.start("Prototypes:")) {
protStream = protStream.map(prot -> {
DBG.println(prot);
return prot;
}).collect(Collectors.toList()).stream();
}
}
Stream<AssemblyResolvedPatterns> patStream =
protStream.map(p -> p.state).distinct().flatMap(s -> s.resolve(empty, errors));
@ -159,33 +152,28 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
if (rootRec == null) {
return temp;
}
try (DbgCtx dc = DBG.start("Resolving root recursion:")) {
AssemblyResolutionResults result = factory.newAssemblyResolutionResults();
AssemblyResolutionResults result = factory.newAssemblyResolutionResults();
for (AssemblyResolution ar : temp) {
if (ar.isError()) {
result.add(ar);
continue;
}
@SuppressWarnings("unchecked")
RP rp = (RP) ar;
AssemblyPatternBlock dst = rp.getContext();
// TODO: The desired context may need to be passed in. For now, just take start.
AssemblyPatternBlock src = context; // NOTE: This is only correct for "instruction"
String table = "instruction";
DBG.println("Finding paths from " + src + " to " + ar.lineToString());
Collection<Deque<AssemblyConstructorSemantic>> paths =
ctxGraph.computeOptimalApplications(src, table, dst, table);
DBG.println("Found " + paths.size());
for (Deque<AssemblyConstructorSemantic> path : paths) {
DBG.println(" " + path);
result.absorb(applyRecursionPath(path, tree, rootRec, ar));
}
for (AssemblyResolution ar : temp) {
if (ar.isError()) {
result.add(ar);
continue;
}
@SuppressWarnings("unchecked")
RP rp = (RP) ar;
AssemblyPatternBlock dst = rp.getContext();
// TODO: The desired context may need to be passed in. For now, just take start.
AssemblyPatternBlock src = context; // NOTE: This is only correct for "instruction"
String table = "instruction";
return result;
Collection<Deque<AssemblyConstructorSemantic>> paths =
ctxGraph.computeOptimalApplications(src, table, dst, table);
for (Deque<AssemblyConstructorSemantic> path : paths) {
result.absorb(applyRecursionPath(path, tree, rootRec, ar));
}
}
return result;
}
/**
@ -206,9 +194,7 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
vals.put(INST_NEXT, at.add(rp.getInstructionLength()).getAddressableWordOffset());
// inst_next2 use not really supported
vals.put(INST_NEXT2, at.add(rp.getInstructionLength()).getAddressableWordOffset());
DBG.println("Backfilling: " + rp);
AssemblyResolution ar = rp.backfill(SOLVER, vals);
DBG.println("Backfilled final: " + ar);
return ar;
}).apply(factory, rp -> {
if (rp.hasBackfills()) {
@ -364,11 +350,8 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
*/
protected AssemblyResolutionResults applyMutations(AssemblyConstructorSemantic sem,
AssemblyResolutionResults temp) {
DBG.println("Applying context mutations:");
return temp.apply(factory, rp -> {
DBG.println("Current: " + rp.lineToString());
AssemblyResolution backctx = sem.solveContextChanges(rp, vals);
DBG.println("Mutated: " + backctx.lineToString());
return backctx;
}).apply(factory, rp -> {
return rp.solveContextChangesForForbids(sem, vals);
@ -381,7 +364,6 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
*/
protected AssemblyResolutionResults applyPatterns(AssemblyConstructorSemantic sem, int shift,
AssemblyResolutionResults temp) {
DBG.println("Applying patterns:");
Collection<AssemblyResolution> patterns =
sem.getPatterns()
.stream()

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.
@ -142,8 +142,6 @@ public class AssemblyConstructState extends AbstractAssemblyState {
return sem.getPatterns()
.stream()
.map(pat -> {
DBG.println(path + ": Constructor pattern: " + pat.lineToString());
DBG.println(path + ": Current pattern: " + fromMutations.lineToString());
AssemblyResolvedPatterns combined = fromMutations.combine(pat.shift(shift));
//DBG.println("Combined pattern: " + combined);
return combined;

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.
@ -100,8 +100,6 @@ public class AssemblyConstructStateGenerator
Stream<AssemblyResolvedPatterns> applied = sem.applyPatternsForward(gc.shift, fromLeft)
.filter(pat -> {
if (pat == null) {
gc.dbg("Conflicting pattern. fromLeft=" + fromLeft + ",sem=" +
sem.getLocation());
return false;
}
return true;

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.
@ -20,7 +20,6 @@ import java.util.stream.Stream;
import ghidra.app.plugin.assembler.sleigh.expr.MaskedLong;
import ghidra.app.plugin.assembler.sleigh.expr.RecursiveDescentSolver;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.languages.sleigh.SleighLanguages;
import ghidra.app.plugin.languages.sleigh.SubtableEntryVisitor;
import ghidra.app.plugin.processors.sleigh.*;
@ -36,7 +35,6 @@ import ghidra.app.plugin.processors.sleigh.symbol.SubtableSymbol;
*/
public class AssemblyConstructorSemantic implements Comparable<AssemblyConstructorSemantic> {
protected static final RecursiveDescentSolver SOLVER = RecursiveDescentSolver.getSolver();
protected static final DbgTimer DBG = AbstractAssemblyTreeResolver.DBG;
protected final Set<AssemblyResolvedPatterns> patterns = new HashSet<>();
protected final AbstractAssemblyResolutionFactory<?, ?> factory;
@ -304,28 +302,22 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
Map<String, Long> vals) {
for (ContextChange chg : reversedChanges) {
if (chg instanceof ContextOp) {
DBG.println("Current: " + res.lineToString());
// This seems backwards. That's because we're going backwards.
// This is the "write" location for disassembly.
ContextOp cop = (ContextOp) chg;
DBG.println("Handling context change: " + cop);
// TODO: Is this res or subres?
MaskedLong reqval = res.readContextOp(cop);
if (reqval.equals(MaskedLong.UNKS)) {
DBG.println("Doesn't affect a current requirement");
continue; // this context change does not satisfy any requirement
}
DBG.println("'read' " + reqval);
// Remove the requirement that we just read before trying to solve
res = res.maskOut(cop);
DBG.println("Masked out: " + res.lineToString());
// Now, solve
AssemblyResolution sol = factory.solveOrBackfill(cop.getPatternExpression(), reqval,
vals, res, "Solution to " + cop);
DBG.println("Solution: " + sol.lineToString());
if (sol.isError()) {
AssemblyResolvedError err = (AssemblyResolvedError) sol;
return factory.error(err.getError(), res);
@ -344,7 +336,6 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
AssemblyResolvedBackfill solbf = (AssemblyResolvedBackfill) sol;
res = res.combine(solbf);
}
DBG.println("Combined: " + res.lineToString());
}
}
return res;
@ -381,14 +372,10 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
*
* @param shift the (right) shift in bytes to apply to the patterns before combining
* @param fromLeft the accumulated patterns from the left sibling or parent
* @return
* @return the stream of results
*/
public Stream<AssemblyResolvedPatterns> applyPatternsForward(int shift,
AssemblyResolvedPatterns fromLeft) {
if (patterns.isEmpty()) {
DBG.println("No patterns for " + getLocation() + "?" + "(hash=" +
System.identityHashCode(this) + ")");
}
return patterns.stream().map(pat -> fromLeft.combine(pat.shift(shift)));
}

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,7 +18,6 @@ package ghidra.app.plugin.assembler.sleigh.sem;
import java.math.BigInteger;
import java.util.List;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.*;
@ -38,8 +37,6 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
protected AssemblyPatternBlock curctx; // the pseudo context value
protected AssemblyPatternBlock defctx; // the computed default
protected final static DbgTimer dbg = DbgTimer.INACTIVE;
/**
* Compute the default context at most addresses for the given language
*
@ -110,17 +107,14 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
@Override
public void setValue(Register register, BigInteger value) throws ContextChangeException {
dbg.println("Set " + register + " to " + value);
}
@Override
public void setRegisterValue(RegisterValue value) throws ContextChangeException {
dbg.println("Set " + value);
}
@Override
public void clearRegister(Register register) throws ContextChangeException {
dbg.println("Clear " + register);
}
@Override
@ -165,12 +159,10 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
@Override
public void setFutureRegisterValue(Address address, RegisterValue value) {
dbg.println("Set " + value + " at " + address);
}
@Override
public void setFutureRegisterValue(Address fromAddr, Address toAddr, RegisterValue value) {
dbg.println("Set " + value + " for [" + fromAddr + ":" + toAddr + "]");
}
@Override
@ -182,8 +174,6 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
return;
}
defctx = defctx.combine(AssemblyPatternBlock.fromRegisterValue(registerValue));
dbg.println("Combining " + registerValue);
dbg.println(" " + defctx);
}
@Override

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.
@ -47,7 +47,6 @@ public class AssemblyNopStateGenerator
@Override
public Stream<AssemblyGeneratedPrototype> generate(GeneratorContext gc) {
gc.dbg("Generating NOP for " + opSym);
return Stream.of(new AssemblyGeneratedPrototype(
new AssemblyNopState(resolver, gc.path, gc.shift, opSym), fromLeft));
}

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.
@ -20,7 +20,6 @@ import java.util.stream.Stream;
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyNumericTerminal;
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyTerminal;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.DbgCtx;
import ghidra.app.plugin.processors.sleigh.ConstructState;
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
import ghidra.app.plugin.processors.sleigh.symbol.OperandSymbol;
@ -128,42 +127,37 @@ public class AssemblyOperandState extends AbstractAssemblyState {
if (symExp == null) {
symExp = opSym.getDefiningSymbol().getPatternExpression();
}
DBG.println("Equation: " + symExp + " = " + Long.toHexString(value));
String desc = "Solution to " + opSym + " in " + Long.toHexString(value) + " = " + symExp;
AssemblyResolution sol =
factory.solveOrBackfill(symExp, value, bitsize, resolver.vals, null, desc);
DBG.println("Solution: " + sol);
AssemblyResolution shifted = sol.shift(shift);
DBG.println("Shifted: " + shifted);
return shifted;
}
@Override
protected Stream<AssemblyResolvedPatterns> resolve(AssemblyResolvedPatterns fromRight,
Collection<AssemblyResolvedError> errors) {
try (DbgCtx dc = DBG.start("Resolving " + terminal)) {
AssemblyResolution sol = solveNumeric();
if (sol.isError()) {
errors.add((AssemblyResolvedError) sol);
return Stream.of();
}
if (sol.isBackfill()) {
AssemblyResolvedPatterns combined =
fromRight.combine((AssemblyResolvedBackfill) sol);
return Stream.of(combined.withRight(fromRight));
}
AssemblyResolution combined = fromRight.combine((AssemblyResolvedPatterns) sol);
if (combined == null) {
errors.add(factory.newErrorBuilder()
.error("Pattern/operand conflict")
.description("Resolving " + terminal)
.build());
return Stream.of();
}
AssemblyResolvedPatterns pats = (AssemblyResolvedPatterns) combined;
// Do not take constructor from right
return Stream.of(pats.withRight(fromRight).withConstructor(null));
AssemblyResolution sol = solveNumeric();
if (sol.isError()) {
errors.add((AssemblyResolvedError) sol);
return Stream.of();
}
if (sol.isBackfill()) {
AssemblyResolvedPatterns combined =
fromRight.combine((AssemblyResolvedBackfill) sol);
return Stream.of(combined.withRight(fromRight));
}
AssemblyResolution combined = fromRight.combine((AssemblyResolvedPatterns) sol);
if (combined == null) {
errors.add(factory.newErrorBuilder()
.error("Pattern/operand conflict")
.description("Resolving " + terminal)
.build());
return Stream.of();
}
AssemblyResolvedPatterns pats = (AssemblyResolvedPatterns) combined;
// Do not take constructor from right
return Stream.of(pats.withRight(fromRight).withConstructor(null));
}
public AssemblyTerminal getTerminal() {

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.
@ -21,8 +21,6 @@ import java.util.stream.Collectors;
import org.apache.commons.collections4.set.AbstractSetDecorator;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
/**
* A set of possible assembly resolutions for a single SLEIGH constructor
*
@ -34,7 +32,6 @@ import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
* encodings, including error records describing the pruned intermediate results.
*/
public class AssemblyResolutionResults extends AbstractSetDecorator<AssemblyResolution> {
protected static final DbgTimer DBG = AbstractAssemblyTreeResolver.DBG;
public interface Applicator {
Iterable<? extends AssemblyResolution> getPatterns(AssemblyResolvedPatterns cur);
@ -142,11 +139,8 @@ public class AssemblyResolutionResults extends AbstractSetDecorator<AssemblyReso
continue;
}
AssemblyResolvedPatterns rp = (AssemblyResolvedPatterns) res;
DBG.println("Current: " + rp.lineToString());
for (AssemblyResolution ar : applicator.getPatterns(rp)) {
DBG.println("Pattern: " + ar.lineToString());
AssemblyResolvedPatterns combined = applicator.combine(rp, ar);
DBG.println("Combined: " + (combined == null ? "(null)" : combined.lineToString()));
if (combined == null) {
results.add(factory.error(applicator.describeError(rp, ar), ar));
continue;

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.
@ -53,7 +53,6 @@ public class DefaultAssemblyResolvedError extends AbstractAssemblyResolution
String description, List<? extends AssemblyResolution> children,
AssemblyResolution right, String error) {
super(factory, description, children, right);
AbstractAssemblyTreeResolver.DBG.println(error);
this.error = error;
}

View file

@ -758,11 +758,9 @@ public class DefaultAssemblyResolvedPatterns extends AbstractAssemblyResolution
Set<Integer> printed =
Arrays.stream(cons.getOpsPrintOrder()).boxed().collect(Collectors.toSet());
if (!(opSym.getDefiningSymbol() instanceof SubtableSymbol)) {
AssemblyTreeResolver.DBG.println("Operand " + opSym + " is not a sub-table");
continue;
}
if (!printed.contains(opIdx)) {
AssemblyTreeResolver.DBG.println("Operand " + opSym + " is hidden");
continue;
}
AssemblyResolvedPatterns child = (AssemblyResolvedPatterns) children.get(opIdx);

View file

@ -1,261 +0,0 @@
/* ###
* 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.plugin.assembler.sleigh.util;
import java.io.*;
import java.util.Stack;
/**
* A debugging, timing, and diagnostic tool
*
* <p>
* TODO: I should probably remove this and rely on the Msg.trace() method, or at the very least,
* refactor this to use that.
*/
public class DbgTimer extends PrintStream {
// a stack of start times
Stack<Long> timeStack = new Stack<>();
/**
* Create a new debugging timer, wrapping the given output stream
*
* @param out the stream
*/
public DbgTimer(OutputStream out) {
super(new TabbingOutputStream(out));
TabbingOutputStream tos = (TabbingOutputStream) this.out;
tos.setTimeStack(timeStack);
}
/**
* Create a new debugging timer, wrapping standard out
*/
public DbgTimer() {
this(System.out);
}
/**
* A (rather slow) output stream that indents every line of its output
*/
public static class TabbingOutputStream extends OutputStream {
protected static final int STATE_NOLINE = 0;
protected static final int STATE_LINE = 1;
protected OutputStream out;
protected int state = STATE_NOLINE;
protected Stack<Long> timeStack;
/**
* Create a new stream wrapping another
*
* @param out the stream to wrap
*/
private TabbingOutputStream(OutputStream out) {
this.out = out;
}
/**
* Start a new (indented) line of output
*
* @throws IOException
*/
protected void startln() throws IOException {
for (@SuppressWarnings("unused")
Long l : timeStack) {
out.write(' ');
out.write(' ');
}
}
/**
* Workaround: Set the time stack reference
*
* @param timeStack the stack
*/
protected void setTimeStack(Stack<Long> timeStack) {
this.timeStack = timeStack;
}
/**
* {@inheritDoc}
*
* Parses each line and prepends the indentation as they are printed
*/
@Override
public void write(int b) throws IOException {
if (b == '\n' || b == '\r') {
out.write(b);
state = STATE_NOLINE;
}
else if (state == STATE_NOLINE) {
startln();
out.write(b);
state = STATE_LINE;
}
else {
out.write(b);
}
}
@Override
public void close() throws IOException {
if (out == System.out || out == System.err) {
out.flush(); // might as well
return;
}
try (OutputStream s = out) {
s.flush();
}
}
@Override
public void flush() throws IOException {
out.flush();
}
}
/** An instance that prints to standard out */
public static final DbgTimer ACTIVE = new DbgTimer();
/** An instance that prints to /dev/null */
public static final DbgTimer INACTIVE = new DbgTimer(new OutputStream() {
@Override
public void write(int b) throws IOException {
// This prevents inefficient squelching of debug messages. It is much better to squelch
// at the original print call (many overridden below). If one was missed, please
// override it too. Also see the TODO in the class documentation above.
throw new AssertionError("INTERNAL: Should not be here.");
}
}) {
@Override
public void print(String msg) {
// Nothing
}
@Override
public void println(String msg) {
// Nothing
}
@Override
public void println() {
// Nothing
}
@Override
public void print(Object msg) {
// Nothing
}
@Override
public void println(Object msg) {
// Nothing
}
@Override
public DbgCtx start(Object message) {
return null;
}
@Override
public void stop() {
// Nothing
}
};
/**
* Start a new, possibly long-running, task
*
* This is meant to be used idiomatically, as in a try-with-resources block:
*
* <pre>
* try (DbgCtx dc = dbg.start("Twiddling the frobs:")) {
* // do some classy twiddling
* } // this will automatically print done and the time elapsed within the try block
* </pre>
*
* This idiom is preferred because the task will be stopped even if an error occurs, if the
* method returns from within the block, etc.
*
* @param message the message to print when the task begins
* @return a context to close when the task ends
*
*/
public DbgCtx start(Object message) {
println(message);
flush();
timeStack.push(System.currentTimeMillis());
return new DbgCtx(this);
}
/**
* Stop the current task
*
* <p>
* This will print done and the elapsed time since the start of the task. The "current task" is
* determined from the stack.
*/
public void stop() {
long time = System.currentTimeMillis() - timeStack.pop();
flush();
println("Done after " + time + "ms");
}
/**
* Replace the wrapped output stream (usually temporarily)
*
* @see #resetOutputStream(TabbingOutputStream)
* @param s the replacement stream
* @return the original stream, wrapped in a tabbing stream
*/
public TabbingOutputStream setOutputStream(OutputStream s) {
flush();
TabbingOutputStream old = (TabbingOutputStream) this.out;
TabbingOutputStream tos = new TabbingOutputStream(s);
tos.setTimeStack(timeStack);
this.out = tos;
return old;
}
/**
* Put the original tabbing stream back
*
* @see #setOutputStream(OutputStream)
* @param s the original wrapped stream
* @return the replacement stream, wrapped in a tabbing stream
*/
public TabbingOutputStream resetOutputStream(TabbingOutputStream s) {
flush();
TabbingOutputStream old = (TabbingOutputStream) this.out;
this.out = s;
return old;
}
/**
* A context for idiomatic use of the {@link DbgTimer} in a try-with-resources block
*/
public static class DbgCtx implements AutoCloseable {
private DbgTimer dbg;
private DbgCtx(DbgTimer dbg) {
this.dbg = dbg;
}
@Override
public void close() {
dbg.stop();
}
}
}

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.
@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.assembler.sleigh;
import static org.junit.Assert.*;
import static org.junit.Assert.fail;
import java.util.*;
@ -25,10 +25,8 @@ import org.junit.Before;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.assembler.*;
import ghidra.app.plugin.assembler.sleigh.parse.*;
import ghidra.app.plugin.assembler.sleigh.parse.AssemblyParseResult;
import ghidra.app.plugin.assembler.sleigh.sem.*;
import ghidra.app.plugin.assembler.sleigh.tree.AssemblyParseTreeNode;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.processors.sleigh.SleighInstructionPrototype;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.util.PseudoInstruction;
@ -39,7 +37,6 @@ import ghidra.program.model.lang.*;
import ghidra.program.model.mem.*;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
/**
* A test for assembly of a particular SLEIGH language
@ -52,7 +49,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
// note: disable debug output in batch mode--over 15M of output to the test log
static final DbgTimer dbg = BATCH_MODE ? DbgTimer.INACTIVE : DbgTimer.ACTIVE;
static String setupLangID = "";
/**
@ -89,32 +85,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
return (SleighLanguage) languageService.getLanguage(langID);
}
/**
* Print a collection of parse trees to the debug printer
*
* @param trees the trees
*/
protected static void dbgPrintTrees(Collection<AssemblyParseResult> trees) {
dbg.println("Got " + trees.size() + " tree(s).");
Set<String> suggestions = new TreeSet<>();
for (AssemblyParseResult result : trees) {
if (!result.isError()) {
AssemblyParseAcceptResult acc = (AssemblyParseAcceptResult) result;
AssemblyParseTreeNode tree = acc.getTree();
tree.print(dbg);
}
else {
AssemblyParseErrorResult err = (AssemblyParseErrorResult) result;
dbg.println(err);
if (err.getBuffer().equals("")) {
suggestions.addAll(err.getSuggestions());
}
}
}
dbg.println("Proposals: " + suggestions);
}
/**
* Disassemble an instruction, presumably the result of assembly
*
@ -168,7 +138,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
*/
protected void checkOneCompat(String instr, AssemblyResolutionResults rr) {
AssemblyPatternBlock ins = AssemblyPatternBlock.fromString(instr);
dbg.println("Checking against: " + ins);
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess
Set<AssemblyResolvedPatterns> misses = new TreeSet<>();
for (AssemblyResolution ar : rr) {
@ -183,15 +152,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
}
misses.add(rescon);
}
dbg.println("Errors:");
for (AssemblyResolution ar : errs) {
dbg.println(ar.toString(" "));
}
dbg.println("Mismatches:");
for (AssemblyResolution ar : misses) {
dbg.println(ar.toString(" "));
}
fail("No result matched the desired instruction bytes");
}
@ -209,7 +169,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
Address address = lang.getDefaultSpace().getAddress(addr);
final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address)
: AssemblyPatternBlock.fromString(ctxstr)).fillMask();
dbg.println("Checking each: " + disassembly + " ctx:" + ctx);
boolean gotOne = false;
boolean failedOne = false;
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess.
@ -223,13 +182,10 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
}
AssemblyResolvedPatterns rp = (AssemblyResolvedPatterns) ar;
try {
dbg.println(" " + rp.lineToString());
for (byte[] ins : rp.possibleInsVals(ctx)) {
dbg.println(" " + NumericUtilities.convertBytesToString(ins));
PseudoInstruction pi = disassemble(addr, ins, ctx.getVals());
String cons = dumpConstructorTree(pi);
String dis = pi.toString();
dbg.println(" " + dis);
if (!disassembly.contains(dis.trim())) {
failedOne = true;
misTxtToCons.put(dis, cons);
@ -243,24 +199,9 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
}
}
if (failedOne) {
dbg.println("Disassembly Mismatches:");
for (String dis : misTxtToCons.keySet()) {
dbg.println(" " + dis);
for (String cons : misTxtToCons.get(dis)) {
for (AssemblyResolvedPatterns rc : misTxtConsToRes.get(dis + cons)) {
dbg.println(" d:" + cons);
dbg.println(" a:" + rc.dumpConstructorTree());
dbg.println(rc.toString(" "));
}
}
}
fail("At least one result did not disassemble to the given text");
}
if (!gotOne) {
dbg.println("Errors:");
for (AssemblyResolution ar : errs) {
dbg.println(ar.toString(" "));
}
fail("Did not get any matches");
}
}
@ -288,8 +229,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
if (ar.isError()) {
continue;
}
dbg.println("Got:");
dbg.println(ar.toString(" "));
fail("All results were expected to be errors");
}
}
@ -356,7 +295,7 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
@Override
public Collection<AssemblyParseResult> filterParse(
Collection<AssemblyParseResult> parse) throws AssemblySyntaxException {
dbgPrintTrees(parse);
AssemblyTestCase.dbgPrintTrees(parse);
if (checkAllSyntaxErrs) {
checkAllSyntaxErrs(parse);
}
@ -458,7 +397,7 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
}
/**
* Like {@link #assertOneCompatRestExact(String, String, String, long), except a context is
* Like {@link #assertOneCompatRestExact(String, String, long, String)}, except a context is
* given
*
* @param assembly the input assembly
@ -493,7 +432,7 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
}
/**
* Like {@link # assertAllSemanticErrors(String), but a context is given
* Like {@link #assertAllSemanticErrors(String)}, but a context is given
*
* @param assembly the input assembly
* @param ctxstr the context pattern for assembly

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.
@ -17,6 +17,8 @@ package ghidra.app.plugin.assembler.sleigh;
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.*;
import org.apache.commons.collections4.MultiValuedMap;
@ -28,9 +30,7 @@ import ghidra.app.plugin.assembler.*;
import ghidra.app.plugin.assembler.sleigh.parse.*;
import ghidra.app.plugin.assembler.sleigh.sem.*;
import ghidra.app.plugin.assembler.sleigh.tree.AssemblyParseTreeNode;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.processors.sleigh.*;
import ghidra.app.plugin.processors.sleigh.SleighDebugLogger.SleighDebugMode;
import ghidra.app.util.PseudoInstruction;
import ghidra.generic.util.datastruct.TreeSetValuedTreeMap;
import ghidra.program.model.address.Address;
@ -38,7 +38,6 @@ import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.lang.*;
import ghidra.program.model.mem.*;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
/**
* A test for assembly of a particular SLEIGH language
@ -52,7 +51,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
// note: disable debug output in batch mode--over 15M of output to the test log
static final DbgTimer dbg = BATCH_MODE ? DbgTimer.INACTIVE : DbgTimer.ACTIVE;
static String setupLangID = "";
/**
@ -91,24 +89,25 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
* @param trees the trees
*/
protected static void dbgPrintTrees(Collection<AssemblyParseResult> trees) {
dbg.println("Got " + trees.size() + " tree(s).");
Msg.trace(AssemblyTestCase.class, "Got " + trees.size() + " tree(s).");
Set<String> suggestions = new TreeSet<>();
for (AssemblyParseResult result : trees) {
if (!result.isError()) {
AssemblyParseAcceptResult acc = (AssemblyParseAcceptResult) result;
AssemblyParseTreeNode tree = acc.getTree();
tree.print(dbg);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
tree.print(new PrintStream(baos));
Msg.trace(AssemblyTestCase.class, baos.toByteArray());
}
else {
AssemblyParseErrorResult err = (AssemblyParseErrorResult) result;
dbg.println(err);
Msg.trace(AssemblyTestCase.class, err.toString());
if (err.getBuffer().equals("")) {
suggestions.addAll(err.getSuggestions());
}
}
}
dbg.println("Proposals: " + suggestions);
Msg.trace(AssemblyTestCase.class, "Proposals: " + suggestions);
}
/**
@ -129,12 +128,7 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
Address at = lang.getDefaultSpace().getAddress(addr);
context.setContextRegister(ctx);
MemBuffer buf = new ByteMemBufferImpl(at, ins, lang.isBigEndian());
SleighDebugLogger logger =
new SleighDebugLogger(buf, context, lang, SleighDebugMode.VERBOSE);
InstructionPrototype ip = lang.parse(buf, context, false);
if (VERBOSE_DIS) {
dbg.println("SleighLog:\n" + logger.toString());
}
return new PseudoInstruction(at, ip, buf, context);
}
@ -169,7 +163,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
*/
protected void checkOneCompat(String instr, AssemblyResolutionResults rr) {
AssemblyPatternBlock ins = AssemblyPatternBlock.fromString(instr);
dbg.println("Checking against: " + ins);
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess
Set<AssemblyResolvedPatterns> misses = new TreeSet<>();
for (AssemblyResolution ar : rr) {
@ -185,14 +178,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
misses.add(rescon);
}
dbg.println("Errors:");
for (AssemblyResolution ar : errs) {
dbg.println(ar.toString(" "));
}
dbg.println("Mismatches:");
for (AssemblyResolution ar : misses) {
dbg.println(ar.toString(" "));
}
fail("No result matched the desired instruction bytes");
}
@ -210,7 +195,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
Address address = lang.getDefaultSpace().getAddress(addr);
final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address)
: AssemblyPatternBlock.fromString(ctxstr)).fillMask();
dbg.println("Checking each: " + disassembly + " ctx:" + ctx);
boolean gotOne = false;
boolean failedOne = false;
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess.
@ -224,13 +208,10 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
}
AssemblyResolvedPatterns rcon = (AssemblyResolvedPatterns) ar;
try {
dbg.println(" " + rcon.lineToString());
for (byte[] ins : rcon.possibleInsVals(ctx)) {
dbg.println(" " + NumericUtilities.convertBytesToString(ins));
PseudoInstruction pi = disassemble(addr, ins, ctx.getVals());
String cons = dumpConstructorTree(pi);
String dis = pi.toString();
dbg.println(" " + dis);
if (!disassembly.contains(dis.trim())) {
failedOne = true;
misTxtToCons.put(dis, cons);
@ -244,24 +225,9 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
}
}
if (failedOne) {
dbg.println("Disassembly Mismatches:");
for (String dis : misTxtToCons.keySet()) {
dbg.println(" " + dis);
for (String cons : misTxtToCons.get(dis)) {
for (AssemblyResolvedPatterns rc : misTxtConsToRes.get(dis + cons)) {
dbg.println(" d:" + cons);
dbg.println(" a:" + rc.dumpConstructorTree());
dbg.println(rc.toString(" "));
}
}
}
fail("At least one result did not disassemble to the given text");
}
if (!gotOne) {
dbg.println("Errors:");
for (AssemblyResolution ar : errs) {
dbg.println(ar.toString(" "));
}
fail("Did not get any matches");
}
}
@ -289,8 +255,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
if (ar.isError()) {
continue;
}
dbg.println("Got:");
dbg.println(ar.toString(" "));
fail("All results were expected to be errors");
}
}
@ -459,7 +423,7 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
}
/**
* Like {@link #assertOneCompatRestExact(String, String, String, long), except a context is
* Like {@link #assertOneCompatRestExact(String, String, long, String)}, except a context is
* given
*
* @param assembly the input assembly
@ -494,7 +458,7 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
}
/**
* Like {@link # assertAllSemanticErrors(String), but a context is given
* Like {@link #assertAllSemanticErrors(String)}, but a context is given
*
* @param assembly the input assembly
* @param ctxstr the context pattern for assembly

View file

@ -1,42 +0,0 @@
/* ###
* 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.plugin.assembler.sleigh;
import org.junit.Test;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.DbgCtx;
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.TabbingOutputStream;
public class DbgTimerTest {
@Test
public void testDbgTimer() {
try (DbgTimer dbg = new DbgTimer()) {
dbg.println("The first line");
try (DbgCtx dc = dbg.start("First push")) {
dbg.println("An indented line");
}
dbg.println("The last line");
TabbingOutputStream old = dbg.setOutputStream(System.err);
dbg.println("The error line");
try (DbgCtx dc = dbg.start("Error push")) {
dbg.println("An indented error line");
}
dbg.println("The last error line");
dbg.resetOutputStream(old);
}
}
}