mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +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
|
@ -24,7 +24,6 @@ import ghidra.app.plugin.assembler.sleigh.grammars.AssemblyGrammar;
|
||||||
import ghidra.app.plugin.assembler.sleigh.grammars.AssemblySentential;
|
import ghidra.app.plugin.assembler.sleigh.grammars.AssemblySentential;
|
||||||
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.symbol.*;
|
import ghidra.app.plugin.assembler.sleigh.symbol.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer.DbgCtx;
|
|
||||||
import ghidra.app.plugin.languages.sleigh.InputContextScraper;
|
import ghidra.app.plugin.languages.sleigh.InputContextScraper;
|
||||||
import ghidra.app.plugin.processors.sleigh.*;
|
import ghidra.app.plugin.processors.sleigh.*;
|
||||||
import ghidra.app.plugin.processors.sleigh.pattern.DisjointPattern;
|
import ghidra.app.plugin.processors.sleigh.pattern.DisjointPattern;
|
||||||
|
@ -72,10 +71,8 @@ public class WildSleighAssemblerBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void buildInputContexts() {
|
protected void buildInputContexts() {
|
||||||
try (DbgCtx dc = dbg.start("Building input contexts")) {
|
InputContextScraper scraper = new InputContextScraper(lang);
|
||||||
InputContextScraper scraper = new InputContextScraper(lang);
|
this.inputContexts = scraper.scrapeInputContexts();
|
||||||
this.inputContexts = scraper.scrapeInputContexts();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -39,7 +39,6 @@ public class WildAssemblyNopStateGenerator
|
||||||
public Stream<AssemblyGeneratedPrototype> generate(GeneratorContext gc) {
|
public Stream<AssemblyGeneratedPrototype> generate(GeneratorContext gc) {
|
||||||
// TODO: Do we want to restrict the values?
|
// TODO: Do we want to restrict the values?
|
||||||
// TODO: Is this the right place to generate "interesting values"?
|
// TODO: Is this the right place to generate "interesting values"?
|
||||||
gc.dbg("Generating WILD NOP for " + opSym);
|
|
||||||
return Stream.of(new AssemblyGeneratedPrototype(
|
return Stream.of(new AssemblyGeneratedPrototype(
|
||||||
new WildAssemblyNopState(resolver, gc.path, gc.shift, opSym, wildcard), fromLeft));
|
new WildAssemblyNopState(resolver, gc.path, gc.shift, opSym, wildcard), fromLeft));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.sem.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyNumericSymbols;
|
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyNumericSymbols;
|
||||||
import ghidra.app.plugin.assembler.sleigh.tree.AssemblyParseBranch;
|
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.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.framework.model.DomainObjectChangedEvent;
|
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||||
import ghidra.framework.model.DomainObjectListener;
|
import ghidra.framework.model.DomainObjectListener;
|
||||||
|
@ -43,7 +42,6 @@ import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public abstract class AbstractSleighAssembler<RP extends AssemblyResolvedPatterns>
|
public abstract class AbstractSleighAssembler<RP extends AssemblyResolvedPatterns>
|
||||||
implements GenericAssembler<RP> {
|
implements GenericAssembler<RP> {
|
||||||
protected static final DbgTimer dbg = DbgTimer.INACTIVE;
|
|
||||||
|
|
||||||
protected class ListenerForSymbolsRefresh implements DomainObjectListener {
|
protected class ListenerForSymbolsRefresh implements DomainObjectListener {
|
||||||
@Override
|
@Override
|
||||||
|
@ -150,7 +148,6 @@ public abstract class AbstractSleighAssembler<RP extends AssemblyResolvedPattern
|
||||||
for (String part : assembly) {
|
for (String part : assembly) {
|
||||||
for (String line : part.split("\n")) {
|
for (String line : part.split("\n")) {
|
||||||
RegisterValue rv = program.getProgramContext().getDisassemblyContext(at);
|
RegisterValue rv = program.getProgramContext().getDisassemblyContext(at);
|
||||||
dbg.println(rv);
|
|
||||||
AssemblyPatternBlock ctx = AssemblyPatternBlock.fromRegisterValue(rv);
|
AssemblyPatternBlock ctx = AssemblyPatternBlock.fromRegisterValue(rv);
|
||||||
ctx = ctx.fillMask();
|
ctx = ctx.fillMask();
|
||||||
byte[] insbytes = assembleLine(at, line, ctx);
|
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.parse.AssemblyParser;
|
||||||
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.symbol.*;
|
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.SleighLanguages;
|
||||||
import ghidra.app.plugin.languages.sleigh.SubtableEntryVisitor;
|
import ghidra.app.plugin.languages.sleigh.SubtableEntryVisitor;
|
||||||
import ghidra.app.plugin.processors.sleigh.*;
|
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.app.plugin.processors.sleigh.template.HandleTpl;
|
||||||
import ghidra.program.model.lang.LanguageID;
|
import ghidra.program.model.lang.LanguageID;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.SystemUtilities;
|
|
||||||
|
|
||||||
public abstract class AbstractSleighAssemblerBuilder< //
|
public abstract class AbstractSleighAssemblerBuilder< //
|
||||||
RP extends AssemblyResolvedPatterns, A extends GenericAssembler<RP>>
|
RP extends AssemblyResolvedPatterns, A extends GenericAssembler<RP>>
|
||||||
implements GenericAssemblerBuilder<RP, A> {
|
implements GenericAssemblerBuilder<RP, A> {
|
||||||
protected static final DbgTimer dbg =
|
|
||||||
SystemUtilities.isInTestingBatchMode() ? DbgTimer.INACTIVE : DbgTimer.ACTIVE;
|
|
||||||
|
|
||||||
protected final SleighLanguage lang;
|
protected final SleighLanguage lang;
|
||||||
protected final AbstractAssemblyResolutionFactory<RP, ?> factory;
|
protected final AbstractAssemblyResolutionFactory<RP, ?> factory;
|
||||||
|
@ -319,41 +314,39 @@ public abstract class AbstractSleighAssemblerBuilder< //
|
||||||
* Build the full grammar for the language
|
* Build the full grammar for the language
|
||||||
*/
|
*/
|
||||||
protected void buildGrammar() {
|
protected void buildGrammar() {
|
||||||
try (DbgCtx dc = dbg.start("Building grammar")) {
|
grammar = new AssemblyGrammar(factory);
|
||||||
grammar = new AssemblyGrammar(factory);
|
for (Symbol sym : lang.getSymbolTable().getSymbolList()) {
|
||||||
for (Symbol sym : lang.getSymbolTable().getSymbolList()) {
|
if (sym instanceof SubtableSymbol) {
|
||||||
if (sym instanceof SubtableSymbol) {
|
SubtableSymbol subtable = (SubtableSymbol) sym;
|
||||||
SubtableSymbol subtable = (SubtableSymbol) sym;
|
grammar.combine(buildSubGrammar(subtable));
|
||||||
grammar.combine(buildSubGrammar(subtable));
|
}
|
||||||
}
|
else if (sym instanceof VarnodeSymbol) {
|
||||||
else if (sym instanceof VarnodeSymbol) {
|
// Ignore. This just becomes a string terminal
|
||||||
// Ignore. This just becomes a string terminal
|
}
|
||||||
}
|
else if (sym instanceof StartSymbol) {
|
||||||
else if (sym instanceof StartSymbol) {
|
// Ignore. We handle inst_start in semantic processing
|
||||||
// Ignore. We handle inst_start in semantic processing
|
}
|
||||||
}
|
else if (sym instanceof EndSymbol) {
|
||||||
else if (sym instanceof EndSymbol) {
|
// Ignore. We handle inst_next in semantic processing
|
||||||
// Ignore. We handle inst_next in semantic processing
|
}
|
||||||
}
|
|
||||||
|
else if (sym instanceof Next2Symbol) {
|
||||||
else if (sym instanceof Next2Symbol) {
|
// Ignore. We handle inst_next2 in semantic processing
|
||||||
// Ignore. We handle inst_next2 in semantic processing
|
}
|
||||||
}
|
else if (sym instanceof UseropSymbol) {
|
||||||
else if (sym instanceof UseropSymbol) {
|
// Ignore. We don't do pcode.
|
||||||
// Ignore. We don't do pcode.
|
}
|
||||||
}
|
else if (sym instanceof OperandSymbol) {
|
||||||
else if (sym instanceof OperandSymbol) {
|
// Ignore. These are terminals, or will be produced by their defining symbols
|
||||||
// Ignore. These are terminals, or will be produced by their defining symbols
|
}
|
||||||
}
|
else if (sym instanceof ValueSymbol) {
|
||||||
else if (sym instanceof ValueSymbol) {
|
// Ignore. These are now terminals
|
||||||
// Ignore. These are now terminals
|
}
|
||||||
}
|
else {
|
||||||
else {
|
throw new RuntimeException("Unexpected type: " + sym.getClass());
|
||||||
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
|
* Build the context transition graph for the language
|
||||||
*/
|
*/
|
||||||
protected void buildContextGraph() {
|
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
|
* Build the parser for the language
|
||||||
*/
|
*/
|
||||||
protected void buildParser() {
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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);
|
MaskedLong rval = solver.getValue(exp.getRight(), vals, cur);
|
||||||
|
|
||||||
if (lval != null && !lval.isFullyDefined()) {
|
if (lval != null && !lval.isFullyDefined()) {
|
||||||
if (!lval.isFullyUndefined()) {
|
|
||||||
dbg.println("Partially-defined left value for binary solver: " + lval);
|
|
||||||
}
|
|
||||||
lval = null;
|
lval = null;
|
||||||
}
|
}
|
||||||
if (rval != null && !rval.isFullyDefined()) {
|
if (rval != null && !rval.isFullyDefined()) {
|
||||||
if (!rval.isFullyUndefined()) {
|
|
||||||
dbg.println("Partially-defined right value for binary solver: " + rval);
|
|
||||||
}
|
|
||||||
rval = null;
|
rval = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +74,6 @@ public abstract class AbstractBinaryExpressionSolver<T extends BinaryExpression>
|
||||||
return factory.newErrorBuilder().error(e.getMessage()).description(description).build();
|
return factory.newErrorBuilder().error(e.getMessage()).description(description).build();
|
||||||
}
|
}
|
||||||
catch (AssertionError e) {
|
catch (AssertionError e) {
|
||||||
dbg.println("While solving: " + exp + " (" + description + ")");
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -19,7 +19,6 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
|
|
||||||
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
|
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,8 +30,6 @@ public abstract class AbstractExpressionSolver<T extends PatternExpression> {
|
||||||
private Class<T> tcls;
|
private Class<T> tcls;
|
||||||
protected RecursiveDescentSolver solver;
|
protected RecursiveDescentSolver solver;
|
||||||
|
|
||||||
protected final DbgTimer dbg = DbgTimer.INACTIVE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a solver that can solve expression of the given type
|
* 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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); }
|
* AssemblyResolvedConstructor.error(e.getMessage(), description, null); }
|
||||||
*/
|
*/
|
||||||
catch (AssertionError e) {
|
catch (AssertionError e) {
|
||||||
dbg.println("While solving: " + exp + " (" + description + ")");
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.expr.match.ExpressionMatcher;
|
||||||
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
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.app.plugin.processors.sleigh.expression.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
@ -70,31 +69,26 @@ public class OrExpressionSolver extends AbstractBinaryExpressionSolver<OrExpress
|
||||||
long lo = 0;
|
long lo = 0;
|
||||||
PatternExpression fieldExp = null;
|
PatternExpression fieldExp = null;
|
||||||
AssemblyResolvedPatterns result = factory.nop(description);
|
AssemblyResolvedPatterns result = factory.nop(description);
|
||||||
try (DbgCtx dc = dbg.start("Trying solution of field catenation")) {
|
for (Map.Entry<Long, PatternExpression> ent : fields.entrySet()) {
|
||||||
dbg.println("Original: " + goal + ":= " + exp);
|
long hi = ent.getKey();
|
||||||
for (Map.Entry<Long, PatternExpression> ent : fields.entrySet()) {
|
if (hi == 0) {
|
||||||
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;
|
|
||||||
fieldExp = ent.getValue();
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -166,8 +160,6 @@ public class OrExpressionSolver extends AbstractBinaryExpressionSolver<OrExpress
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, I know it's a circular shift
|
// 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,
|
return solveLeftCircularShift(factory, expValu1, expShift, size, dir, goal, vals, cur,
|
||||||
hints, description);
|
hints, description);
|
||||||
}
|
}
|
||||||
|
@ -181,15 +173,9 @@ public class OrExpressionSolver extends AbstractBinaryExpressionSolver<OrExpress
|
||||||
MaskedLong valShift = solver.getValue(expShift, vals, cur);
|
MaskedLong valShift = solver.getValue(expShift, vals, cur);
|
||||||
|
|
||||||
if (valValue != null && !valValue.isFullyDefined()) {
|
if (valValue != null && !valValue.isFullyDefined()) {
|
||||||
if (!valValue.isFullyUndefined()) {
|
|
||||||
dbg.println("Partially-defined f for left circular shift solver: " + valValue);
|
|
||||||
}
|
|
||||||
valValue = null;
|
valValue = null;
|
||||||
}
|
}
|
||||||
if (valShift != null && valShift.isFullyDefined()) {
|
if (valShift != null && valShift.isFullyDefined()) {
|
||||||
if (!valShift.isFullyUndefined()) {
|
|
||||||
dbg.println("Partially-defined g for left circular shift solver: " + valShift);
|
|
||||||
}
|
|
||||||
valShift = null;
|
valShift = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,16 +264,14 @@ public class OrExpressionSolver extends AbstractBinaryExpressionSolver<OrExpress
|
||||||
return tryCatenationExpression(factory, exp, goal, vals, cur, hints, description);
|
return tryCatenationExpression(factory, exp, goal, vals, cur, hints, description);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
dbg.println("while solving: " + goal + "=:" + exp);
|
// Will be reported later
|
||||||
dbg.println(e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return tryCircularShiftExpression(factory, exp, goal, vals, cur, hints, description);
|
return tryCircularShiftExpression(factory, exp, goal, vals, cur, hints, description);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
dbg.println("while solving: " + goal + "=:" + exp);
|
// Will be reported later
|
||||||
dbg.println(e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<ExpressionMatcher<?>, PatternExpression> match = MATCHERS.neqConst.match(exp);
|
Map<ExpressionMatcher<?>, PatternExpression> match = MATCHERS.neqConst.match(exp);
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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 java.util.*;
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
|
|
||||||
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
|
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,7 +38,6 @@ import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
|
||||||
* {@link PatternExpression}.
|
* {@link PatternExpression}.
|
||||||
*/
|
*/
|
||||||
public class RecursiveDescentSolver {
|
public class RecursiveDescentSolver {
|
||||||
protected static final DbgTimer DBG = DbgTimer.INACTIVE;
|
|
||||||
private static final RecursiveDescentSolver INSTANCE = new RecursiveDescentSolver();
|
private static final RecursiveDescentSolver INSTANCE = new RecursiveDescentSolver();
|
||||||
|
|
||||||
// A mapping from each subclass of PatternExpression to the appropriate solver
|
// 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,
|
PatternExpression exp, MaskedLong goal, Map<String, Long> vals,
|
||||||
AssemblyResolvedPatterns cur, Set<SolverHint> hints, String description)
|
AssemblyResolvedPatterns cur, Set<SolverHint> hints, String description)
|
||||||
throws NeedsBackfillException {
|
throws NeedsBackfillException {
|
||||||
try {
|
return getRegistered(exp.getClass()).solve(factory, exp, goal, vals, cur, hints,
|
||||||
return getRegistered(exp.getClass()).solve(factory, exp, goal, vals, cur, hints,
|
description);
|
||||||
description);
|
|
||||||
}
|
|
||||||
catch (UnsupportedOperationException e) {
|
|
||||||
DBG.println("Error solving " + exp + " = " + goal);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,7 +162,6 @@ public class RecursiveDescentSolver {
|
||||||
protected <T extends PatternExpression> MaskedLong getValue(T exp, Map<String, Long> vals,
|
protected <T extends PatternExpression> MaskedLong getValue(T exp, Map<String, Long> vals,
|
||||||
AssemblyResolvedPatterns cur) throws NeedsBackfillException {
|
AssemblyResolvedPatterns cur) throws NeedsBackfillException {
|
||||||
MaskedLong value = getRegistered(exp.getClass()).getValue(exp, vals, cur);
|
MaskedLong value = getRegistered(exp.getClass()).getValue(exp, vals, cur);
|
||||||
DBG.println("Expression: " + value + " =: " + exp);
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.symbol.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.tree.*;
|
import ghidra.app.plugin.assembler.sleigh.tree.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.util.AsmUtil;
|
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
|
* A class that implements the LALR(1) parsing algorithm
|
||||||
|
@ -75,8 +73,6 @@ public class AssemblyParseMachine implements Comparable<AssemblyParseMachine> {
|
||||||
|
|
||||||
static int nextMachineId = 0;
|
static int nextMachineId = 0;
|
||||||
|
|
||||||
static final DbgTimer DBG = DbgTimer.INACTIVE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new parse state
|
* Construct a new parse state
|
||||||
*
|
*
|
||||||
|
@ -206,7 +202,6 @@ public class AssemblyParseMachine implements Comparable<AssemblyParseMachine> {
|
||||||
c.accepted = accepted;
|
c.accepted = accepted;
|
||||||
c.error = error;
|
c.error = error;
|
||||||
|
|
||||||
DBG.println("Copied " + id + " to " + c.id);
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,41 +219,37 @@ public class AssemblyParseMachine implements Comparable<AssemblyParseMachine> {
|
||||||
*/
|
*/
|
||||||
protected void doAction(Action a, AssemblyParseToken tok, Set<AssemblyParseMachine> results,
|
protected void doAction(Action a, AssemblyParseToken tok, Set<AssemblyParseMachine> results,
|
||||||
Deque<AssemblyParseMachine> visited) {
|
Deque<AssemblyParseMachine> visited) {
|
||||||
try (DbgCtx dc = DBG.start("Action: " + a)) {
|
if (a instanceof ShiftAction) {
|
||||||
if (a instanceof ShiftAction) {
|
AssemblyParseMachine m = copy();
|
||||||
AssemblyParseMachine m = copy();
|
m.stack.push(((ShiftAction) a).newStateNum);
|
||||||
m.stack.push(((ShiftAction) a).newStateNum);
|
m.treeStack.push(tok);
|
||||||
m.treeStack.push(tok);
|
m.lastTok = tok;
|
||||||
m.lastTok = tok;
|
m.pos += tok.getString().length();
|
||||||
m.pos += tok.getString().length();
|
m.exhaust(results, visited);
|
||||||
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) {
|
for (Action aa : m.parser.actions.get(m.stack.peek(), prod.getLHS())) {
|
||||||
AssemblyProduction prod = ((ReduceAction) a).prod;
|
GotoAction ga = (GotoAction) aa;
|
||||||
AssemblyParseBranch branch = new AssemblyParseBranch(parser.grammar, prod);
|
AssemblyParseMachine n = m.copy();
|
||||||
AssemblyParseMachine m = copy();
|
n.stack.push(ga.newStateNum);
|
||||||
m.output.add(prod.getIndex());
|
n.treeStack.push(branch);
|
||||||
DBG.println("Prod: " + prod);
|
n.exhaust(results, visited);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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,
|
protected void consume(AssemblyTerminal t, AssemblyParseToken tok,
|
||||||
Set<AssemblyParseMachine> results, Deque<AssemblyParseMachine> visited) {
|
Set<AssemblyParseMachine> results, Deque<AssemblyParseMachine> visited) {
|
||||||
try (DbgCtx dc = DBG.start("Matched " + t + " " + tok)) {
|
Collection<Action> as = parser.actions.get(stack.peek(), t);
|
||||||
Collection<Action> as = parser.actions.get(stack.peek(), t);
|
assert !as.isEmpty();
|
||||||
assert !as.isEmpty();
|
for (Action a : as) {
|
||||||
DBG.println("Actions: " + as);
|
doAction(a, tok, results, visited);
|
||||||
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
|
* @param visited a collection of machine states already visited
|
||||||
*/
|
*/
|
||||||
protected void exhaust(Set<AssemblyParseMachine> results, Deque<AssemblyParseMachine> visited) {
|
protected void exhaust(Set<AssemblyParseMachine> results, Deque<AssemblyParseMachine> visited) {
|
||||||
try (DbgCtx dc = DBG.start("Exhausting machine " + id)) {
|
AssemblyParseMachine loop = findLoop(this, visited);
|
||||||
DBG.println("Machine: " + this);
|
if (loop != null) {
|
||||||
AssemblyParseMachine loop = findLoop(this, visited);
|
return;
|
||||||
if (loop != null) {
|
}
|
||||||
DBG.println("Pruned. Loop of " + loop.id);
|
try (DequePush<?> push = DequePush.push(visited, this)) {
|
||||||
return;
|
if (error != ERROR_NONE) {
|
||||||
|
throw new AssertionError("INTERNAL: Tried to step a machine with errors");
|
||||||
}
|
}
|
||||||
try (DequePush<?> push = DequePush.push(visited, this)) {
|
if (accepted) {
|
||||||
if (error != ERROR_NONE) {
|
// Gratuitous inputs should be detected by getTree
|
||||||
throw new AssertionError("INTERNAL: Tried to step a machine with errors");
|
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
|
if (!unmatched.isEmpty()) {
|
||||||
throw new AssertionError("INTERNAL: Tried to step an accepted machine");
|
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());
|
else {
|
||||||
if (terms.isEmpty()) {
|
newExpected = new TreeSet<>();
|
||||||
throw new RuntimeException("Encountered a state with no actions");
|
newExpected.add(AssemblySentential.WHITE_SPACE);
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.grammars.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.symbol.*;
|
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;
|
import ghidra.app.plugin.assembler.sleigh.util.TableEntry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,12 +63,6 @@ public class AssemblyParser {
|
||||||
// the LALR(1) Action/Goto table
|
// the LALR(1) Action/Goto table
|
||||||
protected AssemblyParseActionGotoTable actions;
|
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
|
* 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.addProduction(start, new AssemblySentential<>(grammar.getStart(), AssemblyEOI.EOI));
|
||||||
grammar.setStart(start);
|
grammar.setStart(start);
|
||||||
|
|
||||||
try (DbgCtx dc = DBG.start("Computing First/Follow for General Grammar")) {
|
this.ff = new AssemblyFirstFollow(grammar);
|
||||||
this.ff = new AssemblyFirstFollow(grammar);
|
buildLR0Machine();
|
||||||
if (DBG_DETAIL) {
|
buildExtendedGrammar();
|
||||||
printGeneralFF(DBG);
|
this.extff = new AssemblyFirstFollow(extendedGrammar);
|
||||||
}
|
buildActionGotoTable();
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void buildLR0Machine() {
|
protected void buildLR0Machine() {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base for a node in an assembly prototype
|
* Base for a node in an assembly prototype
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAssemblyState {
|
public abstract class AbstractAssemblyState {
|
||||||
protected static final DbgTimer DBG = AbstractAssemblyTreeResolver.DBG;
|
|
||||||
|
|
||||||
protected final AbstractAssemblyTreeResolver<?> resolver;
|
protected final AbstractAssemblyTreeResolver<?> resolver;
|
||||||
protected final AbstractAssemblyResolutionFactory<?, ?> factory;
|
protected final AbstractAssemblyResolutionFactory<?, ?> factory;
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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 java.util.stream.Stream;
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.sleigh.tree.AssemblyParseTreeNode;
|
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
|
* 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
|
* @param <N> the type of parse tree node to process
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAssemblyStateGenerator<N extends AssemblyParseTreeNode> {
|
public abstract class AbstractAssemblyStateGenerator<N extends AssemblyParseTreeNode> {
|
||||||
protected static final DbgTimer DBG = AbstractAssemblyTreeResolver.DBG;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context to pass along as states are generated
|
* Context to pass along as states are generated
|
||||||
|
@ -73,15 +71,6 @@ public abstract class AbstractAssemblyStateGenerator<N extends AssemblyParseTree
|
||||||
path.add(cons);
|
path.add(cons);
|
||||||
return new GeneratorContext(path, this.shift + shift);
|
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;
|
protected final AbstractAssemblyTreeResolver<?> resolver;
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.sem.AssemblyResolutionResults.Applicator;
|
||||||
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyNonTerminal;
|
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyNonTerminal;
|
||||||
import ghidra.app.plugin.assembler.sleigh.tree.*;
|
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.*;
|
||||||
import ghidra.app.plugin.processors.sleigh.symbol.*;
|
import ghidra.app.plugin.processors.sleigh.symbol.*;
|
||||||
import ghidra.program.model.address.Address;
|
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
|
* 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}.
|
* given parse tree. Details of this process are described in {@link SleighAssemblerBuilder}.
|
||||||
*
|
*
|
||||||
|
* @param <RP> the type for resolved assembly patterns
|
||||||
* @see SleighAssemblerBuilder
|
* @see SleighAssemblerBuilder
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPatterns> {
|
public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPatterns> {
|
||||||
protected static final RecursiveDescentSolver SOLVER = RecursiveDescentSolver.getSolver();
|
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_START = "inst_start";
|
||||||
public static final String INST_NEXT = "inst_next";
|
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
|
* 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 at the address where the instruction will start
|
||||||
* @param tree the parse tree
|
* @param tree the parse tree
|
||||||
* @param context the context expected at {@code instStart}
|
* @param context the context expected at {@code instStart}
|
||||||
|
@ -86,6 +85,9 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
|
||||||
this.ctxGraph = ctxGraph;
|
this.ctxGraph = ctxGraph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the factory for assembly results}
|
||||||
|
*/
|
||||||
public AbstractAssemblyResolutionFactory<RP, ?> getFactory() {
|
public AbstractAssemblyResolutionFactory<RP, ?> getFactory() {
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
@ -104,15 +106,6 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
|
||||||
Stream<AssemblyGeneratedPrototype> protStream =
|
Stream<AssemblyGeneratedPrototype> protStream =
|
||||||
rootGen.generate(new GeneratorContext(List.of(), 0));
|
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 =
|
Stream<AssemblyResolvedPatterns> patStream =
|
||||||
protStream.map(p -> p.state).distinct().flatMap(s -> s.resolve(empty, errors));
|
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) {
|
if (rootRec == null) {
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
try (DbgCtx dc = DBG.start("Resolving root recursion:")) {
|
AssemblyResolutionResults result = factory.newAssemblyResolutionResults();
|
||||||
AssemblyResolutionResults result = factory.newAssemblyResolutionResults();
|
|
||||||
|
|
||||||
for (AssemblyResolution ar : temp) {
|
for (AssemblyResolution ar : temp) {
|
||||||
if (ar.isError()) {
|
if (ar.isError()) {
|
||||||
result.add(ar);
|
result.add(ar);
|
||||||
continue;
|
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@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());
|
vals.put(INST_NEXT, at.add(rp.getInstructionLength()).getAddressableWordOffset());
|
||||||
// inst_next2 use not really supported
|
// inst_next2 use not really supported
|
||||||
vals.put(INST_NEXT2, at.add(rp.getInstructionLength()).getAddressableWordOffset());
|
vals.put(INST_NEXT2, at.add(rp.getInstructionLength()).getAddressableWordOffset());
|
||||||
DBG.println("Backfilling: " + rp);
|
|
||||||
AssemblyResolution ar = rp.backfill(SOLVER, vals);
|
AssemblyResolution ar = rp.backfill(SOLVER, vals);
|
||||||
DBG.println("Backfilled final: " + ar);
|
|
||||||
return ar;
|
return ar;
|
||||||
}).apply(factory, rp -> {
|
}).apply(factory, rp -> {
|
||||||
if (rp.hasBackfills()) {
|
if (rp.hasBackfills()) {
|
||||||
|
@ -364,11 +350,8 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
|
||||||
*/
|
*/
|
||||||
protected AssemblyResolutionResults applyMutations(AssemblyConstructorSemantic sem,
|
protected AssemblyResolutionResults applyMutations(AssemblyConstructorSemantic sem,
|
||||||
AssemblyResolutionResults temp) {
|
AssemblyResolutionResults temp) {
|
||||||
DBG.println("Applying context mutations:");
|
|
||||||
return temp.apply(factory, rp -> {
|
return temp.apply(factory, rp -> {
|
||||||
DBG.println("Current: " + rp.lineToString());
|
|
||||||
AssemblyResolution backctx = sem.solveContextChanges(rp, vals);
|
AssemblyResolution backctx = sem.solveContextChanges(rp, vals);
|
||||||
DBG.println("Mutated: " + backctx.lineToString());
|
|
||||||
return backctx;
|
return backctx;
|
||||||
}).apply(factory, rp -> {
|
}).apply(factory, rp -> {
|
||||||
return rp.solveContextChangesForForbids(sem, vals);
|
return rp.solveContextChangesForForbids(sem, vals);
|
||||||
|
@ -381,7 +364,6 @@ public abstract class AbstractAssemblyTreeResolver<RP extends AssemblyResolvedPa
|
||||||
*/
|
*/
|
||||||
protected AssemblyResolutionResults applyPatterns(AssemblyConstructorSemantic sem, int shift,
|
protected AssemblyResolutionResults applyPatterns(AssemblyConstructorSemantic sem, int shift,
|
||||||
AssemblyResolutionResults temp) {
|
AssemblyResolutionResults temp) {
|
||||||
DBG.println("Applying patterns:");
|
|
||||||
Collection<AssemblyResolution> patterns =
|
Collection<AssemblyResolution> patterns =
|
||||||
sem.getPatterns()
|
sem.getPatterns()
|
||||||
.stream()
|
.stream()
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -142,8 +142,6 @@ public class AssemblyConstructState extends AbstractAssemblyState {
|
||||||
return sem.getPatterns()
|
return sem.getPatterns()
|
||||||
.stream()
|
.stream()
|
||||||
.map(pat -> {
|
.map(pat -> {
|
||||||
DBG.println(path + ": Constructor pattern: " + pat.lineToString());
|
|
||||||
DBG.println(path + ": Current pattern: " + fromMutations.lineToString());
|
|
||||||
AssemblyResolvedPatterns combined = fromMutations.combine(pat.shift(shift));
|
AssemblyResolvedPatterns combined = fromMutations.combine(pat.shift(shift));
|
||||||
//DBG.println("Combined pattern: " + combined);
|
//DBG.println("Combined pattern: " + combined);
|
||||||
return combined;
|
return combined;
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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)
|
Stream<AssemblyResolvedPatterns> applied = sem.applyPatternsForward(gc.shift, fromLeft)
|
||||||
.filter(pat -> {
|
.filter(pat -> {
|
||||||
if (pat == null) {
|
if (pat == null) {
|
||||||
gc.dbg("Conflicting pattern. fromLeft=" + fromLeft + ",sem=" +
|
|
||||||
sem.getLocation());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.MaskedLong;
|
||||||
import ghidra.app.plugin.assembler.sleigh.expr.RecursiveDescentSolver;
|
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.SleighLanguages;
|
||||||
import ghidra.app.plugin.languages.sleigh.SubtableEntryVisitor;
|
import ghidra.app.plugin.languages.sleigh.SubtableEntryVisitor;
|
||||||
import ghidra.app.plugin.processors.sleigh.*;
|
import ghidra.app.plugin.processors.sleigh.*;
|
||||||
|
@ -36,7 +35,6 @@ import ghidra.app.plugin.processors.sleigh.symbol.SubtableSymbol;
|
||||||
*/
|
*/
|
||||||
public class AssemblyConstructorSemantic implements Comparable<AssemblyConstructorSemantic> {
|
public class AssemblyConstructorSemantic implements Comparable<AssemblyConstructorSemantic> {
|
||||||
protected static final RecursiveDescentSolver SOLVER = RecursiveDescentSolver.getSolver();
|
protected static final RecursiveDescentSolver SOLVER = RecursiveDescentSolver.getSolver();
|
||||||
protected static final DbgTimer DBG = AbstractAssemblyTreeResolver.DBG;
|
|
||||||
|
|
||||||
protected final Set<AssemblyResolvedPatterns> patterns = new HashSet<>();
|
protected final Set<AssemblyResolvedPatterns> patterns = new HashSet<>();
|
||||||
protected final AbstractAssemblyResolutionFactory<?, ?> factory;
|
protected final AbstractAssemblyResolutionFactory<?, ?> factory;
|
||||||
|
@ -304,28 +302,22 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||||
Map<String, Long> vals) {
|
Map<String, Long> vals) {
|
||||||
for (ContextChange chg : reversedChanges) {
|
for (ContextChange chg : reversedChanges) {
|
||||||
if (chg instanceof ContextOp) {
|
if (chg instanceof ContextOp) {
|
||||||
DBG.println("Current: " + res.lineToString());
|
|
||||||
// This seems backwards. That's because we're going backwards.
|
// This seems backwards. That's because we're going backwards.
|
||||||
// This is the "write" location for disassembly.
|
// This is the "write" location for disassembly.
|
||||||
ContextOp cop = (ContextOp) chg;
|
ContextOp cop = (ContextOp) chg;
|
||||||
DBG.println("Handling context change: " + cop);
|
|
||||||
|
|
||||||
// TODO: Is this res or subres?
|
// TODO: Is this res or subres?
|
||||||
MaskedLong reqval = res.readContextOp(cop);
|
MaskedLong reqval = res.readContextOp(cop);
|
||||||
if (reqval.equals(MaskedLong.UNKS)) {
|
if (reqval.equals(MaskedLong.UNKS)) {
|
||||||
DBG.println("Doesn't affect a current requirement");
|
|
||||||
continue; // this context change does not satisfy any 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
|
// Remove the requirement that we just read before trying to solve
|
||||||
res = res.maskOut(cop);
|
res = res.maskOut(cop);
|
||||||
DBG.println("Masked out: " + res.lineToString());
|
|
||||||
|
|
||||||
// Now, solve
|
// Now, solve
|
||||||
AssemblyResolution sol = factory.solveOrBackfill(cop.getPatternExpression(), reqval,
|
AssemblyResolution sol = factory.solveOrBackfill(cop.getPatternExpression(), reqval,
|
||||||
vals, res, "Solution to " + cop);
|
vals, res, "Solution to " + cop);
|
||||||
DBG.println("Solution: " + sol.lineToString());
|
|
||||||
if (sol.isError()) {
|
if (sol.isError()) {
|
||||||
AssemblyResolvedError err = (AssemblyResolvedError) sol;
|
AssemblyResolvedError err = (AssemblyResolvedError) sol;
|
||||||
return factory.error(err.getError(), res);
|
return factory.error(err.getError(), res);
|
||||||
|
@ -344,7 +336,6 @@ public class AssemblyConstructorSemantic implements Comparable<AssemblyConstruct
|
||||||
AssemblyResolvedBackfill solbf = (AssemblyResolvedBackfill) sol;
|
AssemblyResolvedBackfill solbf = (AssemblyResolvedBackfill) sol;
|
||||||
res = res.combine(solbf);
|
res = res.combine(solbf);
|
||||||
}
|
}
|
||||||
DBG.println("Combined: " + res.lineToString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
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 shift the (right) shift in bytes to apply to the patterns before combining
|
||||||
* @param fromLeft the accumulated patterns from the left sibling or parent
|
* @param fromLeft the accumulated patterns from the left sibling or parent
|
||||||
* @return
|
* @return the stream of results
|
||||||
*/
|
*/
|
||||||
public Stream<AssemblyResolvedPatterns> applyPatternsForward(int shift,
|
public Stream<AssemblyResolvedPatterns> applyPatternsForward(int shift,
|
||||||
AssemblyResolvedPatterns fromLeft) {
|
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)));
|
return patterns.stream().map(pat -> fromLeft.combine(pat.shift(shift)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.math.BigInteger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.plugin.assembler.sleigh.util.DbgTimer;
|
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
@ -38,8 +37,6 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
|
||||||
protected AssemblyPatternBlock curctx; // the pseudo context value
|
protected AssemblyPatternBlock curctx; // the pseudo context value
|
||||||
protected AssemblyPatternBlock defctx; // the computed default
|
protected AssemblyPatternBlock defctx; // the computed default
|
||||||
|
|
||||||
protected final static DbgTimer dbg = DbgTimer.INACTIVE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the default context at most addresses for the given language
|
* Compute the default context at most addresses for the given language
|
||||||
*
|
*
|
||||||
|
@ -110,17 +107,14 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(Register register, BigInteger value) throws ContextChangeException {
|
public void setValue(Register register, BigInteger value) throws ContextChangeException {
|
||||||
dbg.println("Set " + register + " to " + value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRegisterValue(RegisterValue value) throws ContextChangeException {
|
public void setRegisterValue(RegisterValue value) throws ContextChangeException {
|
||||||
dbg.println("Set " + value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearRegister(Register register) throws ContextChangeException {
|
public void clearRegister(Register register) throws ContextChangeException {
|
||||||
dbg.println("Clear " + register);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -165,12 +159,10 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFutureRegisterValue(Address address, RegisterValue value) {
|
public void setFutureRegisterValue(Address address, RegisterValue value) {
|
||||||
dbg.println("Set " + value + " at " + address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFutureRegisterValue(Address fromAddr, Address toAddr, RegisterValue value) {
|
public void setFutureRegisterValue(Address fromAddr, Address toAddr, RegisterValue value) {
|
||||||
dbg.println("Set " + value + " for [" + fromAddr + ":" + toAddr + "]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,8 +174,6 @@ public class AssemblyDefaultContext implements DisassemblerContext, DefaultProgr
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
defctx = defctx.combine(AssemblyPatternBlock.fromRegisterValue(registerValue));
|
defctx = defctx.combine(AssemblyPatternBlock.fromRegisterValue(registerValue));
|
||||||
dbg.println("Combining " + registerValue);
|
|
||||||
dbg.println(" " + defctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -47,7 +47,6 @@ public class AssemblyNopStateGenerator
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<AssemblyGeneratedPrototype> generate(GeneratorContext gc) {
|
public Stream<AssemblyGeneratedPrototype> generate(GeneratorContext gc) {
|
||||||
gc.dbg("Generating NOP for " + opSym);
|
|
||||||
return Stream.of(new AssemblyGeneratedPrototype(
|
return Stream.of(new AssemblyGeneratedPrototype(
|
||||||
new AssemblyNopState(resolver, gc.path, gc.shift, opSym), fromLeft));
|
new AssemblyNopState(resolver, gc.path, gc.shift, opSym), fromLeft));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.AssemblyNumericTerminal;
|
||||||
import ghidra.app.plugin.assembler.sleigh.symbol.AssemblyTerminal;
|
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.ConstructState;
|
||||||
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
|
import ghidra.app.plugin.processors.sleigh.expression.PatternExpression;
|
||||||
import ghidra.app.plugin.processors.sleigh.symbol.OperandSymbol;
|
import ghidra.app.plugin.processors.sleigh.symbol.OperandSymbol;
|
||||||
|
@ -128,42 +127,37 @@ public class AssemblyOperandState extends AbstractAssemblyState {
|
||||||
if (symExp == null) {
|
if (symExp == null) {
|
||||||
symExp = opSym.getDefiningSymbol().getPatternExpression();
|
symExp = opSym.getDefiningSymbol().getPatternExpression();
|
||||||
}
|
}
|
||||||
DBG.println("Equation: " + symExp + " = " + Long.toHexString(value));
|
|
||||||
String desc = "Solution to " + opSym + " in " + Long.toHexString(value) + " = " + symExp;
|
String desc = "Solution to " + opSym + " in " + Long.toHexString(value) + " = " + symExp;
|
||||||
AssemblyResolution sol =
|
AssemblyResolution sol =
|
||||||
factory.solveOrBackfill(symExp, value, bitsize, resolver.vals, null, desc);
|
factory.solveOrBackfill(symExp, value, bitsize, resolver.vals, null, desc);
|
||||||
DBG.println("Solution: " + sol);
|
|
||||||
AssemblyResolution shifted = sol.shift(shift);
|
AssemblyResolution shifted = sol.shift(shift);
|
||||||
DBG.println("Shifted: " + shifted);
|
|
||||||
return shifted;
|
return shifted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<AssemblyResolvedPatterns> resolve(AssemblyResolvedPatterns fromRight,
|
protected Stream<AssemblyResolvedPatterns> resolve(AssemblyResolvedPatterns fromRight,
|
||||||
Collection<AssemblyResolvedError> errors) {
|
Collection<AssemblyResolvedError> errors) {
|
||||||
try (DbgCtx dc = DBG.start("Resolving " + terminal)) {
|
AssemblyResolution sol = solveNumeric();
|
||||||
AssemblyResolution sol = solveNumeric();
|
if (sol.isError()) {
|
||||||
if (sol.isError()) {
|
errors.add((AssemblyResolvedError) sol);
|
||||||
errors.add((AssemblyResolvedError) sol);
|
return Stream.of();
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
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() {
|
public AssemblyTerminal getTerminal() {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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 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
|
* 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.
|
* encodings, including error records describing the pruned intermediate results.
|
||||||
*/
|
*/
|
||||||
public class AssemblyResolutionResults extends AbstractSetDecorator<AssemblyResolution> {
|
public class AssemblyResolutionResults extends AbstractSetDecorator<AssemblyResolution> {
|
||||||
protected static final DbgTimer DBG = AbstractAssemblyTreeResolver.DBG;
|
|
||||||
|
|
||||||
public interface Applicator {
|
public interface Applicator {
|
||||||
Iterable<? extends AssemblyResolution> getPatterns(AssemblyResolvedPatterns cur);
|
Iterable<? extends AssemblyResolution> getPatterns(AssemblyResolvedPatterns cur);
|
||||||
|
@ -142,11 +139,8 @@ public class AssemblyResolutionResults extends AbstractSetDecorator<AssemblyReso
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AssemblyResolvedPatterns rp = (AssemblyResolvedPatterns) res;
|
AssemblyResolvedPatterns rp = (AssemblyResolvedPatterns) res;
|
||||||
DBG.println("Current: " + rp.lineToString());
|
|
||||||
for (AssemblyResolution ar : applicator.getPatterns(rp)) {
|
for (AssemblyResolution ar : applicator.getPatterns(rp)) {
|
||||||
DBG.println("Pattern: " + ar.lineToString());
|
|
||||||
AssemblyResolvedPatterns combined = applicator.combine(rp, ar);
|
AssemblyResolvedPatterns combined = applicator.combine(rp, ar);
|
||||||
DBG.println("Combined: " + (combined == null ? "(null)" : combined.lineToString()));
|
|
||||||
if (combined == null) {
|
if (combined == null) {
|
||||||
results.add(factory.error(applicator.describeError(rp, ar), ar));
|
results.add(factory.error(applicator.describeError(rp, ar), ar));
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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,
|
String description, List<? extends AssemblyResolution> children,
|
||||||
AssemblyResolution right, String error) {
|
AssemblyResolution right, String error) {
|
||||||
super(factory, description, children, right);
|
super(factory, description, children, right);
|
||||||
AbstractAssemblyTreeResolver.DBG.println(error);
|
|
||||||
this.error = error;
|
this.error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -758,11 +758,9 @@ public class DefaultAssemblyResolvedPatterns extends AbstractAssemblyResolution
|
||||||
Set<Integer> printed =
|
Set<Integer> printed =
|
||||||
Arrays.stream(cons.getOpsPrintOrder()).boxed().collect(Collectors.toSet());
|
Arrays.stream(cons.getOpsPrintOrder()).boxed().collect(Collectors.toSet());
|
||||||
if (!(opSym.getDefiningSymbol() instanceof SubtableSymbol)) {
|
if (!(opSym.getDefiningSymbol() instanceof SubtableSymbol)) {
|
||||||
AssemblyTreeResolver.DBG.println("Operand " + opSym + " is not a sub-table");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!printed.contains(opIdx)) {
|
if (!printed.contains(opIdx)) {
|
||||||
AssemblyTreeResolver.DBG.println("Operand " + opSym + " is hidden");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AssemblyResolvedPatterns child = (AssemblyResolvedPatterns) children.get(opIdx);
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.assembler.sleigh;
|
package ghidra.app.plugin.assembler.sleigh;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -25,10 +25,8 @@ import org.junit.Before;
|
||||||
|
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
import ghidra.app.plugin.assembler.*;
|
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.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.SleighInstructionPrototype;
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.app.util.PseudoInstruction;
|
import ghidra.app.util.PseudoInstruction;
|
||||||
|
@ -39,7 +37,6 @@ import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.program.util.DefaultLanguageService;
|
import ghidra.program.util.DefaultLanguageService;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.NumericUtilities;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A test for assembly of a particular SLEIGH language
|
* 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
|
// 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 = "";
|
static String setupLangID = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,32 +85,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
|
||||||
return (SleighLanguage) languageService.getLanguage(langID);
|
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
|
* 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) {
|
protected void checkOneCompat(String instr, AssemblyResolutionResults rr) {
|
||||||
AssemblyPatternBlock ins = AssemblyPatternBlock.fromString(instr);
|
AssemblyPatternBlock ins = AssemblyPatternBlock.fromString(instr);
|
||||||
dbg.println("Checking against: " + ins);
|
|
||||||
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess
|
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess
|
||||||
Set<AssemblyResolvedPatterns> misses = new TreeSet<>();
|
Set<AssemblyResolvedPatterns> misses = new TreeSet<>();
|
||||||
for (AssemblyResolution ar : rr) {
|
for (AssemblyResolution ar : rr) {
|
||||||
|
@ -183,15 +152,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
misses.add(rescon);
|
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");
|
fail("No result matched the desired instruction bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +169,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
|
||||||
Address address = lang.getDefaultSpace().getAddress(addr);
|
Address address = lang.getDefaultSpace().getAddress(addr);
|
||||||
final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address)
|
final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address)
|
||||||
: AssemblyPatternBlock.fromString(ctxstr)).fillMask();
|
: AssemblyPatternBlock.fromString(ctxstr)).fillMask();
|
||||||
dbg.println("Checking each: " + disassembly + " ctx:" + ctx);
|
|
||||||
boolean gotOne = false;
|
boolean gotOne = false;
|
||||||
boolean failedOne = false;
|
boolean failedOne = false;
|
||||||
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess.
|
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess.
|
||||||
|
@ -223,13 +182,10 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
AssemblyResolvedPatterns rp = (AssemblyResolvedPatterns) ar;
|
AssemblyResolvedPatterns rp = (AssemblyResolvedPatterns) ar;
|
||||||
try {
|
try {
|
||||||
dbg.println(" " + rp.lineToString());
|
|
||||||
for (byte[] ins : rp.possibleInsVals(ctx)) {
|
for (byte[] ins : rp.possibleInsVals(ctx)) {
|
||||||
dbg.println(" " + NumericUtilities.convertBytesToString(ins));
|
|
||||||
PseudoInstruction pi = disassemble(addr, ins, ctx.getVals());
|
PseudoInstruction pi = disassemble(addr, ins, ctx.getVals());
|
||||||
String cons = dumpConstructorTree(pi);
|
String cons = dumpConstructorTree(pi);
|
||||||
String dis = pi.toString();
|
String dis = pi.toString();
|
||||||
dbg.println(" " + dis);
|
|
||||||
if (!disassembly.contains(dis.trim())) {
|
if (!disassembly.contains(dis.trim())) {
|
||||||
failedOne = true;
|
failedOne = true;
|
||||||
misTxtToCons.put(dis, cons);
|
misTxtToCons.put(dis, cons);
|
||||||
|
@ -243,24 +199,9 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failedOne) {
|
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");
|
fail("At least one result did not disassemble to the given text");
|
||||||
}
|
}
|
||||||
if (!gotOne) {
|
if (!gotOne) {
|
||||||
dbg.println("Errors:");
|
|
||||||
for (AssemblyResolution ar : errs) {
|
|
||||||
dbg.println(ar.toString(" "));
|
|
||||||
}
|
|
||||||
fail("Did not get any matches");
|
fail("Did not get any matches");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,8 +229,6 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
|
||||||
if (ar.isError()) {
|
if (ar.isError()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dbg.println("Got:");
|
|
||||||
dbg.println(ar.toString(" "));
|
|
||||||
fail("All results were expected to be errors");
|
fail("All results were expected to be errors");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,7 +295,7 @@ public abstract class AbstractAssemblyTest extends AbstractGenericTest {
|
||||||
@Override
|
@Override
|
||||||
public Collection<AssemblyParseResult> filterParse(
|
public Collection<AssemblyParseResult> filterParse(
|
||||||
Collection<AssemblyParseResult> parse) throws AssemblySyntaxException {
|
Collection<AssemblyParseResult> parse) throws AssemblySyntaxException {
|
||||||
dbgPrintTrees(parse);
|
AssemblyTestCase.dbgPrintTrees(parse);
|
||||||
if (checkAllSyntaxErrs) {
|
if (checkAllSyntaxErrs) {
|
||||||
checkAllSyntaxErrs(parse);
|
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
|
* given
|
||||||
*
|
*
|
||||||
* @param assembly the input assembly
|
* @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 assembly the input assembly
|
||||||
* @param ctxstr the context pattern for assembly
|
* @param ctxstr the context pattern for assembly
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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 static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.apache.commons.collections4.MultiValuedMap;
|
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.parse.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.tree.AssemblyParseTreeNode;
|
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.*;
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighDebugLogger.SleighDebugMode;
|
|
||||||
import ghidra.app.util.PseudoInstruction;
|
import ghidra.app.util.PseudoInstruction;
|
||||||
import ghidra.generic.util.datastruct.TreeSetValuedTreeMap;
|
import ghidra.generic.util.datastruct.TreeSetValuedTreeMap;
|
||||||
import ghidra.program.model.address.Address;
|
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.lang.*;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.NumericUtilities;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A test for assembly of a particular SLEIGH language
|
* 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
|
// 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 = "";
|
static String setupLangID = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,24 +89,25 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
|
||||||
* @param trees the trees
|
* @param trees the trees
|
||||||
*/
|
*/
|
||||||
protected static void dbgPrintTrees(Collection<AssemblyParseResult> 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<>();
|
Set<String> suggestions = new TreeSet<>();
|
||||||
for (AssemblyParseResult result : trees) {
|
for (AssemblyParseResult result : trees) {
|
||||||
if (!result.isError()) {
|
if (!result.isError()) {
|
||||||
AssemblyParseAcceptResult acc = (AssemblyParseAcceptResult) result;
|
AssemblyParseAcceptResult acc = (AssemblyParseAcceptResult) result;
|
||||||
AssemblyParseTreeNode tree = acc.getTree();
|
AssemblyParseTreeNode tree = acc.getTree();
|
||||||
tree.print(dbg);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
tree.print(new PrintStream(baos));
|
||||||
|
Msg.trace(AssemblyTestCase.class, baos.toByteArray());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AssemblyParseErrorResult err = (AssemblyParseErrorResult) result;
|
AssemblyParseErrorResult err = (AssemblyParseErrorResult) result;
|
||||||
dbg.println(err);
|
Msg.trace(AssemblyTestCase.class, err.toString());
|
||||||
if (err.getBuffer().equals("")) {
|
if (err.getBuffer().equals("")) {
|
||||||
suggestions.addAll(err.getSuggestions());
|
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);
|
Address at = lang.getDefaultSpace().getAddress(addr);
|
||||||
context.setContextRegister(ctx);
|
context.setContextRegister(ctx);
|
||||||
MemBuffer buf = new ByteMemBufferImpl(at, ins, lang.isBigEndian());
|
MemBuffer buf = new ByteMemBufferImpl(at, ins, lang.isBigEndian());
|
||||||
SleighDebugLogger logger =
|
|
||||||
new SleighDebugLogger(buf, context, lang, SleighDebugMode.VERBOSE);
|
|
||||||
InstructionPrototype ip = lang.parse(buf, context, false);
|
InstructionPrototype ip = lang.parse(buf, context, false);
|
||||||
if (VERBOSE_DIS) {
|
|
||||||
dbg.println("SleighLog:\n" + logger.toString());
|
|
||||||
}
|
|
||||||
return new PseudoInstruction(at, ip, buf, context);
|
return new PseudoInstruction(at, ip, buf, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +163,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
|
||||||
*/
|
*/
|
||||||
protected void checkOneCompat(String instr, AssemblyResolutionResults rr) {
|
protected void checkOneCompat(String instr, AssemblyResolutionResults rr) {
|
||||||
AssemblyPatternBlock ins = AssemblyPatternBlock.fromString(instr);
|
AssemblyPatternBlock ins = AssemblyPatternBlock.fromString(instr);
|
||||||
dbg.println("Checking against: " + ins);
|
|
||||||
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess
|
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess
|
||||||
Set<AssemblyResolvedPatterns> misses = new TreeSet<>();
|
Set<AssemblyResolvedPatterns> misses = new TreeSet<>();
|
||||||
for (AssemblyResolution ar : rr) {
|
for (AssemblyResolution ar : rr) {
|
||||||
|
@ -185,14 +178,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
|
||||||
misses.add(rescon);
|
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");
|
fail("No result matched the desired instruction bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +195,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
|
||||||
Address address = lang.getDefaultSpace().getAddress(addr);
|
Address address = lang.getDefaultSpace().getAddress(addr);
|
||||||
final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address)
|
final AssemblyPatternBlock ctx = (ctxstr == null ? context.getDefaultAt(address)
|
||||||
: AssemblyPatternBlock.fromString(ctxstr)).fillMask();
|
: AssemblyPatternBlock.fromString(ctxstr)).fillMask();
|
||||||
dbg.println("Checking each: " + disassembly + " ctx:" + ctx);
|
|
||||||
boolean gotOne = false;
|
boolean gotOne = false;
|
||||||
boolean failedOne = false;
|
boolean failedOne = false;
|
||||||
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess.
|
Set<AssemblyResolvedError> errs = new TreeSet<>(); // Display in order, I guess.
|
||||||
|
@ -224,13 +208,10 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
AssemblyResolvedPatterns rcon = (AssemblyResolvedPatterns) ar;
|
AssemblyResolvedPatterns rcon = (AssemblyResolvedPatterns) ar;
|
||||||
try {
|
try {
|
||||||
dbg.println(" " + rcon.lineToString());
|
|
||||||
for (byte[] ins : rcon.possibleInsVals(ctx)) {
|
for (byte[] ins : rcon.possibleInsVals(ctx)) {
|
||||||
dbg.println(" " + NumericUtilities.convertBytesToString(ins));
|
|
||||||
PseudoInstruction pi = disassemble(addr, ins, ctx.getVals());
|
PseudoInstruction pi = disassemble(addr, ins, ctx.getVals());
|
||||||
String cons = dumpConstructorTree(pi);
|
String cons = dumpConstructorTree(pi);
|
||||||
String dis = pi.toString();
|
String dis = pi.toString();
|
||||||
dbg.println(" " + dis);
|
|
||||||
if (!disassembly.contains(dis.trim())) {
|
if (!disassembly.contains(dis.trim())) {
|
||||||
failedOne = true;
|
failedOne = true;
|
||||||
misTxtToCons.put(dis, cons);
|
misTxtToCons.put(dis, cons);
|
||||||
|
@ -244,24 +225,9 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failedOne) {
|
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");
|
fail("At least one result did not disassemble to the given text");
|
||||||
}
|
}
|
||||||
if (!gotOne) {
|
if (!gotOne) {
|
||||||
dbg.println("Errors:");
|
|
||||||
for (AssemblyResolution ar : errs) {
|
|
||||||
dbg.println(ar.toString(" "));
|
|
||||||
}
|
|
||||||
fail("Did not get any matches");
|
fail("Did not get any matches");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,8 +255,6 @@ public abstract class AssemblyTestCase extends AbstractGenericTest {
|
||||||
if (ar.isError()) {
|
if (ar.isError()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dbg.println("Got:");
|
|
||||||
dbg.println(ar.toString(" "));
|
|
||||||
fail("All results were expected to be errors");
|
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
|
* given
|
||||||
*
|
*
|
||||||
* @param assembly the input assembly
|
* @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 assembly the input assembly
|
||||||
* @param ctxstr the context pattern for 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