mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-5800: Delete asm debug logging altogether
This commit is contained in:
parent
3e50533187
commit
0e3beed22a
27 changed files with 235 additions and 821 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.
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue