Merge remote-tracking branch 'origin/Ghidra_10.1'

This commit is contained in:
Ryan Kurtz 2021-11-29 12:00:27 -05:00
commit d6841fbe0f
10 changed files with 468 additions and 633 deletions

View file

@ -983,4 +983,27 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
emuThread.stepInstruction();
}
}
/**
* Test that unimplemented instructions (as opposed to instructions with no semantics) result in
* an interrupt.
*/
@Test(expected = PcodeExecutionException.class)
public void testUNIMPL() throws Throwable {
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
assertEquals(Register.NO_CONTEXT, tb.language.getContextBaseRegister());
TraceThread thread = initTrace(tb,
List.of(
"pc = 0x00400000;",
"sp = 0x00110000;"),
List.of(
"unimpl"));
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0);
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
emuThread.overrideContextWithDefault();
emuThread.stepInstruction();
}
}
}

View file

@ -122,10 +122,22 @@ public class PcodeExecutor<T> {
}
}
protected void badOp(PcodeOp op) {
switch (op.getOpcode()) {
case PcodeOp.UNIMPLEMENTED:
throw new LowlevelError(
"Encountered an unimplemented instruction at " + op.getSeqnum().getTarget());
default:
throw new LowlevelError(
"Unsupported p-code op at " + op.getSeqnum().getTarget() + ": " + op);
}
}
public void stepOp(PcodeOp op, PcodeFrame frame, SleighUseropLibrary<T> library) {
OpBehavior b = OpBehaviorFactory.getOpBehavior(op.getOpcode());
if (b == null) {
throw new LowlevelError("Unsupported pcode op" + op);
badOp(op);
return;
}
if (b instanceof UnaryOpBehavior) {
executeUnaryOp(op, (UnaryOpBehavior) b);
@ -164,7 +176,8 @@ public class PcodeExecutor<T> {
executeReturn(op, frame);
return;
default:
throw new LowlevelError("Unsupported op " + op);
badOp(op);
return;
}
}

View file

@ -24,11 +24,18 @@ import ghidra.app.services.GraphDisplayBroker;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.*;
import ghidra.service.graph.*;
import ghidra.util.WebColors;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class GraphClassesScript extends GhidraScript {
private static final String NO_INHERITANCE = "No Inheritance";
private static final String SINGLE_INHERITANCE = "Single Inheritance";
private static final String MULTIPLE_INHERITANCE = "Multiple Inheritance";
private static final String VIRTUAL_INHERITANCE = "Virtual Inheritance";
private static final String NON_VIRTUAL_INHERITANCE = "Non-virtual Inheritance";
List<Structure> classStructures = new ArrayList<Structure>();
@Override
@ -107,7 +114,15 @@ public class GraphClassesScript extends GhidraScript {
*/
private AttributedGraph createGraph() throws Exception {
AttributedGraph g = new AttributedGraph("Test Graph", new EmptyGraphType());
GraphType graphType =
new GraphTypeBuilder("Class Hierarchy Graph").vertexType(NO_INHERITANCE)
.vertexType(SINGLE_INHERITANCE)
.vertexType(MULTIPLE_INHERITANCE)
.edgeType(NON_VIRTUAL_INHERITANCE)
.edgeType(VIRTUAL_INHERITANCE)
.build();
AttributedGraph g = new AttributedGraph("Recovered Classes Graph", graphType);
for (Structure classStructure : classStructures) {
@ -176,24 +191,27 @@ public class GraphClassesScript extends GhidraScript {
AttributedEdge edge = g.addEdge(parentVertex, classVertex);
if (isVirtualParent) {
edge.setAttribute("Color", "Orange");
edge.setEdgeType(VIRTUAL_INHERITANCE);
}
else {
// else leave it default lime green
edge.setEdgeType(NON_VIRTUAL_INHERITANCE);
}
// else leave it default lime green
description = removeClassSubstring(description, parentName);
}
// no parent = blue vertex
if (numParents == 0) {
classVertex.setAttribute("Color", "Blue");
classVertex.setVertexType(NO_INHERITANCE);
}
// single parent = green vertex
else if (numParents == 1) {
classVertex.setAttribute("Color", "Green");
classVertex.setVertexType(SINGLE_INHERITANCE);
}
// multiple parents = red vertex
else {
classVertex.setAttribute("Color", "Red");
classVertex.setVertexType(MULTIPLE_INHERITANCE);
}
}
@ -295,7 +313,20 @@ public class GraphClassesScript extends GhidraScript {
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
display = service.getGraphDisplay(false, TaskMonitor.DUMMY);
display.setGraph(graph, "test graph", false, TaskMonitor.DUMMY);
GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType())
.vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE)
.vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN)
.vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED)
.edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN)
.edge(VIRTUAL_INHERITANCE, WebColors.ORANGE)
.defaultVertexColor(WebColors.PURPLE)
.defaultEdgeColor(WebColors.PURPLE)
.defaultLayoutAlgorithm("Compact Hierarchical")
.build();
display.setGraph(graph, graphOptions,
"Recovered Classes Graph", false, TaskMonitor.DUMMY);
}

View file

@ -35,7 +35,7 @@
// this script and default vfunctions named by this script are likely to change in the future
// once an official design for Object Oriented representation is determined.
// NOTE: Windows class recovery is more complete and tested than gcc class recovery, which is still
// in early stages of development. Gcc class data types are only recovered for classes without multiple or
// in early stages of development. Gcc class data types are only recovered for classes without
// virtual inheritance but if the program contains DWARF, there will be some amount of data recovered
// by the DWARF analyzer.
// NOTE: For likely the best results, run this script on freshly analyzed programs. No testing has been
@ -65,6 +65,8 @@ import ghidra.app.services.Analyzer;
import ghidra.app.services.GraphDisplayBroker;
import ghidra.app.util.bin.format.dwarf4.next.DWARFFunctionImporter;
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProvider;
import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProviderFactory;
import ghidra.app.util.bin.format.pdb.PdbParserConstants;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
@ -74,6 +76,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.service.graph.*;
import ghidra.util.WebColors;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.GraphException;
import ghidra.util.task.TaskMonitor;
@ -117,6 +120,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
// edge between child and parent is orange if child inherits the parent virtually
// edge between child and parent is lime green if child inherits the parent non-virtually
private static final boolean GRAPH_CLASS_HIERARCHIES = false;
private static final String NO_INHERITANCE = "No Inheritance";
private static final String SINGLE_INHERITANCE = "Single Inheritance";
private static final String MULTIPLE_INHERITANCE = "Multiple Inheritance";
private static final String VIRTUAL_INHERITANCE = "Virtual Inheritance";
private static final String NON_VIRTUAL_INHERITANCE = "Non-virtual Inheritance";
// show shortened class template names in class structure field names
private static final boolean USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS = true;
@ -134,23 +142,29 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE";
// DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES
// If replacedClassStructuresOption is set to the following, no replaced structures will be removed
// from the data type manager
private static final int DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES = 0;
// REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES
// If replacedClassStructuresOption is set to the following, only empty existing class structures
// that were replaced by this script will be removed from the data type manager
private static final int REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES = 1;
// REMOVE_ALL_REPLACED_CLASS_STRUCTURES
// If replacedClassStructuresOption is set to the following, all existing class structures that
// were replaced by this script, including non-emtpy ones, will be removed from the data type
// manager
private static final int REMOVE_ALL_REPLACED_CLASS_STRUCTURES = 2;
private static enum removeOption {
DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES,
REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES,
REMOVE_ALL_REPLACED_CLASS_STRUCTURES
}
// NEW OPTION -
// This option allows the user to decide whether and how to remove replaced existing class structures
// using one of the above three flags
int replacedClassStructuresOption = DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES;
removeOption replacedClassStructuresOption =
removeOption.DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES;
boolean programHasRTTIApplied = false;
boolean hasDebugSymbols;
@ -178,16 +192,14 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return;
}
if (isWindows()) {
hasDebugSymbols = isPDBLoadedInProgram();
nameVfunctions = !hasDebugSymbols;
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram,
currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
REPLACE_EXISTING_CLASS_STRUCTURES,
monitor);
recoverClassesFromRTTI =
new RTTIWindowsClassRecoverer(currentProgram, currentLocation, state.getTool(),
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, REPLACE_EXISTING_CLASS_STRUCTURES, monitor);
}
else if (isGcc()) {
@ -204,11 +216,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
return;
}
nameVfunctions = !hasDebugSymbols;
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
REPLACE_EXISTING_CLASS_STRUCTURES,
monitor);
recoverClassesFromRTTI =
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
nameVfunctions, hasDebugSymbols, REPLACE_EXISTING_CLASS_STRUCTURES, monitor);
}
else {
println("This script will not work on this program type");
@ -281,7 +292,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
getNumberOfConstructorsOrDestructors(recoveredClasses) +
" class member functions to assign.");
if (!hasDebugSymbols) {
if (BOOKMARK_FOUND_FUNCTIONS) {
@ -301,23 +311,32 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
showGraph(graph);
}
if (replacedClassStructuresOption == REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES) {
if (replacedClassStructuresOption == removeOption.REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES) {
println("Removing all empty replaced class structures from the data type manager");
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, false);
}
if (replacedClassStructuresOption == REMOVE_ALL_REPLACED_CLASS_STRUCTURES) {
if (replacedClassStructuresOption == removeOption.REMOVE_ALL_REPLACED_CLASS_STRUCTURES) {
println(
"Removing all replaced class structures from the data type manager, including non-empty ones");
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, true);
}
decompilerUtils.disposeDecompilerInterface();
}
private boolean hasDwarf() {
return DWARFProgram.isDWARF(currentProgram);
if (DWARFProgram.isDWARF(currentProgram)) {
DWARFSectionProvider dsp =
DWARFSectionProviderFactory.createSectionProviderFor(currentProgram, monitor);
if (dsp == null) {
return false;
}
dsp.close();
return true;
}
return false;
}
/**
@ -331,8 +350,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
private boolean isDwarfLoadedInProgram() {
return DWARFFunctionImporter.hasDWARFProgModule(currentProgram,
DWARFProgram.DWARF_ROOT_NAME);
Options options = currentProgram.getOptions(Program.PROGRAM_INFO);
return (DWARFFunctionImporter.hasDWARFProgModule(currentProgram,
DWARFProgram.DWARF_ROOT_NAME) || options.getBoolean("DWARF Loaded", false));
}
public String validate() {
@ -392,7 +413,15 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
private AttributedGraph createGraph(List<RecoveredClass> recoveredClasses)
throws CancelledException {
AttributedGraph g = new AttributedGraph("Test Graph", new EmptyGraphType());
GraphType graphType =
new GraphTypeBuilder("Class Hierarchy Graph").vertexType(NO_INHERITANCE)
.vertexType(SINGLE_INHERITANCE)
.vertexType(MULTIPLE_INHERITANCE)
.edgeType(NON_VIRTUAL_INHERITANCE)
.edgeType(VIRTUAL_INHERITANCE)
.build();
AttributedGraph g = new AttributedGraph("Recovered Classes Graph", graphType);
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
while (recoveredClassIterator.hasNext()) {
@ -408,7 +437,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
// no parent = blue vertex
if (classHierarchyMap.isEmpty()) {
classVertex.setAttribute("Color", "Blue");
classVertex.setVertexType(NO_INHERITANCE);
classVertex.setDescription(recoveredClass.getClassPath().getPath());
continue;
}
@ -417,11 +446,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
// single parent = green vertex
if (parents.size() == 1) {
classVertex.setAttribute("Color", "Green");
classVertex.setVertexType(SINGLE_INHERITANCE);
}
// multiple parents = red vertex
else {
classVertex.setAttribute("Color", "Red");
classVertex.setVertexType(MULTIPLE_INHERITANCE);
}
classVertex.setDescription(recoveredClass.getClassPath().getPath());
@ -448,9 +477,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
// edge between child and parent is orange if child inherits the parent virtually
if (isVirtualParent) {
edge.setAttribute("Color", "Orange");
edge.setEdgeType(VIRTUAL_INHERITANCE);
}
// else edge between child and parent is lime green if child inherits the parent non-virtually
else {
edge.setEdgeType(NON_VIRTUAL_INHERITANCE);
}
}
}
@ -471,7 +503,20 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
display = service.getGraphDisplay(false, TaskMonitor.DUMMY);
display.setGraph(graph, "test graph", false, TaskMonitor.DUMMY);
GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType())
.vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE)
.vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN)
.vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED)
.edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN)
.edge(VIRTUAL_INHERITANCE, WebColors.ORANGE)
.defaultVertexColor(WebColors.PURPLE)
.defaultEdgeColor(WebColors.PURPLE)
.defaultLayoutAlgorithm("Compact Hierarchical")
.build();
display.setGraph(graph, graphOptions,
"Recovered Classes Graph", false, TaskMonitor.DUMMY);
}
/**

View file

@ -1045,8 +1045,10 @@ public class ExtraScriptUtils extends FlatProgramAPI {
* @param parent parent CategoryPath
* @param categoryName name of the new category in the parent path
* @return CategoryPath for new categoryName
* @throws CancelledException if cancelled
*/
public CategoryPath createDataTypeCategoryPath(CategoryPath parent, String categoryName) {
public CategoryPath createDataTypeCategoryPath(CategoryPath parent, String categoryName)
throws CancelledException {
CategoryPath dataTypePath;
@ -1070,12 +1072,8 @@ public class ExtraScriptUtils extends FlatProgramAPI {
int index = 0;
String newCategoryName = new String();
while (index < categoryName.length()) {
try {
monitor.checkCanceled();
}
catch (CancelledException e) {
return null;
}
monitor.checkCanceled();
if (categoryName.substring(index).startsWith("::") && !insideBrackets) {
newCategoryName = newCategoryName.concat("/");

View file

@ -44,7 +44,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, boolean hasDebugSymbols, boolean replaceClassStructures,
TaskMonitor monitor) {
TaskMonitor monitor) throws Exception {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
replaceClassStructures,
@ -76,7 +76,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
return dataTypeManager;
}
public boolean containsRTTI() throws CancelledException {
public boolean containsRTTI() throws CancelledException, InvalidInputException {
return true;
}
@ -104,12 +104,12 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
public void fixUpProgram() {
public void fixUpProgram() throws CancelledException, Exception {
return;
}
public List<RecoveredClass> createRecoveredClasses() {
public List<RecoveredClass> createRecoveredClasses() throws Exception {
return new ArrayList<RecoveredClass>();
}
@ -121,10 +121,10 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
* Method to promote the namespace is a class namespace.
* @param namespace the namespace for the vftable
* @return true if namespace is (now) a class namespace or false if it could not be promoted.
* @throws InvalidInputException if namespace was contained in function and could not be promoted
*/
public Namespace promoteToClassNamespace(Namespace namespace) {
public Namespace promoteToClassNamespace(Namespace namespace) throws InvalidInputException {
try {
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
SymbolType symbolType = newClass.getSymbol().getSymbolType();
@ -134,13 +134,6 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
Msg.debug(this,
"Could not promote " + namespace.getName() + " to a class namespace");
return null;
}
catch (InvalidInputException e) {
Msg.debug(this, "Could not promote " + namespace.getName() +
" to a class namespace because " + e.getMessage());
return null;
}
}
@ -221,7 +214,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
Structure existingClassStructure =
(Structure) dataTypeManager.getDataType(dataTypePath, dataTypeName);
if (!existingClassStructure.isNotYetDefined()) {
if (existingClassStructure != null && !existingClassStructure.isNotYetDefined()) {
recoveredClass.addExistingClassStructure(existingClassStructure);
break;
}

View file

@ -74,18 +74,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVfunctions, boolean isDwarfLoaded, boolean replaceExistingClassStructures,
TaskMonitor monitor) {
TaskMonitor monitor) throws Exception {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
replaceExistingClassStructures,
isDwarfLoaded,
monitor);
replaceExistingClassStructures, isDwarfLoaded, monitor);
this.isDwarfLoaded = isDwarfLoaded;
this.replaceClassStructs = replaceExistingClassStructures;
}
@Override
public boolean containsRTTI() throws CancelledException {
public boolean containsRTTI() throws CancelledException, InvalidInputException {
if (!hasSpecialVtable()) {
return false;
@ -103,44 +101,33 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
}
@Override
public List<RecoveredClass> createRecoveredClasses() {
public List<RecoveredClass> createRecoveredClasses() throws CancelledException, Exception {
try {
processGccRTTI();
if (recoveredClasses == null) {
Msg.debug(this, "Could not recover gcc rtti classes");
return null;
}
createCalledFunctionMap(recoveredClasses);
createClassHierarchyListAndMapForGcc();
if (isDwarfLoaded) {
retrieveExistingClassStructures(recoveredClasses);
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
}
else {
processConstructorAndDestructors();
}
createVftableOrderMap(recoveredClasses);
figureOutClassDataMembers(recoveredClasses);
createAndApplyClassStructures();
return recoveredClasses;
}
catch (CancelledException e) {
e.printStackTrace();
processGccRTTI();
if (recoveredClasses == null) {
Msg.debug(this, "Could not recover gcc rtti classes");
return null;
}
catch (Exception e) {
e.printStackTrace();
return null;
createCalledFunctionMap(recoveredClasses);
createClassHierarchyListAndMapForGcc();
if (isDwarfLoaded) {
retrieveExistingClassStructures(recoveredClasses);
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
}
else {
processConstructorAndDestructors();
}
createVftableOrderMap(recoveredClasses);
figureOutClassDataMembers(recoveredClasses);
createAndApplyClassStructures();
return recoveredClasses;
}
@ -171,8 +158,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
Address found = program.getMemory()
.findBytes(commentBlock.getStart(),
commentBlock.getEnd(), gccBytes, maskBytes, true, monitor);
.findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, maskBytes,
true, monitor);
if (found == null) {
return false;
}
@ -184,8 +171,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
* Method to check for at least one special RTTI vtable
* @return true if the program has at least one special vtable, false if none
* @throws CancelledException if cancelled
* @throws InvalidInputException if bad characters creating labels
*/
private boolean hasSpecialVtable() throws CancelledException {
private boolean hasSpecialVtable() throws CancelledException, InvalidInputException {
boolean hasSpecialVtable = createSpecialVtables();
return hasSpecialVtable;
@ -287,8 +275,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
}
private void updateClassesWithParentsAndFlags(List<Symbol> typeinfoSymbols)
throws Exception {
private void updateClassesWithParentsAndFlags(List<Symbol> typeinfoSymbols) throws Exception {
// add properties and parents to each class
Iterator<Symbol> typeinfoIterator = typeinfoSymbols.iterator();
@ -464,6 +451,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
while (vtableIterator.hasNext()) {
monitor.checkCanceled();
Symbol vtableSymbol = vtableIterator.next();
@ -534,14 +522,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
throw new Exception("typeinfo has global namespace " + typeinfoAddress);
}
try {
Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
classNamespace, SourceType.ANALYSIS);
vtableSymbols.add(vtableSymbol);
}
catch (InvalidInputException e) {
continue;
}
Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
classNamespace, SourceType.ANALYSIS);
vtableSymbols.add(vtableSymbol);
api.setPlateComment(vtableAddress, "vtable for " + classNamespace.getName(true));
}
@ -631,16 +614,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
if (namespacesByPath.isEmpty()) {
try {
Namespace newNamespace =
NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace,
program, SourceType.ANALYSIS);
return newNamespace;
}
catch (InvalidInputException e) {
e.printStackTrace();
return null;
}
Namespace newNamespace = NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace,
program, SourceType.ANALYSIS);
return newNamespace;
}
if (namespacesByPath.size() == 1) {
return namespacesByPath.get(0);
@ -684,8 +661,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
// check direct refs to see if they are in undefined area or not in function
byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, typeinfoAddress);
addByteSearchPattern(searcher, validTypeinfoRefs, typeinfoAddress, bytes,
monitor);
addByteSearchPattern(searcher, validTypeinfoRefs, typeinfoAddress, bytes, monitor);
}
searcher.search(program, searchSet, monitor);
@ -780,10 +756,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
* @param vtableNamespace the namespace of the given vtable
* @param isPrimary true if the vtable is the primary one for the class
* @param listOfAllVtables list of all vtables
* @throws CancelledException if cancelled
*/
private void processVtable(Address vtableAddress, Namespace vtableNamespace, boolean isPrimary,
List<Symbol> listOfAllVtables)
throws Exception {
List<Symbol> listOfAllVtables) throws CancelledException, Exception {
// skip the special tables
if (vtableAddress.equals(class_type_info_vtable) ||
@ -818,13 +794,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
Data typeinfoPtr = api.getDataAt(typeinfoAddress);
if (typeinfoPtr == null) {
DataType nullPointer = dataTypeManager.getPointer(null);
try {
api.createData(typeinfoAddress, nullPointer);
}
catch (Exception e) {
Msg.debug(this,
"Could not create typeinfo pointer at " + typeinfoAddress.toString());
}
api.createData(typeinfoAddress, nullPointer);
}
// if not already named a construction-vtable then check to see if it is one so it can
@ -850,33 +822,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
Namespace classNamespace = createConstructionNamespace(vtableSymbol,
vttSymbolBeforeConstructionVtable);
try {
vtableSymbol.setNameAndNamespace("construction-vtable",
classNamespace, SourceType.ANALYSIS);
vtableNamespace = vtableSymbol.getParentNamespace();
// label the subVTTaddress
symbolTable.createLabel(subVTTAddress, "subVTT_" + n,
vttSymbolBeforeConstructionVtable.getParentNamespace(),
SourceType.ANALYSIS);
vtableSymbol.setNameAndNamespace("construction-vtable", classNamespace,
SourceType.ANALYSIS);
vtableNamespace = vtableSymbol.getParentNamespace();
// label the subVTTaddress
symbolTable.createLabel(subVTTAddress, "subVTT_" + n,
vttSymbolBeforeConstructionVtable.getParentNamespace(),
SourceType.ANALYSIS);
api.setPlateComment(vtableAddress, "construction vtable " + n +
" for class " +
api.setPlateComment(vtableAddress,
"construction vtable " + n + " for class " +
vttSymbolBeforeConstructionVtable.getParentNamespace()
.getName(
true));
.getName(true));
}
catch (InvalidInputException e) {
Msg.debug(this, e.getMessage());
continue;
}
catch (CircularDependencyException e) {
Msg.debug(this, e.getMessage());
continue;
}
catch (DuplicateNameException e) {
continue;
}
}
}
@ -919,25 +877,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
vftableLabel = "internal_" + vftableLabel;
}
try {
symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace,
SourceType.ANALYSIS);
symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace,
SourceType.ANALYSIS);
createVftableArray(possibleVftableAddress, numFunctionPointers);
}
catch (IllegalArgumentException e) {
Msg.debug(this, "Could not label vftable at " + possibleVftableAddress.toString());
}
catch (InvalidInputException e) {
Msg.debug(this, "Could not label vftable at " + possibleVftableAddress.toString());
}
catch (CancelledException e) {
return;
}
catch (AddressOutOfBoundsException e) {
Msg.debug(this, "Couldn't create vftable due to Address out of bounds issue");
return;
}
createVftableArray(possibleVftableAddress, numFunctionPointers);
// check for an internal vtable after the vftable and make a symbol there if there is one
// will process them later
@ -1050,7 +993,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
}
private boolean createInternalVtable(Address possibleInternalVtableAddress,
Namespace vtableNamespace) throws CancelledException {
Namespace vtableNamespace) throws CancelledException, InvalidInputException, Exception {
// check to see if it is a pointer and if so, it cannot be an internal vtable
// as they contain at least one long
Address pointer = getPointerToDefinedMemory(possibleInternalVtableAddress);
@ -1071,27 +1014,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
(possibleInternalVtableSymbol.getSource() == SourceType.DEFAULT &&
(isValidVtableStart(possibleInternalVtableAddress) ||
isValidVftableStart(possibleInternalVtableAddress)))) {
try {
symbolTable.createLabel(possibleInternalVtableAddress,
"internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace,
SourceType.ANALYSIS);
processVtable(possibleInternalVtableAddress, vtableNamespace, false, null);
return true;
}
catch (IllegalArgumentException e) {
Msg.debug(this, "Could not label internal vtable at " +
possibleInternalVtableAddress.toString());
return true; // still created vtable, just couldn't name it
}
catch (InvalidInputException e) {
Msg.debug(this, "Could not label internal vtable at " +
possibleInternalVtableAddress.toString());
return true; // still created vtable, just couldn't name it
}
catch (Exception e) {
e.printStackTrace();
}
symbolTable.createLabel(possibleInternalVtableAddress,
"internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace,
SourceType.ANALYSIS);
processVtable(possibleInternalVtableAddress, vtableNamespace, false, null);
return true;
}
return false;
@ -1102,8 +1030,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
* @param classNamespace the given namespace
* @param address the address of the potential VTT table
* @return true if a valid VTT has been discovered and label created
* @throws Exception if data creation results in an exception
*/
private boolean createVTT(Namespace classNamespace, Address address) {
private boolean createVTT(Namespace classNamespace, Address address) throws Exception {
// get pointer at address
Address pointer = getPointerToDefinedMemory(address);
@ -1120,22 +1049,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
}
// if it is then create the VTT symbol and create pointer there
try {
symbolTable.createLabel(address, "VTT", classNamespace, SourceType.ANALYSIS);
}
catch (IllegalArgumentException e) {
Msg.debug(this, "Could not label VTT at " + address.toString());
}
catch (InvalidInputException e) {
Msg.debug(this, "Could not label VTT at " + address.toString());
}
symbolTable.createLabel(address, "VTT", classNamespace, SourceType.ANALYSIS);
DataType nullPointer = dataTypeManager.getPointer(null);
try {
api.createData(pointer, nullPointer);
}
catch (Exception e) {
// already data there
// already data there so don't try and overwrite it
}
api.setPlateComment(address, "VTT for " + classNamespace.getName(true));
@ -1144,7 +1066,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
}
private Data createVftableArray(Address vftableAddress, int numFunctionPointers)
throws CancelledException, AddressOutOfBoundsException {
throws Exception {
api.clearListing(vftableAddress,
vftableAddress.add((numFunctionPointers * defaultPointerSize - 1)));
@ -1152,14 +1074,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
DataType pointerDataType = dataTypeManager.getPointer(null);
ArrayDataType vftableArrayDataType =
new ArrayDataType(pointerDataType, numFunctionPointers, defaultPointerSize);
try {
Data vftableArrayData = api.createData(vftableAddress, vftableArrayDataType);
return vftableArrayData;
}
catch (Exception e) {
return null;
}
Data vftableArrayData = api.createData(vftableAddress, vftableArrayDataType);
return vftableArrayData;
}
/**
@ -1349,35 +1266,25 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
* @param vtableAddress the given special vtable address
* @return the address of the typeinfo in the vtable if replace was successful, null otherwise
* @throws CancelledException if cancelled
* @throws InvalidInputException if bad characters when creating label
*/
private Address createSpecialVtable(Address vtableAddress) throws CancelledException {
private Address createSpecialVtable(Address vtableAddress)
throws CancelledException, InvalidInputException {
Symbol vtableSymbol = symbolTable.getPrimarySymbol(vtableAddress);
api.clearListing(vtableAddress);
try {
int vtableLongs = createVtableLongs(vtableAddress);
if (vtableLongs > 0) {
int vtableLongs = createVtableLongs(vtableAddress);
Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize);
symbolTable.createLabel(typeinfoAddress, "typeinfo",
vtableSymbol.getParentNamespace(), SourceType.ANALYSIS);
return typeinfoAddress;
}
return null;
}
if (vtableLongs > 0) {
catch (AddressOutOfBoundsException e) {
return null;
Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize);
symbolTable.createLabel(typeinfoAddress, "typeinfo", vtableSymbol.getParentNamespace(),
SourceType.ANALYSIS);
return typeinfoAddress;
}
catch (IllegalArgumentException e) {
return null;
}
catch (InvalidInputException e) {
return null;
}
return null;
}
/**
@ -1409,7 +1316,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
api.createData(address, pointer);
Address referencedAddress = extraUtils.getSingleReferencedAddress(address);
// if it isn't valid, clear what we just created and increment to offset so
// if it isn't a valid pointer, clear what we just created and increment to offset so
// the next can be checked
if (referencedAddress == null || !programAddressSet.contains(referencedAddress)) {
api.clearListing(address);
@ -1422,6 +1329,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
return numLongs;
}
}
// if bump into existing data return the number found so far
catch (Exception e) {
return numLongs;
}
@ -1534,20 +1442,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
}
private Data applyTypeinfoStructure(Structure typeInfoStructure, Address typeinfoAddress)
throws CancelledException, AddressOutOfBoundsException {
throws CancelledException, AddressOutOfBoundsException, Exception {
api.clearListing(typeinfoAddress, typeinfoAddress.add(typeInfoStructure.getLength() - 1));
Data newStructure;
try {
newStructure = api.createData(typeinfoAddress, typeInfoStructure);
}
catch (Exception e) {
newStructure = null;
}
if (newStructure == null) {
Msg.debug(this,
"Could not create " + typeInfoStructure.getName() + " at " + typeinfoAddress);
}
newStructure = api.createData(typeinfoAddress, typeInfoStructure);
return newStructure;
}
@ -1560,14 +1461,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
try {
numBases = api.getInt(typeinfoAddress.add(offsetOfNumBases));
}
// if there isn't enough memory to get the int then return null
catch (MemoryAccessException | AddressOutOfBoundsException e) {
return null;
}
// get or create the vmiClassTypeInfoStruct
Structure vmiClassTypeinfoStructure =
(Structure) dataTypeManager.getDataType(classDataTypesCategoryPath,
VMI_CLASS_TYPE_INFO_STRUCTURE + numBases);
Structure vmiClassTypeinfoStructure = (Structure) dataTypeManager
.getDataType(classDataTypesCategoryPath, VMI_CLASS_TYPE_INFO_STRUCTURE + numBases);
if (vmiClassTypeinfoStructure == null) {
vmiClassTypeinfoStructure =
createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases);
@ -1575,7 +1476,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
return vmiClassTypeinfoStructure;
}
private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) {
private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress)
throws DuplicateNameException, InvalidInputException {
String mangledTypeinfo = getTypeinfoName(typeinfoAddress);
if (mangledTypeinfo == null) {
@ -1614,25 +1516,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
}
// create the new typeinfo symbol in the demangled namespace
try {
Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace,
SourceType.ANALYSIS);
return newSymbol;
}
catch (InvalidInputException e) {
Msg.error(this,
typeinfoAddress.toString() + " invalid input exception " + e.getMessage());
return null;
}
catch (IllegalArgumentException e) {
Msg.debug(this,
typeinfoAddress.toString() + " illegal argument exception " + e.getMessage());
return null;
}
Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace,
SourceType.ANALYSIS);
return newSymbol;
}
private Namespace createTypeinfoClassNamespace(String namespaceString) {
private Namespace createTypeinfoClassNamespace(String namespaceString)
throws DuplicateNameException, InvalidInputException {
int indexOfColons = namespaceString.indexOf("::");
Namespace namespace = globalNamespace;
@ -1659,20 +1550,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
return classNamespace;
}
private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace) {
private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace)
throws DuplicateNameException, InvalidInputException {
Namespace namespace = symbolTable.getNamespace(namespaceName, parentNamespace);
if (namespace == null) {
try {
namespace = symbolTable.createNameSpace(parentNamespace, namespaceName,
SourceType.ANALYSIS);
}
catch (DuplicateNameException e) {
// shouldn't happen since it only gets here if the symbol didn't exist in the first place
}
catch (InvalidInputException e) {
return null;
}
namespace =
symbolTable.createNameSpace(parentNamespace, namespaceName, SourceType.ANALYSIS);
}
return namespace;
}
@ -1710,12 +1595,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
StringDataType sdt = new StringDataType();
String str;
try {
str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen);
}
catch (AddressOutOfBoundsException e) {
return null;
}
str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen);
return str;
}
@ -1814,26 +1696,37 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
return false;
}
/**
* Get the references to the special type infos that exist in the current program.
* @return the references to the special type infos that exist in the current program
* @throws CancelledException if cancelled
*/
private List<Address> getTypeinfoAddressesUsingSpecialTypeinfos() throws CancelledException {
List<Address> specialTypeinfoRefs = new ArrayList<Address>();
Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info);
for (Reference ref : refsToClassTypeinfo) {
monitor.checkCanceled();
specialTypeinfoRefs.add(ref.getFromAddress());
if (class_type_info != null) {
Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info);
for (Reference ref : refsToClassTypeinfo) {
monitor.checkCanceled();
specialTypeinfoRefs.add(ref.getFromAddress());
}
}
Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info);
for (Reference ref : refsToSiClassTypeinfo) {
monitor.checkCanceled();
specialTypeinfoRefs.add(ref.getFromAddress());
if (si_class_type_info != null) {
Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info);
for (Reference ref : refsToSiClassTypeinfo) {
monitor.checkCanceled();
specialTypeinfoRefs.add(ref.getFromAddress());
}
}
Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info);
for (Reference ref : refsToVmiClassTypeinfo) {
monitor.checkCanceled();
specialTypeinfoRefs.add(ref.getFromAddress());
if (vmi_class_type_info != null) {
Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info);
for (Reference ref : refsToVmiClassTypeinfo) {
monitor.checkCanceled();
specialTypeinfoRefs.add(ref.getFromAddress());
}
}
return specialTypeinfoRefs;
@ -2153,8 +2046,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
//virtual base offset for the virtual base referenced (negative).
long offset = (publicVirtualOffsetFlag & offsetMask) >> 8;
Msg.debug(this, "typeinfo " + typeinfoAddress + " base [" + i + "] isVirtual = " +
isVirtual + " isPublic = " + isPublic + " offset = " + offset);
if (DEBUG) {
Msg.debug(this, "typeinfo " + typeinfoAddress + " base [" + i + "] isVirtual = " +
isVirtual + " isPublic = " + isPublic + " offset = " + offset);
}
// add order to parent and parent offset
orderToParentMap.put(i, parentClass);
@ -2232,8 +2127,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
* correct data types. Also creates a type info symbol at the correct offset in the table.
* @return true if all found tables have a typeinfo symbol created successfully
* @throws CancelledException if cancelled
* @throws InvalidInputException if bad characters creating labels
*/
private boolean createSpecialVtables() throws CancelledException {
private boolean createSpecialVtables() throws CancelledException, InvalidInputException {
class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__class_type_info");
class_type_info = null;
@ -2517,8 +2413,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
* Use information from RTTI Base class Arrays to create class hierarchy lists and maps
* @throws CancelledException if cancelled
*/
private void createClassHierarchyListAndMapForGcc()
throws CancelledException, Exception {
private void createClassHierarchyListAndMapForGcc() throws CancelledException, Exception {
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
while (recoveredClassIterator.hasNext()) {
@ -2683,22 +2578,20 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
* address
* @param start the starting address
* @param end the ending address
* @throws CancelledException if cancelled
* @throws Exception if data has conflict when created
*/
private void createLongs(Address start, Address end) {
private void createLongs(Address start, Address end) throws CancelledException, Exception {
LongDataType longDT = new LongDataType();
int offset = 0;
Address address = start;
while (address != null && !address.equals(end)) {
try {
api.clearListing(address);
api.createData(address, longDT);
offset += defaultPointerSize;
address = getAddress(start, offset);
}
catch (Exception e) {
return;
}
api.clearListing(address, address.add(defaultPointerSize - 1));
api.createData(address, longDT);
offset += defaultPointerSize;
address = getAddress(start, offset);
}
}
@ -2868,9 +2761,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
// can't handle creating class data types for classes with virtual parents yet
if (recoveredClass.inheritsVirtualAncestor()) {
if (DEBUG) {
Msg.debug(this, "Cannot create class data type for " +
recoveredClass.getClassNamespace().getName(true) +
" because it has virtual ancestors and we don't yet handle that use case.");
Msg.debug(this,
"Cannot create class data type for " +
recoveredClass.getClassNamespace().getName(true) +
" because it has virtual ancestors and we don't yet handle that use case.");
}
return;
}
@ -2901,27 +2795,23 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
// and class member data structure
Structure classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes);
// check for DWARF -- if none add c/d/etc to class
//TODO: if decide to replace dwarf data types then remove this check so the replaces
// in the following methods can replace the dwarf data types
if (!isDwarfLoaded) {
// Now that we have a class data type
// name constructor and destructor functions and put into the class namespace
addConstructorsToClassNamespace(recoveredClass, classStruct);
addDestructorsToClassNamespace(recoveredClass, classStruct);
// Now that we have a class data type
// name constructor and destructor functions and put into the class namespace
addConstructorsToClassNamespace(recoveredClass, classStruct);
addDestructorsToClassNamespace(recoveredClass, classStruct);
//TODO:
// addNonThisDestructorsToClassNamespace(recoveredClass);
// addVbaseDestructorsToClassNamespace(recoveredClass);
// addVbtableToClassNamespace(recoveredClass);
//
//TODO:
// // add secondary label on functions with inlined constructors or destructors
// createInlinedConstructorComments(recoveredClass);
// createInlinedDestructorComments(recoveredClass);
// createIndeterminateInlineComments(recoveredClass);
// add label on constructor destructor functions that could not be determined which were which
createIndeterminateLabels(recoveredClass, classStruct);
}
// add label on constructor destructor functions that could not be determined which were which
createIndeterminateLabels(recoveredClass, classStruct);
// This is done after the class structure is created and added to the dtmanager
// because if done before the class structures are created

View file

@ -70,7 +70,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVFunctions, boolean isPDBLoaded, boolean replaceClassStructures,
TaskMonitor monitor) throws CancelledException {
TaskMonitor monitor) throws Exception {
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions,
isPDBLoaded, replaceClassStructures, monitor);
@ -98,121 +98,98 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
}
@Override
public void fixUpProgram() {
public void fixUpProgram() throws CancelledException, Exception {
if (ghidraVersion.compareTo("10.0") < 0) {
try {
fixUpRttiAnalysis();
}
catch (Exception e) {
e.printStackTrace();
}
}
fixUpRttiAnalysis();
}
// if there are undefined areas that reference vftables attempt to create functions
// containing them
List<Symbol> vftableSymbols;
try {
vftableSymbols = getListOfVftableSymbols();
createMissingFunctions(vftableSymbols);
}
catch (CancelledException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
List<Symbol> vftableSymbols = getListOfVftableSymbols();
createMissingFunctions(vftableSymbols);
return;
}
@Override
public List<RecoveredClass> createRecoveredClasses() {
public List<RecoveredClass> createRecoveredClasses() throws Exception {
List<Symbol> vftableSymbols;
try {
vftableSymbols = getListOfVftableSymbols();
List<RecoveredClass> recoveredClasses =
recoverClassesFromClassHierarchyDescriptors(vftableSymbols);
vftableSymbols = getListOfVftableSymbols();
determineVftableOffsetsfromRTTI(recoveredClasses);
List<RecoveredClass> recoveredClasses =
recoverClassesFromClassHierarchyDescriptors(vftableSymbols);
// If no new classes have been recovered, no need to continue. Return out of script.
if (recoveredClasses.isEmpty()) {
determineVftableOffsetsfromRTTI(recoveredClasses);
return recoveredClasses;
}
createCalledFunctionMap(recoveredClasses);
// figure out class hierarchies using either RTTI or vftable refs
monitor.setMessage("Assigning class inheritance and hierarchies");
assignClassInheritanceAndHierarchies(recoveredClasses);
// Since PDB has applied so much information, use it to figure out the class member data 4
// items (if it has them) and the constructors and destructors.
if (isPDBLoaded) {
monitor.setMessage(
"Attempting to use pdb to assign class hierarchies and extend known pdb data " +
"type information ...");
retrieveExistingClassStructures(recoveredClasses);
// assign constructors and destructors based on name
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
}
// otherwise figure everything out from scratch
else {
monitor.setMessage("Figuring out class method types");
// println(
// "Figuring out class method types (constructor, destructor, inline constructor, " +
// "inline destructor, deleting destructor, clone) ...");
processConstructorAndDestructors(recoveredClasses);
}
// create order of vftable in constructor map for each class that has a constructor so far
createVftableOrderMap(recoveredClasses);
determineParentClassInfoFromBaseClassArray(recoveredClasses);
assignParentClassToVftables(recoveredClasses);
// using all the information found above, create the class structures, add the constructor,
// destructor, vfunctions to class which finds the appropriate class structure and assigns
// to "this" param
//println("Creating class data types and applying class structures...");
monitor.setMessage("Creating class data types and applying class structures");
figureOutClassDataMembers(recoveredClasses);
if (USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS) {
extraUtils.createShortenedTemplateNamesForClasses(recoveredClasses);
}
createAndApplyClassStructures(recoveredClasses);
if (!isPDBLoaded) {
// create better vftable labels for multi vftable classes
updateMultiVftableLabels(recoveredClasses);
//println("Removing erroneous FID namespaces and corresponding class data types");
removeEmptyClassesAndStructures();
}
// If no new classes have been recovered, no need to continue. Return out of script.
if (recoveredClasses.isEmpty()) {
return recoveredClasses;
}
catch (CancelledException e) {
e.printStackTrace();
return null;
createCalledFunctionMap(recoveredClasses);
// figure out class hierarchies using either RTTI or vftable refs
monitor.setMessage("Assigning class inheritance and hierarchies");
assignClassInheritanceAndHierarchies(recoveredClasses);
// Since PDB has applied so much information, use it to figure out the class member data 4
// items (if it has them) and the constructors and destructors.
if (isPDBLoaded) {
monitor.setMessage(
"Attempting to use pdb to assign class hierarchies and extend known pdb data " +
"type information ...");
retrieveExistingClassStructures(recoveredClasses);
// assign constructors and destructors based on name
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
}
catch (Exception e) {
e.printStackTrace();
return null;
// otherwise figure everything out from scratch
else {
monitor.setMessage("Figuring out class method types");
// println(
// "Figuring out class method types (constructor, destructor, inline constructor, " +
// "inline destructor, deleting destructor, clone) ...");
processConstructorAndDestructors(recoveredClasses);
}
// create order of vftable in constructor map for each class that has a constructor so far
createVftableOrderMap(recoveredClasses);
determineParentClassInfoFromBaseClassArray(recoveredClasses);
assignParentClassToVftables(recoveredClasses);
// using all the information found above, create the class structures, add the constructor,
// destructor, vfunctions to class which finds the appropriate class structure and assigns
// to "this" param
//println("Creating class data types and applying class structures...");
monitor.setMessage("Creating class data types and applying class structures");
figureOutClassDataMembers(recoveredClasses);
if (USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS) {
extraUtils.createShortenedTemplateNamesForClasses(recoveredClasses);
}
createAndApplyClassStructures(recoveredClasses);
if (!isPDBLoaded) {
// create better vftable labels for multi vftable classes
updateMultiVftableLabels(recoveredClasses);
//println("Removing erroneous FID namespaces and corresponding class data types");
removeEmptyClassesAndStructures();
}
return recoveredClasses;
}
private boolean isVisualStudioOrClangPe() {
@ -351,7 +328,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
continue;
}
//println("Cannot create RTTI_CompleteObjectLocator at " + symbol.getAddress());
Msg.debug(this, "Cannot create RTTI_CompleteObjectLocator at " + symbol.getAddress());
}
return completeObjectLocatorSymbols;
@ -417,7 +394,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
continue;
}
//println("Cannot create RTTI_Base_Class_Descriptor at " + symbol.getAddress());
Msg.debug(this, "Cannot create RTTI_Base_Class_Descriptor at " + symbol.getAddress());
}
return baseClassDescriptorSymbols;
@ -661,8 +638,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
continue;
}
// println("Failed to create a baseClassDescArray structure at " +
// baseClassArrayAddress.toString());
Msg.debug(this, "Failed to create a baseClassDescArray structure at " +
baseClassArrayAddress.toString());
}
return baseClassArrayAddresses;
}
@ -736,13 +713,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace();
if (classNamespace.equals(globalNamespace)) {
//println("no class namespace for " + completeObjectLocatorAddress.toString());
Msg.debug(this,
"No class namespace for " + completeObjectLocatorAddress.toString());
continue;
}
Reference[] referencesTo = extraUtils.getReferencesTo(completeObjectLocatorAddress);
if (referencesTo.length == 0) {
//println("no refs to " + completeObjectLocatorAddress.toString());
Msg.debug(this, "No refs to " + completeObjectLocatorAddress.toString());
continue;
}
@ -995,7 +973,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
* @throws Exception when cancelled
*/
private void determineVftableOffsetsfromRTTI(List<RecoveredClass> recoveredClasses)
throws Exception {
throws AddressOutOfBoundsException, Exception {
PointerDataType pointerDataType = new PointerDataType();
@ -1020,22 +998,16 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
Address colAddress = extraUtils.getReferencedAddress(ptrToColAddress, false);
if (colAddress == null) {
// println(recoveredClass.getName() + " couldn't get referenced col from " +
// ptrToColAddress.toString());
Msg.debug(this, recoveredClass.getName() +
" couldn't get referenced col from " + ptrToColAddress.toString());
continue;
}
try {
Address addressOfOffset = colAddress.add(4);
Address addressOfOffset = colAddress.add(4);
int offset = extraUtils.getInt(addressOfOffset);
int offset = extraUtils.getInt(addressOfOffset);
recoveredClass.addClassOffsetToVftableMapping(offset, vftableAddress);
}
catch (AddressOutOfBoundsException e) {
// println(recoveredClass.getName() + "error getting offset at address " +
// colAddress.toString() + " + 4");
}
recoveredClass.addClassOffsetToVftableMapping(offset, vftableAddress);
}
}
@ -1063,9 +1035,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
int inheritanceFlag = getClassInheritanceFlag(recoveredClass.getClassNamespace());
if (inheritanceFlag == NONE) {
// println(
// "Could not get inheritance attribute from class hierarchy structure for " +
// "class " + recoveredClass.getName());
Msg.debug(this,
"Could not get inheritance attribute from class hierarchy structure for " +
"class " + recoveredClass.getName());
recoveredClassesIterator.remove();
continue;
}
@ -1250,21 +1222,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
RTTI_CLASS_HIERARCHY_DESCRIPTOR_LABEL, classNamespace, false);
if (symbols.size() >= 1) {
try {
return (extraUtils.getInt(symbols.get(0).getAddress().add(4)));
}
catch (MemoryAccessException e) {
// println("Could not get class inheritance flag at address " +
// symbols.get(0).getAddress().toString());
return NONE;
}
catch (AddressOutOfBoundsException e) {
// println("Could not get class inheritance flag at address " +
// symbols.get(0).getAddress().toString());
return NONE;
}
return (extraUtils.getInt(symbols.get(0).getAddress().add(4)));
}
return NONE;
}
@ -1399,7 +1359,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
// this should never happen
if (baseClassArray.size() != 1) {
throw new Exception(
recoveredClass.getName() + " has more than one base class array");
recoveredClass.getName() + " has more than one RTTI base class array");
}
Address baseClassArrayAddress = baseClassArray.get(0).getAddress();
@ -1407,7 +1367,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
if (!baseClassArrayData.isArray()) {
throw new Exception(
recoveredClass.getName() + " base class array is not an array data type");
recoveredClass.getName() + " RTTI base class array is not an array data type " +
baseClassArrayAddress.toString());
}
@ -2690,9 +2651,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
* @return the offset of the single virtual parent or null if there is not a single virtual parent
* or if there is no mapping in the offset map for that parent
* @throws CancelledException if cancelled
* @throws AddressOutOfBoundsException
* @throws MemoryAccessException
*/
public Integer getSingleVirtualParentOffset(RecoveredClass recoveredClass)
throws CancelledException {
throws CancelledException, MemoryAccessException, AddressOutOfBoundsException {
List<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass);
if (virtualParentClasses.size() != 1) {
@ -2706,7 +2669,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
}
private Map<RecoveredClass, Integer> getBaseClassOffsetMap(RecoveredClass recoveredClass)
throws CancelledException {
throws CancelledException, MemoryAccessException, AddressOutOfBoundsException {
Map<RecoveredClass, Integer> parentOffsetMap = new HashMap<RecoveredClass, Integer>();
@ -2727,52 +2690,39 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
continue;
}
try {
RecoveredClass baseClass =
getClassFromBaseClassDescriptor(baseClassDescriptorAddress);
if (baseClass == null) {
// TODO: msg and return null
continue;
}
// Continue if the class has mult inh but base class is not on the parent list
//TODO: possibly update to include all base classes
if (!recoveredClass.getParentList().contains(baseClass)) {
continue;
}
int mdisp = api.getInt(baseClassDescriptorAddress.add(8));
int pdisp = api.getInt(baseClassDescriptorAddress.add(12));
int vdisp = api.getInt(baseClassDescriptorAddress.add(16));
if (pdisp == -1) {
baseClassOffset = mdisp;
}
else {
// else need to fill in the virtually inherited ones
// get the offset of this base class in the class using the vbtable
Address vbtableAddress = recoveredClass.getVbtableAddress();
if (vbtableAddress == null) {
Msg.error(this,
"Cannot retrieve vbtable address so cannot create base class offset map for class " +
recoveredClass.getName());
return null;
}
baseClassOffset =
api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
}
parentOffsetMap.put(baseClass, baseClassOffset);
RecoveredClass baseClass = getClassFromBaseClassDescriptor(baseClassDescriptorAddress);
if (baseClass == null) {
// TODO: return null?
Msg.debug(this, "Could not get base class from baseClassDescriptor " +
baseClassDescriptorAddress.toString());
continue;
}
catch (MemoryAccessException | AddressOutOfBoundsException e) {
Msg.error(this,
"Cannot create base class offset map for class " + recoveredClass.getName());
return null;
// Continue if the class has mult inh but base class is not on the parent list
//TODO: possibly update to include all base classes
if (!recoveredClass.getParentList().contains(baseClass)) {
continue;
}
int mdisp = api.getInt(baseClassDescriptorAddress.add(8));
int pdisp = api.getInt(baseClassDescriptorAddress.add(12));
int vdisp = api.getInt(baseClassDescriptorAddress.add(16));
if (pdisp == -1) {
baseClassOffset = mdisp;
}
else {
// else need to fill in the virtually inherited ones
// get the offset of this base class in the class using the vbtable
Address vbtableAddress = recoveredClass.getVbtableAddress();
if (vbtableAddress == null) {
Msg.error(this,
"Cannot retrieve vbtable address so cannot create base class offset map for class " +
recoveredClass.getName());
return null;
}
baseClassOffset = api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
}
parentOffsetMap.put(baseClass, baseClassOffset);
}
return parentOffsetMap;
}
@ -2885,9 +2835,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
* order to distinguish which base class the vftable is for.
* @param recoveredClasses the list of RecoveredClass objects
* @throws CancelledException if cancelled
* @throws InvalidInputException if bad chars trying to label
* @throws DuplicateNameException if duplicate name
*/
private void updateMultiVftableLabels(List<RecoveredClass> recoveredClasses)
throws CancelledException {
throws CancelledException, DuplicateNameException, InvalidInputException {
if (recoveredClasses.isEmpty()) {
return;
@ -2914,19 +2866,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
if (!shortenedTemplateName.isBlank()) {
baseClassName = shortenedTemplateName;
}
try {
primarySymbol.setName("vftable_for_" + baseClassName,
primarySymbol.getSource());
}
catch (DuplicateNameException e) {
// skip if it's already the correct name
}
catch (InvalidInputException e) {
Msg.debug(this,
"Could not create vftable_for_" + baseClassName +
" due to invalid input exeption at address " +
vftableAddress.toString());
}
primarySymbol.setName("vftable_for_" + baseClassName,
primarySymbol.getSource());
}
}
}

View file

@ -148,7 +148,8 @@ public class RecoveredClassUtils {
public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool,
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) {
boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor)
throws Exception {
this.monitor = monitor;
this.program = program;
@ -551,13 +552,13 @@ public class RecoveredClassUtils {
}
/**
* Method to return reference to the class vftable in the given function
* Method to return the first reference to the class vftable in the given function
* @param recoveredClass the given class
* @param function the given function
* @return the reference to the class vftable in the given function or null if there isn't one
* @throws CancelledException if cancelled
*/
public Address getClassVftableReference(RecoveredClass recoveredClass,
public Address getFirstClassVftableReference(RecoveredClass recoveredClass,
Function function) throws CancelledException {
List<Address> vftableReferenceList = functionToVftableRefsMap.get(function);
@ -566,6 +567,8 @@ public class RecoveredClassUtils {
return null;
}
Collections.sort(vftableReferenceList);
Iterator<Address> vftableRefs = vftableReferenceList.iterator();
while (vftableRefs.hasNext()) {
monitor.checkCanceled();
@ -589,39 +592,6 @@ public class RecoveredClassUtils {
}
/**
* Method to return the vftable reference in the given function that corresponds to the given class
* @param function the given function
* @param recoveredClass the given class
* @return the vftableRef address in the given function that corresponds to the given class
* @throws CancelledException if cancelled
*/
public Address getClassVftableRefInFunction(Function function, RecoveredClass recoveredClass)
throws CancelledException {
List<Address> listOfClassRefsInFunction =
getSortedListOfAncestorRefsInFunction(function, recoveredClass);
Iterator<Address> iterator = listOfClassRefsInFunction.iterator();
while (iterator.hasNext()) {
monitor.checkCanceled();
Address classRef = iterator.next();
Address vftableAddress = vftableRefToVftableMap.get(classRef);
// skip the ones that aren't vftable refs
if (vftableAddress == null) {
continue;
}
// return the first one that is a vftable ref to the given class
RecoveredClass vftableClass = vftableToClassMap.get(vftableAddress);
if (vftableClass.equals(recoveredClass)) {
return classRef;
}
}
return null;
}
/**
* Method to get a sorted list of both vftable and call refs to ancestor classes of the given
* class in the given function
@ -3389,7 +3359,7 @@ public class RecoveredClassUtils {
replaceClassStructure(destructorFunction, className, classStruct);
}
destructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
destructorFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
}
}
@ -3445,7 +3415,7 @@ public class RecoveredClassUtils {
classStruct);
}
vbaseDestructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
vbaseDestructorFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
}
}
@ -3635,7 +3605,9 @@ public class RecoveredClassUtils {
return true;
}
//TODO: decide whether to replace dwarf or not
if (categoryPath.contains("DWARF")) {
return true;
}
// test to see if the data type is an empty structure with "PlaceHolder Class Structure" in
// the description
@ -5146,25 +5118,12 @@ public class RecoveredClassUtils {
while (inlinedDestructorIterator.hasNext()) {
monitor.checkCanceled();
Function destructorFunction = inlinedDestructorIterator.next();
Address classVftableRef =
getClassVftableRefInFunction(destructorFunction, recoveredClass);
//TODO: use this one instead if testing pans out
Address otherWayRef = getClassVftableReference(recoveredClass, destructorFunction);
Address classVftableRef = getFirstClassVftableReference(recoveredClass, destructorFunction);
if (classVftableRef == null) {
continue;
}
//TODO: remove after testing
if (!classVftableRef.equals(otherWayRef)) {
if (DEBUG) {
Msg.debug(this, recoveredClass.getName() + " function " +
destructorFunction.getEntryPoint().toString() + " first ref: " +
classVftableRef.toString() + " other way ref: " + otherWayRef.toString());
}
}
String markupString = classNamespace.getName(true) + "::~" + className;
api.setPreComment(classVftableRef, "inlined destructor: " + markupString);
@ -5189,24 +5148,11 @@ public class RecoveredClassUtils {
Function functionContainingInline = functionsContainingInlineIterator.next();
Address classVftableRef =
getClassVftableRefInFunction(functionContainingInline, recoveredClass);
//TODO: use this one if testing more progs gives same results
Address otherWayRef =
getClassVftableReference(recoveredClass, functionContainingInline);
getFirstClassVftableReference(recoveredClass, functionContainingInline);
if (classVftableRef == null) {
continue;
}
//TODO: remove after testing
if (!classVftableRef.equals(otherWayRef)) {
if (DEBUG) {
Msg.debug(this,
recoveredClass.getName() + " function " +
functionContainingInline.getEntryPoint().toString() + " first ref: " +
classVftableRef.toString() + " other way ref: " +
otherWayRef.toString());
}
}
String markupString = "inlined constructor or destructor (approx location) for " +
classNamespace.getName(true);
@ -5419,22 +5365,11 @@ public class RecoveredClassUtils {
// Type 4 inlined - inlined class c/d called from other than first function
// either just vftable ref before operator delete or vftableref followed by parent call
// before operator delete
Address vftableReference = getFirstClassVftableReference(recoveredClass, virtualFunction);
Address vftableReference = getClassVftableReference(recoveredClass, virtualFunction);
//TODO remove after testing against prev method in more progs
Address otherWayRef = getClassVftableRefInFunction(virtualFunction, recoveredClass);
if (vftableReference == null) {
return;
}
if (!vftableReference.equals(otherWayRef)) {
if (DEBUG) {
Msg.debug(this, recoveredClass.getName() + " function " +
virtualFunction.getEntryPoint().toString() + " first ref: " +
vftableReference.toString() + " other way ref (with ances): " +
otherWayRef.toString());
}
}
List<Function> possibleParentDestructors = getPossibleParentDestructors(virtualFunction);
@ -5725,43 +5660,6 @@ public class RecoveredClassUtils {
}
private boolean isDataAtOffsetEquivalentToStructure(Structure outerStructure,
Structure innerStructure, int offset) {
DataTypeComponent[] innerStructComponents = innerStructure.getDefinedComponents();
for (DataTypeComponent innerComponent : innerStructComponents) {
int innerOffset = innerComponent.getOffset();
DataTypeComponent outerComponent = outerStructure.getComponentAt(offset + innerOffset);
if (outerComponent == null) {
return false;
}
if (innerComponent.getFieldName().equals("vftablePtr")) {
// if one is vftablePtr and other isn't - return false
if (!outerComponent.getFieldName().equals("vftablePtr")) {
return false;
}
// if both are vftablePtrs they should both contain the innerStructure name (ie the class name) in
// the vftablePtr data type name (either <some_class_name>_vftable_for_<innerStruct name> or <innerStruct name>_vftable *
if (outerComponent.getDataType().getDisplayName().contains(
innerStructure.getName()) &&
!innerComponent.getDataType().getDisplayName().contains(
innerStructure.getName())) {
return false;
}
continue;
}
if (!innerComponent.getDataType().equals(outerComponent.getDataType())) {
return false;
}
}
return true;
}
/**
* Method to determine if the given data type is the virtual parent class structure for the given class
* @param recoveredClass the given class
@ -6552,7 +6450,7 @@ public class RecoveredClassUtils {
if (!atexitCalledFunctions.contains(calledFunction)) {
atexitCalledFunctions.add(calledFunction);
}
calledFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
calledFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
}
else {
if (!atexitCalledFunctions.contains(calledFunction)) {

View file

@ -61,6 +61,7 @@
# 1010 0100 ssss tttt # user_four rs rt user_four rs rt
# 1010 0101 nnnn nnnn # user_five n user_five n
# 1010 0110 ssss 0000 # user_six rs user_six rs
# 1010 1000 0000 0000 # unimpl
#
#### RESERVED
# 1101 1001 xxxx xxxx # RESERVED BANK
@ -222,3 +223,4 @@ define pcodeop pcodeop_three;
:user_five Rel8 is $(INSTR_PHASE) op1215=0xa & op0811=0x05 & Rel8 { lr = inst_next; call Rel8; pcodeop_three();}
:user_six rs is $(INSTR_PHASE) op1215=0xa & op0811=0x06 & rs & op0003=0x0 { r1 = pcodeop_one(rs); call [r1];}
:unimpl is $(INSTR_PHASE) op1215=0xa & op0811=0x08 & op0007=0 unimpl