mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch 'origin/Ghidra_10.1'
This commit is contained in:
commit
d6841fbe0f
10 changed files with 468 additions and 633 deletions
|
@ -983,4 +983,27 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
emuThread.stepInstruction();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
public void stepOp(PcodeOp op, PcodeFrame frame, SleighUseropLibrary<T> library) {
|
||||||
OpBehavior b = OpBehaviorFactory.getOpBehavior(op.getOpcode());
|
OpBehavior b = OpBehaviorFactory.getOpBehavior(op.getOpcode());
|
||||||
if (b == null) {
|
if (b == null) {
|
||||||
throw new LowlevelError("Unsupported pcode op" + op);
|
badOp(op);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (b instanceof UnaryOpBehavior) {
|
if (b instanceof UnaryOpBehavior) {
|
||||||
executeUnaryOp(op, (UnaryOpBehavior) b);
|
executeUnaryOp(op, (UnaryOpBehavior) b);
|
||||||
|
@ -164,7 +176,8 @@ public class PcodeExecutor<T> {
|
||||||
executeReturn(op, frame);
|
executeReturn(op, frame);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
throw new LowlevelError("Unsupported op " + op);
|
badOp(op);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,18 @@ import ghidra.app.services.GraphDisplayBroker;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.service.graph.*;
|
import ghidra.service.graph.*;
|
||||||
|
import ghidra.util.WebColors;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class GraphClassesScript extends GhidraScript {
|
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>();
|
List<Structure> classStructures = new ArrayList<Structure>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,7 +114,15 @@ public class GraphClassesScript extends GhidraScript {
|
||||||
*/
|
*/
|
||||||
private AttributedGraph createGraph() throws Exception {
|
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) {
|
for (Structure classStructure : classStructures) {
|
||||||
|
|
||||||
|
@ -176,24 +191,27 @@ public class GraphClassesScript extends GhidraScript {
|
||||||
|
|
||||||
AttributedEdge edge = g.addEdge(parentVertex, classVertex);
|
AttributedEdge edge = g.addEdge(parentVertex, classVertex);
|
||||||
if (isVirtualParent) {
|
if (isVirtualParent) {
|
||||||
edge.setAttribute("Color", "Orange");
|
edge.setEdgeType(VIRTUAL_INHERITANCE);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
// else leave it default lime green
|
// else leave it default lime green
|
||||||
|
edge.setEdgeType(NON_VIRTUAL_INHERITANCE);
|
||||||
|
}
|
||||||
|
|
||||||
description = removeClassSubstring(description, parentName);
|
description = removeClassSubstring(description, parentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// no parent = blue vertex
|
// no parent = blue vertex
|
||||||
if (numParents == 0) {
|
if (numParents == 0) {
|
||||||
classVertex.setAttribute("Color", "Blue");
|
classVertex.setVertexType(NO_INHERITANCE);
|
||||||
}
|
}
|
||||||
// single parent = green vertex
|
// single parent = green vertex
|
||||||
else if (numParents == 1) {
|
else if (numParents == 1) {
|
||||||
classVertex.setAttribute("Color", "Green");
|
classVertex.setVertexType(SINGLE_INHERITANCE);
|
||||||
}
|
}
|
||||||
// multiple parents = red vertex
|
// multiple parents = red vertex
|
||||||
else {
|
else {
|
||||||
classVertex.setAttribute("Color", "Red");
|
classVertex.setVertexType(MULTIPLE_INHERITANCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +313,20 @@ public class GraphClassesScript extends GhidraScript {
|
||||||
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
|
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
|
||||||
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
|
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
|
||||||
display = service.getGraphDisplay(false, TaskMonitor.DUMMY);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
// this script and default vfunctions named by this script are likely to change in the future
|
// 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.
|
// 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
|
// 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
|
// virtual inheritance but if the program contains DWARF, there will be some amount of data recovered
|
||||||
// by the DWARF analyzer.
|
// by the DWARF analyzer.
|
||||||
// NOTE: For likely the best results, run this script on freshly analyzed programs. No testing has been
|
// 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.services.GraphDisplayBroker;
|
||||||
import ghidra.app.util.bin.format.dwarf4.next.DWARFFunctionImporter;
|
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.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.bin.format.pdb.PdbParserConstants;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
|
@ -74,6 +76,7 @@ import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.service.graph.*;
|
import ghidra.service.graph.*;
|
||||||
|
import ghidra.util.WebColors;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.exception.GraphException;
|
import ghidra.util.exception.GraphException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
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 orange if child inherits the parent virtually
|
||||||
// edge between child and parent is lime green if child inherits the parent non-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 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
|
// show shortened class template names in class structure field names
|
||||||
private static final boolean USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS = true;
|
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";
|
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
|
// If replacedClassStructuresOption is set to the following, no replaced structures will be removed
|
||||||
// from the data type manager
|
// 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
|
// 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
|
// 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
|
// 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
|
// were replaced by this script, including non-emtpy ones, will be removed from the data type
|
||||||
// manager
|
// 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 -
|
// NEW OPTION -
|
||||||
// This option allows the user to decide whether and how to remove replaced existing class structures
|
// This option allows the user to decide whether and how to remove replaced existing class structures
|
||||||
// using one of the above three flags
|
// 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 programHasRTTIApplied = false;
|
||||||
boolean hasDebugSymbols;
|
boolean hasDebugSymbols;
|
||||||
|
@ -178,16 +192,14 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (isWindows()) {
|
if (isWindows()) {
|
||||||
|
|
||||||
hasDebugSymbols = isPDBLoadedInProgram();
|
hasDebugSymbols = isPDBLoadedInProgram();
|
||||||
nameVfunctions = !hasDebugSymbols;
|
nameVfunctions = !hasDebugSymbols;
|
||||||
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram,
|
recoverClassesFromRTTI =
|
||||||
currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
|
new RTTIWindowsClassRecoverer(currentProgram, currentLocation, state.getTool(),
|
||||||
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
|
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||||
REPLACE_EXISTING_CLASS_STRUCTURES,
|
nameVfunctions, hasDebugSymbols, REPLACE_EXISTING_CLASS_STRUCTURES, monitor);
|
||||||
monitor);
|
|
||||||
}
|
}
|
||||||
else if (isGcc()) {
|
else if (isGcc()) {
|
||||||
|
|
||||||
|
@ -204,11 +216,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nameVfunctions = !hasDebugSymbols;
|
nameVfunctions = !hasDebugSymbols;
|
||||||
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
|
recoverClassesFromRTTI =
|
||||||
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
|
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
|
||||||
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
|
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||||
REPLACE_EXISTING_CLASS_STRUCTURES,
|
nameVfunctions, hasDebugSymbols, REPLACE_EXISTING_CLASS_STRUCTURES, monitor);
|
||||||
monitor);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
println("This script will not work on this program type");
|
println("This script will not work on this program type");
|
||||||
|
@ -281,7 +292,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
getNumberOfConstructorsOrDestructors(recoveredClasses) +
|
getNumberOfConstructorsOrDestructors(recoveredClasses) +
|
||||||
" class member functions to assign.");
|
" class member functions to assign.");
|
||||||
|
|
||||||
|
|
||||||
if (!hasDebugSymbols) {
|
if (!hasDebugSymbols) {
|
||||||
|
|
||||||
if (BOOKMARK_FOUND_FUNCTIONS) {
|
if (BOOKMARK_FOUND_FUNCTIONS) {
|
||||||
|
@ -301,23 +311,32 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
showGraph(graph);
|
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");
|
println("Removing all empty replaced class structures from the data type manager");
|
||||||
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, false);
|
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replacedClassStructuresOption == REMOVE_ALL_REPLACED_CLASS_STRUCTURES) {
|
if (replacedClassStructuresOption == removeOption.REMOVE_ALL_REPLACED_CLASS_STRUCTURES) {
|
||||||
println(
|
println(
|
||||||
"Removing all replaced class structures from the data type manager, including non-empty ones");
|
"Removing all replaced class structures from the data type manager, including non-empty ones");
|
||||||
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, true);
|
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
decompilerUtils.disposeDecompilerInterface();
|
decompilerUtils.disposeDecompilerInterface();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasDwarf() {
|
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() {
|
private boolean isDwarfLoadedInProgram() {
|
||||||
|
|
||||||
return DWARFFunctionImporter.hasDWARFProgModule(currentProgram,
|
Options options = currentProgram.getOptions(Program.PROGRAM_INFO);
|
||||||
DWARFProgram.DWARF_ROOT_NAME);
|
|
||||||
|
return (DWARFFunctionImporter.hasDWARFProgModule(currentProgram,
|
||||||
|
DWARFProgram.DWARF_ROOT_NAME) || options.getBoolean("DWARF Loaded", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String validate() {
|
public String validate() {
|
||||||
|
@ -392,7 +413,15 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
private AttributedGraph createGraph(List<RecoveredClass> recoveredClasses)
|
private AttributedGraph createGraph(List<RecoveredClass> recoveredClasses)
|
||||||
throws CancelledException {
|
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();
|
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
||||||
while (recoveredClassIterator.hasNext()) {
|
while (recoveredClassIterator.hasNext()) {
|
||||||
|
@ -408,7 +437,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
|
|
||||||
// no parent = blue vertex
|
// no parent = blue vertex
|
||||||
if (classHierarchyMap.isEmpty()) {
|
if (classHierarchyMap.isEmpty()) {
|
||||||
classVertex.setAttribute("Color", "Blue");
|
classVertex.setVertexType(NO_INHERITANCE);
|
||||||
classVertex.setDescription(recoveredClass.getClassPath().getPath());
|
classVertex.setDescription(recoveredClass.getClassPath().getPath());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -417,11 +446,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
|
|
||||||
// single parent = green vertex
|
// single parent = green vertex
|
||||||
if (parents.size() == 1) {
|
if (parents.size() == 1) {
|
||||||
classVertex.setAttribute("Color", "Green");
|
classVertex.setVertexType(SINGLE_INHERITANCE);
|
||||||
}
|
}
|
||||||
// multiple parents = red vertex
|
// multiple parents = red vertex
|
||||||
else {
|
else {
|
||||||
classVertex.setAttribute("Color", "Red");
|
classVertex.setVertexType(MULTIPLE_INHERITANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
classVertex.setDescription(recoveredClass.getClassPath().getPath());
|
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
|
// edge between child and parent is orange if child inherits the parent virtually
|
||||||
if (isVirtualParent) {
|
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);
|
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
|
||||||
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
|
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
|
||||||
display = service.getGraphDisplay(false, TaskMonitor.DUMMY);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1045,8 +1045,10 @@ public class ExtraScriptUtils extends FlatProgramAPI {
|
||||||
* @param parent parent CategoryPath
|
* @param parent parent CategoryPath
|
||||||
* @param categoryName name of the new category in the parent path
|
* @param categoryName name of the new category in the parent path
|
||||||
* @return CategoryPath for new categoryName
|
* @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;
|
CategoryPath dataTypePath;
|
||||||
|
|
||||||
|
@ -1070,12 +1072,8 @@ public class ExtraScriptUtils extends FlatProgramAPI {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
String newCategoryName = new String();
|
String newCategoryName = new String();
|
||||||
while (index < categoryName.length()) {
|
while (index < categoryName.length()) {
|
||||||
try {
|
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
}
|
|
||||||
catch (CancelledException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (categoryName.substring(index).startsWith("::") && !insideBrackets) {
|
if (categoryName.substring(index).startsWith("::") && !insideBrackets) {
|
||||||
newCategoryName = newCategoryName.concat("/");
|
newCategoryName = newCategoryName.concat("/");
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
||||||
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
||||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||||
boolean nameVfunctions, boolean hasDebugSymbols, boolean replaceClassStructures,
|
boolean nameVfunctions, boolean hasDebugSymbols, boolean replaceClassStructures,
|
||||||
TaskMonitor monitor) {
|
TaskMonitor monitor) throws Exception {
|
||||||
|
|
||||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||||
replaceClassStructures,
|
replaceClassStructures,
|
||||||
|
@ -76,7 +76,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
||||||
return dataTypeManager;
|
return dataTypeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsRTTI() throws CancelledException {
|
public boolean containsRTTI() throws CancelledException, InvalidInputException {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,12 +104,12 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void fixUpProgram() {
|
public void fixUpProgram() throws CancelledException, Exception {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<RecoveredClass> createRecoveredClasses() {
|
public List<RecoveredClass> createRecoveredClasses() throws Exception {
|
||||||
|
|
||||||
return new ArrayList<RecoveredClass>();
|
return new ArrayList<RecoveredClass>();
|
||||||
}
|
}
|
||||||
|
@ -121,10 +121,10 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
||||||
* Method to promote the namespace is a class namespace.
|
* Method to promote the namespace is a class namespace.
|
||||||
* @param namespace the namespace for the vftable
|
* @param namespace the namespace for the vftable
|
||||||
* @return true if namespace is (now) a class namespace or false if it could not be promoted.
|
* @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);
|
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
||||||
|
|
||||||
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
||||||
|
@ -135,13 +135,6 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
||||||
"Could not promote " + namespace.getName() + " to a class namespace");
|
"Could not promote " + namespace.getName() + " to a class namespace");
|
||||||
return null;
|
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 existingClassStructure =
|
||||||
(Structure) dataTypeManager.getDataType(dataTypePath, dataTypeName);
|
(Structure) dataTypeManager.getDataType(dataTypePath, dataTypeName);
|
||||||
|
|
||||||
if (!existingClassStructure.isNotYetDefined()) {
|
if (existingClassStructure != null && !existingClassStructure.isNotYetDefined()) {
|
||||||
recoveredClass.addExistingClassStructure(existingClassStructure);
|
recoveredClass.addExistingClassStructure(existingClassStructure);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,18 +74,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
||||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||||
boolean nameVfunctions, boolean isDwarfLoaded, boolean replaceExistingClassStructures,
|
boolean nameVfunctions, boolean isDwarfLoaded, boolean replaceExistingClassStructures,
|
||||||
TaskMonitor monitor) {
|
TaskMonitor monitor) throws Exception {
|
||||||
|
|
||||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||||
replaceExistingClassStructures,
|
replaceExistingClassStructures, isDwarfLoaded, monitor);
|
||||||
isDwarfLoaded,
|
|
||||||
monitor);
|
|
||||||
this.isDwarfLoaded = isDwarfLoaded;
|
this.isDwarfLoaded = isDwarfLoaded;
|
||||||
this.replaceClassStructs = replaceExistingClassStructures;
|
this.replaceClassStructs = replaceExistingClassStructures;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsRTTI() throws CancelledException {
|
public boolean containsRTTI() throws CancelledException, InvalidInputException {
|
||||||
|
|
||||||
if (!hasSpecialVtable()) {
|
if (!hasSpecialVtable()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -103,9 +101,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RecoveredClass> createRecoveredClasses() {
|
public List<RecoveredClass> createRecoveredClasses() throws CancelledException, Exception {
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
processGccRTTI();
|
processGccRTTI();
|
||||||
if (recoveredClasses == null) {
|
if (recoveredClasses == null) {
|
||||||
|
@ -132,15 +128,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
createAndApplyClassStructures();
|
createAndApplyClassStructures();
|
||||||
|
|
||||||
return recoveredClasses;
|
return recoveredClasses;
|
||||||
}
|
|
||||||
catch (CancelledException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,8 +158,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
||||||
|
|
||||||
Address found = program.getMemory()
|
Address found = program.getMemory()
|
||||||
.findBytes(commentBlock.getStart(),
|
.findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, maskBytes,
|
||||||
commentBlock.getEnd(), gccBytes, maskBytes, true, monitor);
|
true, monitor);
|
||||||
if (found == null) {
|
if (found == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -184,8 +171,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* Method to check for at least one special RTTI vtable
|
* Method to check for at least one special RTTI vtable
|
||||||
* @return true if the program has at least one special vtable, false if none
|
* @return true if the program has at least one special vtable, false if none
|
||||||
* @throws CancelledException if cancelled
|
* @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();
|
boolean hasSpecialVtable = createSpecialVtables();
|
||||||
return hasSpecialVtable;
|
return hasSpecialVtable;
|
||||||
|
@ -287,8 +275,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateClassesWithParentsAndFlags(List<Symbol> typeinfoSymbols)
|
private void updateClassesWithParentsAndFlags(List<Symbol> typeinfoSymbols) throws Exception {
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
// add properties and parents to each class
|
// add properties and parents to each class
|
||||||
Iterator<Symbol> typeinfoIterator = typeinfoSymbols.iterator();
|
Iterator<Symbol> typeinfoIterator = typeinfoSymbols.iterator();
|
||||||
|
@ -464,6 +451,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
while (vtableIterator.hasNext()) {
|
while (vtableIterator.hasNext()) {
|
||||||
|
|
||||||
|
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
|
|
||||||
Symbol vtableSymbol = vtableIterator.next();
|
Symbol vtableSymbol = vtableIterator.next();
|
||||||
|
@ -534,14 +522,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
throw new Exception("typeinfo has global namespace " + typeinfoAddress);
|
throw new Exception("typeinfo has global namespace " + typeinfoAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
|
Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
|
||||||
classNamespace, SourceType.ANALYSIS);
|
classNamespace, SourceType.ANALYSIS);
|
||||||
vtableSymbols.add(vtableSymbol);
|
vtableSymbols.add(vtableSymbol);
|
||||||
}
|
|
||||||
catch (InvalidInputException e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
api.setPlateComment(vtableAddress, "vtable for " + classNamespace.getName(true));
|
api.setPlateComment(vtableAddress, "vtable for " + classNamespace.getName(true));
|
||||||
}
|
}
|
||||||
|
@ -631,16 +614,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
if (namespacesByPath.isEmpty()) {
|
if (namespacesByPath.isEmpty()) {
|
||||||
|
|
||||||
try {
|
Namespace newNamespace = NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace,
|
||||||
Namespace newNamespace =
|
|
||||||
NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace,
|
|
||||||
program, SourceType.ANALYSIS);
|
program, SourceType.ANALYSIS);
|
||||||
return newNamespace;
|
return newNamespace;
|
||||||
}
|
|
||||||
catch (InvalidInputException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (namespacesByPath.size() == 1) {
|
if (namespacesByPath.size() == 1) {
|
||||||
return namespacesByPath.get(0);
|
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
|
// check direct refs to see if they are in undefined area or not in function
|
||||||
byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, typeinfoAddress);
|
byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, typeinfoAddress);
|
||||||
|
|
||||||
addByteSearchPattern(searcher, validTypeinfoRefs, typeinfoAddress, bytes,
|
addByteSearchPattern(searcher, validTypeinfoRefs, typeinfoAddress, bytes, monitor);
|
||||||
monitor);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
searcher.search(program, searchSet, monitor);
|
searcher.search(program, searchSet, monitor);
|
||||||
|
@ -780,10 +756,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* @param vtableNamespace the namespace of the given vtable
|
* @param vtableNamespace the namespace of the given vtable
|
||||||
* @param isPrimary true if the vtable is the primary one for the class
|
* @param isPrimary true if the vtable is the primary one for the class
|
||||||
* @param listOfAllVtables list of all vtables
|
* @param listOfAllVtables list of all vtables
|
||||||
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
private void processVtable(Address vtableAddress, Namespace vtableNamespace, boolean isPrimary,
|
private void processVtable(Address vtableAddress, Namespace vtableNamespace, boolean isPrimary,
|
||||||
List<Symbol> listOfAllVtables)
|
List<Symbol> listOfAllVtables) throws CancelledException, Exception {
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
// skip the special tables
|
// skip the special tables
|
||||||
if (vtableAddress.equals(class_type_info_vtable) ||
|
if (vtableAddress.equals(class_type_info_vtable) ||
|
||||||
|
@ -818,13 +794,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
Data typeinfoPtr = api.getDataAt(typeinfoAddress);
|
Data typeinfoPtr = api.getDataAt(typeinfoAddress);
|
||||||
if (typeinfoPtr == null) {
|
if (typeinfoPtr == null) {
|
||||||
DataType nullPointer = dataTypeManager.getPointer(null);
|
DataType nullPointer = dataTypeManager.getPointer(null);
|
||||||
try {
|
|
||||||
api.createData(typeinfoAddress, nullPointer);
|
api.createData(typeinfoAddress, nullPointer);
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.debug(this,
|
|
||||||
"Could not create typeinfo pointer at " + typeinfoAddress.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not already named a construction-vtable then check to see if it is one so it can
|
// if not already named a construction-vtable then check to see if it is one so it can
|
||||||
|
@ -850,34 +822,20 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
Namespace classNamespace = createConstructionNamespace(vtableSymbol,
|
Namespace classNamespace = createConstructionNamespace(vtableSymbol,
|
||||||
vttSymbolBeforeConstructionVtable);
|
vttSymbolBeforeConstructionVtable);
|
||||||
|
|
||||||
try {
|
vtableSymbol.setNameAndNamespace("construction-vtable", classNamespace,
|
||||||
vtableSymbol.setNameAndNamespace("construction-vtable",
|
SourceType.ANALYSIS);
|
||||||
classNamespace, SourceType.ANALYSIS);
|
|
||||||
vtableNamespace = vtableSymbol.getParentNamespace();
|
vtableNamespace = vtableSymbol.getParentNamespace();
|
||||||
// label the subVTTaddress
|
// label the subVTTaddress
|
||||||
symbolTable.createLabel(subVTTAddress, "subVTT_" + n,
|
symbolTable.createLabel(subVTTAddress, "subVTT_" + n,
|
||||||
vttSymbolBeforeConstructionVtable.getParentNamespace(),
|
vttSymbolBeforeConstructionVtable.getParentNamespace(),
|
||||||
SourceType.ANALYSIS);
|
SourceType.ANALYSIS);
|
||||||
|
|
||||||
api.setPlateComment(vtableAddress, "construction vtable " + n +
|
api.setPlateComment(vtableAddress,
|
||||||
" for class " +
|
"construction vtable " + n + " for class " +
|
||||||
vttSymbolBeforeConstructionVtable.getParentNamespace()
|
vttSymbolBeforeConstructionVtable.getParentNamespace()
|
||||||
.getName(
|
.getName(true));
|
||||||
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;
|
vftableLabel = "internal_" + vftableLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace,
|
symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace,
|
||||||
SourceType.ANALYSIS);
|
SourceType.ANALYSIS);
|
||||||
|
|
||||||
createVftableArray(possibleVftableAddress, numFunctionPointers);
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for an internal vtable after the vftable and make a symbol there if there is one
|
// check for an internal vtable after the vftable and make a symbol there if there is one
|
||||||
// will process them later
|
// will process them later
|
||||||
|
@ -1050,7 +993,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean createInternalVtable(Address possibleInternalVtableAddress,
|
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
|
// check to see if it is a pointer and if so, it cannot be an internal vtable
|
||||||
// as they contain at least one long
|
// as they contain at least one long
|
||||||
Address pointer = getPointerToDefinedMemory(possibleInternalVtableAddress);
|
Address pointer = getPointerToDefinedMemory(possibleInternalVtableAddress);
|
||||||
|
@ -1071,27 +1014,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
(possibleInternalVtableSymbol.getSource() == SourceType.DEFAULT &&
|
(possibleInternalVtableSymbol.getSource() == SourceType.DEFAULT &&
|
||||||
(isValidVtableStart(possibleInternalVtableAddress) ||
|
(isValidVtableStart(possibleInternalVtableAddress) ||
|
||||||
isValidVftableStart(possibleInternalVtableAddress)))) {
|
isValidVftableStart(possibleInternalVtableAddress)))) {
|
||||||
try {
|
|
||||||
symbolTable.createLabel(possibleInternalVtableAddress,
|
symbolTable.createLabel(possibleInternalVtableAddress,
|
||||||
"internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace,
|
"internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace,
|
||||||
SourceType.ANALYSIS);
|
SourceType.ANALYSIS);
|
||||||
processVtable(possibleInternalVtableAddress, vtableNamespace, false, null);
|
processVtable(possibleInternalVtableAddress, vtableNamespace, false, null);
|
||||||
return true;
|
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();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1102,8 +1030,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* @param classNamespace the given namespace
|
* @param classNamespace the given namespace
|
||||||
* @param address the address of the potential VTT table
|
* @param address the address of the potential VTT table
|
||||||
* @return true if a valid VTT has been discovered and label created
|
* @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
|
// get pointer at address
|
||||||
Address pointer = getPointerToDefinedMemory(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
|
// if it is then create the VTT symbol and create pointer there
|
||||||
try {
|
|
||||||
symbolTable.createLabel(address, "VTT", classNamespace, SourceType.ANALYSIS);
|
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
DataType nullPointer = dataTypeManager.getPointer(null);
|
DataType nullPointer = dataTypeManager.getPointer(null);
|
||||||
try {
|
try {
|
||||||
api.createData(pointer, nullPointer);
|
api.createData(pointer, nullPointer);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
// already data there
|
// already data there so don't try and overwrite it
|
||||||
}
|
}
|
||||||
|
|
||||||
api.setPlateComment(address, "VTT for " + classNamespace.getName(true));
|
api.setPlateComment(address, "VTT for " + classNamespace.getName(true));
|
||||||
|
@ -1144,7 +1066,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Data createVftableArray(Address vftableAddress, int numFunctionPointers)
|
private Data createVftableArray(Address vftableAddress, int numFunctionPointers)
|
||||||
throws CancelledException, AddressOutOfBoundsException {
|
throws Exception {
|
||||||
|
|
||||||
api.clearListing(vftableAddress,
|
api.clearListing(vftableAddress,
|
||||||
vftableAddress.add((numFunctionPointers * defaultPointerSize - 1)));
|
vftableAddress.add((numFunctionPointers * defaultPointerSize - 1)));
|
||||||
|
@ -1152,15 +1074,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
DataType pointerDataType = dataTypeManager.getPointer(null);
|
DataType pointerDataType = dataTypeManager.getPointer(null);
|
||||||
ArrayDataType vftableArrayDataType =
|
ArrayDataType vftableArrayDataType =
|
||||||
new ArrayDataType(pointerDataType, numFunctionPointers, defaultPointerSize);
|
new ArrayDataType(pointerDataType, numFunctionPointers, defaultPointerSize);
|
||||||
try {
|
|
||||||
Data vftableArrayData = api.createData(vftableAddress, vftableArrayDataType);
|
Data vftableArrayData = api.createData(vftableAddress, vftableArrayDataType);
|
||||||
return vftableArrayData;
|
return vftableArrayData;
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to check for a valid vtable at the given address
|
* Method to check for a valid vtable at the given address
|
||||||
|
@ -1349,37 +1266,27 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* @param vtableAddress the given special vtable address
|
* @param vtableAddress the given special vtable address
|
||||||
* @return the address of the typeinfo in the vtable if replace was successful, null otherwise
|
* @return the address of the typeinfo in the vtable if replace was successful, null otherwise
|
||||||
* @throws CancelledException if cancelled
|
* @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);
|
Symbol vtableSymbol = symbolTable.getPrimarySymbol(vtableAddress);
|
||||||
|
|
||||||
api.clearListing(vtableAddress);
|
api.clearListing(vtableAddress);
|
||||||
try {
|
|
||||||
int vtableLongs = createVtableLongs(vtableAddress);
|
int vtableLongs = createVtableLongs(vtableAddress);
|
||||||
|
|
||||||
if (vtableLongs > 0) {
|
if (vtableLongs > 0) {
|
||||||
|
|
||||||
Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize);
|
Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize);
|
||||||
symbolTable.createLabel(typeinfoAddress, "typeinfo",
|
symbolTable.createLabel(typeinfoAddress, "typeinfo", vtableSymbol.getParentNamespace(),
|
||||||
vtableSymbol.getParentNamespace(), SourceType.ANALYSIS);
|
SourceType.ANALYSIS);
|
||||||
return typeinfoAddress;
|
return typeinfoAddress;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (AddressOutOfBoundsException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (InvalidInputException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to create long data type at the given vtable address and return the number created OR
|
* Method to create long data type at the given vtable address and return the number created OR
|
||||||
* if they are already created, just return how many there are
|
* if they are already created, just return how many there are
|
||||||
|
@ -1409,7 +1316,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
api.createData(address, pointer);
|
api.createData(address, pointer);
|
||||||
Address referencedAddress = extraUtils.getSingleReferencedAddress(address);
|
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
|
// the next can be checked
|
||||||
if (referencedAddress == null || !programAddressSet.contains(referencedAddress)) {
|
if (referencedAddress == null || !programAddressSet.contains(referencedAddress)) {
|
||||||
api.clearListing(address);
|
api.clearListing(address);
|
||||||
|
@ -1422,6 +1329,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
return numLongs;
|
return numLongs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if bump into existing data return the number found so far
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
return numLongs;
|
return numLongs;
|
||||||
}
|
}
|
||||||
|
@ -1534,20 +1442,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Data applyTypeinfoStructure(Structure typeInfoStructure, Address typeinfoAddress)
|
private Data applyTypeinfoStructure(Structure typeInfoStructure, Address typeinfoAddress)
|
||||||
throws CancelledException, AddressOutOfBoundsException {
|
throws CancelledException, AddressOutOfBoundsException, Exception {
|
||||||
|
|
||||||
api.clearListing(typeinfoAddress, typeinfoAddress.add(typeInfoStructure.getLength() - 1));
|
api.clearListing(typeinfoAddress, typeinfoAddress.add(typeInfoStructure.getLength() - 1));
|
||||||
Data newStructure;
|
Data newStructure;
|
||||||
try {
|
|
||||||
newStructure = api.createData(typeinfoAddress, typeInfoStructure);
|
newStructure = api.createData(typeinfoAddress, typeInfoStructure);
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
newStructure = null;
|
|
||||||
}
|
|
||||||
if (newStructure == null) {
|
|
||||||
Msg.debug(this,
|
|
||||||
"Could not create " + typeInfoStructure.getName() + " at " + typeinfoAddress);
|
|
||||||
}
|
|
||||||
return newStructure;
|
return newStructure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1560,14 +1461,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
try {
|
try {
|
||||||
numBases = api.getInt(typeinfoAddress.add(offsetOfNumBases));
|
numBases = api.getInt(typeinfoAddress.add(offsetOfNumBases));
|
||||||
}
|
}
|
||||||
|
// if there isn't enough memory to get the int then return null
|
||||||
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get or create the vmiClassTypeInfoStruct
|
// get or create the vmiClassTypeInfoStruct
|
||||||
Structure vmiClassTypeinfoStructure =
|
Structure vmiClassTypeinfoStructure = (Structure) dataTypeManager
|
||||||
(Structure) dataTypeManager.getDataType(classDataTypesCategoryPath,
|
.getDataType(classDataTypesCategoryPath, VMI_CLASS_TYPE_INFO_STRUCTURE + numBases);
|
||||||
VMI_CLASS_TYPE_INFO_STRUCTURE + numBases);
|
|
||||||
if (vmiClassTypeinfoStructure == null) {
|
if (vmiClassTypeinfoStructure == null) {
|
||||||
vmiClassTypeinfoStructure =
|
vmiClassTypeinfoStructure =
|
||||||
createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases);
|
createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases);
|
||||||
|
@ -1575,7 +1476,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
return vmiClassTypeinfoStructure;
|
return vmiClassTypeinfoStructure;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) {
|
private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress)
|
||||||
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
|
||||||
String mangledTypeinfo = getTypeinfoName(typeinfoAddress);
|
String mangledTypeinfo = getTypeinfoName(typeinfoAddress);
|
||||||
if (mangledTypeinfo == null) {
|
if (mangledTypeinfo == null) {
|
||||||
|
@ -1614,25 +1516,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the new typeinfo symbol in the demangled namespace
|
// create the new typeinfo symbol in the demangled namespace
|
||||||
try {
|
|
||||||
Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace,
|
Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace,
|
||||||
SourceType.ANALYSIS);
|
SourceType.ANALYSIS);
|
||||||
return newSymbol;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
private Namespace createTypeinfoClassNamespace(String namespaceString)
|
||||||
|
throws DuplicateNameException, InvalidInputException {
|
||||||
private Namespace createTypeinfoClassNamespace(String namespaceString) {
|
|
||||||
|
|
||||||
int indexOfColons = namespaceString.indexOf("::");
|
int indexOfColons = namespaceString.indexOf("::");
|
||||||
Namespace namespace = globalNamespace;
|
Namespace namespace = globalNamespace;
|
||||||
|
@ -1659,20 +1550,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
return classNamespace;
|
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);
|
Namespace namespace = symbolTable.getNamespace(namespaceName, parentNamespace);
|
||||||
if (namespace == null) {
|
if (namespace == null) {
|
||||||
try {
|
|
||||||
namespace = symbolTable.createNameSpace(parentNamespace, namespaceName,
|
namespace =
|
||||||
SourceType.ANALYSIS);
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
@ -1710,12 +1595,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
StringDataType sdt = new StringDataType();
|
StringDataType sdt = new StringDataType();
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
try {
|
|
||||||
str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen);
|
str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen);
|
||||||
}
|
|
||||||
catch (AddressOutOfBoundsException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1814,27 +1696,38 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
return false;
|
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 {
|
private List<Address> getTypeinfoAddressesUsingSpecialTypeinfos() throws CancelledException {
|
||||||
|
|
||||||
List<Address> specialTypeinfoRefs = new ArrayList<Address>();
|
List<Address> specialTypeinfoRefs = new ArrayList<Address>();
|
||||||
|
|
||||||
|
if (class_type_info != null) {
|
||||||
Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info);
|
Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info);
|
||||||
for (Reference ref : refsToClassTypeinfo) {
|
for (Reference ref : refsToClassTypeinfo) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (si_class_type_info != null) {
|
||||||
Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info);
|
Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info);
|
||||||
for (Reference ref : refsToSiClassTypeinfo) {
|
for (Reference ref : refsToSiClassTypeinfo) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vmi_class_type_info != null) {
|
||||||
Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info);
|
Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info);
|
||||||
for (Reference ref : refsToVmiClassTypeinfo) {
|
for (Reference ref : refsToVmiClassTypeinfo) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return specialTypeinfoRefs;
|
return specialTypeinfoRefs;
|
||||||
}
|
}
|
||||||
|
@ -2153,8 +2046,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
//virtual base offset for the virtual base referenced (negative).
|
//virtual base offset for the virtual base referenced (negative).
|
||||||
long offset = (publicVirtualOffsetFlag & offsetMask) >> 8;
|
long offset = (publicVirtualOffsetFlag & offsetMask) >> 8;
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
Msg.debug(this, "typeinfo " + typeinfoAddress + " base [" + i + "] isVirtual = " +
|
Msg.debug(this, "typeinfo " + typeinfoAddress + " base [" + i + "] isVirtual = " +
|
||||||
isVirtual + " isPublic = " + isPublic + " offset = " + offset);
|
isVirtual + " isPublic = " + isPublic + " offset = " + offset);
|
||||||
|
}
|
||||||
|
|
||||||
// add order to parent and parent offset
|
// add order to parent and parent offset
|
||||||
orderToParentMap.put(i, parentClass);
|
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.
|
* 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
|
* @return true if all found tables have a typeinfo symbol created successfully
|
||||||
* @throws CancelledException if cancelled
|
* @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_vtable = findSpecialVtable("__cxxabiv1", "__class_type_info");
|
||||||
class_type_info = null;
|
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
|
* Use information from RTTI Base class Arrays to create class hierarchy lists and maps
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
private void createClassHierarchyListAndMapForGcc()
|
private void createClassHierarchyListAndMapForGcc() throws CancelledException, Exception {
|
||||||
throws CancelledException, Exception {
|
|
||||||
|
|
||||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
||||||
while (recoveredClassIterator.hasNext()) {
|
while (recoveredClassIterator.hasNext()) {
|
||||||
|
@ -2683,23 +2578,21 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
* address
|
* address
|
||||||
* @param start the starting address
|
* @param start the starting address
|
||||||
* @param end the ending 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();
|
LongDataType longDT = new LongDataType();
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
Address address = start;
|
Address address = start;
|
||||||
while (address != null && !address.equals(end)) {
|
while (address != null && !address.equals(end)) {
|
||||||
try {
|
|
||||||
api.clearListing(address);
|
api.clearListing(address, address.add(defaultPointerSize - 1));
|
||||||
api.createData(address, longDT);
|
api.createData(address, longDT);
|
||||||
offset += defaultPointerSize;
|
offset += defaultPointerSize;
|
||||||
address = getAddress(start, offset);
|
address = getAddress(start, offset);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2868,7 +2761,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
// can't handle creating class data types for classes with virtual parents yet
|
// can't handle creating class data types for classes with virtual parents yet
|
||||||
if (recoveredClass.inheritsVirtualAncestor()) {
|
if (recoveredClass.inheritsVirtualAncestor()) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Cannot create class data type for " +
|
Msg.debug(this,
|
||||||
|
"Cannot create class data type for " +
|
||||||
recoveredClass.getClassNamespace().getName(true) +
|
recoveredClass.getClassNamespace().getName(true) +
|
||||||
" because it has virtual ancestors and we don't yet handle that use case.");
|
" because it has virtual ancestors and we don't yet handle that use case.");
|
||||||
}
|
}
|
||||||
|
@ -2901,19 +2795,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
// and class member data structure
|
// and class member data structure
|
||||||
Structure classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes);
|
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
|
// Now that we have a class data type
|
||||||
// name constructor and destructor functions and put into the class namespace
|
// name constructor and destructor functions and put into the class namespace
|
||||||
addConstructorsToClassNamespace(recoveredClass, classStruct);
|
addConstructorsToClassNamespace(recoveredClass, classStruct);
|
||||||
addDestructorsToClassNamespace(recoveredClass, classStruct);
|
addDestructorsToClassNamespace(recoveredClass, classStruct);
|
||||||
|
//TODO:
|
||||||
// addNonThisDestructorsToClassNamespace(recoveredClass);
|
// addNonThisDestructorsToClassNamespace(recoveredClass);
|
||||||
// addVbaseDestructorsToClassNamespace(recoveredClass);
|
// addVbaseDestructorsToClassNamespace(recoveredClass);
|
||||||
// addVbtableToClassNamespace(recoveredClass);
|
// addVbtableToClassNamespace(recoveredClass);
|
||||||
//
|
//TODO:
|
||||||
// // add secondary label on functions with inlined constructors or destructors
|
// // add secondary label on functions with inlined constructors or destructors
|
||||||
// createInlinedConstructorComments(recoveredClass);
|
// createInlinedConstructorComments(recoveredClass);
|
||||||
// createInlinedDestructorComments(recoveredClass);
|
// createInlinedDestructorComments(recoveredClass);
|
||||||
|
@ -2921,7 +2811,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
// add label on constructor destructor functions that could not be determined which were which
|
// add label on constructor destructor functions that could not be determined which were which
|
||||||
createIndeterminateLabels(recoveredClass, classStruct);
|
createIndeterminateLabels(recoveredClass, classStruct);
|
||||||
}
|
|
||||||
|
|
||||||
// This is done after the class structure is created and added to the dtmanager
|
// This is done after the class structure is created and added to the dtmanager
|
||||||
// because if done before the class structures are created
|
// because if done before the class structures are created
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
||||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||||
boolean nameVFunctions, boolean isPDBLoaded, boolean replaceClassStructures,
|
boolean nameVFunctions, boolean isPDBLoaded, boolean replaceClassStructures,
|
||||||
TaskMonitor monitor) throws CancelledException {
|
TaskMonitor monitor) throws Exception {
|
||||||
|
|
||||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions,
|
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions,
|
||||||
isPDBLoaded, replaceClassStructures, monitor);
|
isPDBLoaded, replaceClassStructures, monitor);
|
||||||
|
@ -98,41 +98,27 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fixUpProgram() {
|
public void fixUpProgram() throws CancelledException, Exception {
|
||||||
|
|
||||||
if (ghidraVersion.compareTo("10.0") < 0) {
|
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
|
// if there are undefined areas that reference vftables attempt to create functions
|
||||||
// containing them
|
// containing them
|
||||||
List<Symbol> vftableSymbols;
|
List<Symbol> vftableSymbols = getListOfVftableSymbols();
|
||||||
try {
|
|
||||||
vftableSymbols = getListOfVftableSymbols();
|
|
||||||
createMissingFunctions(vftableSymbols);
|
createMissingFunctions(vftableSymbols);
|
||||||
}
|
|
||||||
catch (CancelledException e1) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RecoveredClass> createRecoveredClasses() {
|
public List<RecoveredClass> createRecoveredClasses() throws Exception {
|
||||||
|
|
||||||
List<Symbol> vftableSymbols;
|
List<Symbol> vftableSymbols;
|
||||||
try {
|
|
||||||
vftableSymbols = getListOfVftableSymbols();
|
vftableSymbols = getListOfVftableSymbols();
|
||||||
|
|
||||||
List<RecoveredClass> recoveredClasses =
|
List<RecoveredClass> recoveredClasses =
|
||||||
|
@ -203,15 +189,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
return recoveredClasses;
|
return recoveredClasses;
|
||||||
}
|
|
||||||
catch (CancelledException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +328,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//println("Cannot create RTTI_CompleteObjectLocator at " + symbol.getAddress());
|
Msg.debug(this, "Cannot create RTTI_CompleteObjectLocator at " + symbol.getAddress());
|
||||||
|
|
||||||
}
|
}
|
||||||
return completeObjectLocatorSymbols;
|
return completeObjectLocatorSymbols;
|
||||||
|
@ -417,7 +394,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
continue;
|
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;
|
return baseClassDescriptorSymbols;
|
||||||
|
@ -661,8 +638,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// println("Failed to create a baseClassDescArray structure at " +
|
Msg.debug(this, "Failed to create a baseClassDescArray structure at " +
|
||||||
// baseClassArrayAddress.toString());
|
baseClassArrayAddress.toString());
|
||||||
}
|
}
|
||||||
return baseClassArrayAddresses;
|
return baseClassArrayAddresses;
|
||||||
}
|
}
|
||||||
|
@ -736,13 +713,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace();
|
Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace();
|
||||||
if (classNamespace.equals(globalNamespace)) {
|
if (classNamespace.equals(globalNamespace)) {
|
||||||
//println("no class namespace for " + completeObjectLocatorAddress.toString());
|
Msg.debug(this,
|
||||||
|
"No class namespace for " + completeObjectLocatorAddress.toString());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference[] referencesTo = extraUtils.getReferencesTo(completeObjectLocatorAddress);
|
Reference[] referencesTo = extraUtils.getReferencesTo(completeObjectLocatorAddress);
|
||||||
if (referencesTo.length == 0) {
|
if (referencesTo.length == 0) {
|
||||||
//println("no refs to " + completeObjectLocatorAddress.toString());
|
Msg.debug(this, "No refs to " + completeObjectLocatorAddress.toString());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -995,7 +973,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
* @throws Exception when cancelled
|
* @throws Exception when cancelled
|
||||||
*/
|
*/
|
||||||
private void determineVftableOffsetsfromRTTI(List<RecoveredClass> recoveredClasses)
|
private void determineVftableOffsetsfromRTTI(List<RecoveredClass> recoveredClasses)
|
||||||
throws Exception {
|
throws AddressOutOfBoundsException, Exception {
|
||||||
|
|
||||||
PointerDataType pointerDataType = new PointerDataType();
|
PointerDataType pointerDataType = new PointerDataType();
|
||||||
|
|
||||||
|
@ -1020,23 +998,17 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
Address colAddress = extraUtils.getReferencedAddress(ptrToColAddress, false);
|
Address colAddress = extraUtils.getReferencedAddress(ptrToColAddress, false);
|
||||||
|
|
||||||
if (colAddress == null) {
|
if (colAddress == null) {
|
||||||
// println(recoveredClass.getName() + " couldn't get referenced col from " +
|
Msg.debug(this, recoveredClass.getName() +
|
||||||
// ptrToColAddress.toString());
|
" couldn't get referenced col from " + ptrToColAddress.toString());
|
||||||
continue;
|
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);
|
recoveredClass.addClassOffsetToVftableMapping(offset, vftableAddress);
|
||||||
}
|
}
|
||||||
catch (AddressOutOfBoundsException e) {
|
|
||||||
// println(recoveredClass.getName() + "error getting offset at address " +
|
|
||||||
// colAddress.toString() + " + 4");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,9 +1035,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
int inheritanceFlag = getClassInheritanceFlag(recoveredClass.getClassNamespace());
|
int inheritanceFlag = getClassInheritanceFlag(recoveredClass.getClassNamespace());
|
||||||
if (inheritanceFlag == NONE) {
|
if (inheritanceFlag == NONE) {
|
||||||
// println(
|
Msg.debug(this,
|
||||||
// "Could not get inheritance attribute from class hierarchy structure for " +
|
"Could not get inheritance attribute from class hierarchy structure for " +
|
||||||
// "class " + recoveredClass.getName());
|
"class " + recoveredClass.getName());
|
||||||
recoveredClassesIterator.remove();
|
recoveredClassesIterator.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1250,21 +1222,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
RTTI_CLASS_HIERARCHY_DESCRIPTOR_LABEL, classNamespace, false);
|
RTTI_CLASS_HIERARCHY_DESCRIPTOR_LABEL, classNamespace, false);
|
||||||
|
|
||||||
if (symbols.size() >= 1) {
|
if (symbols.size() >= 1) {
|
||||||
|
|
||||||
try {
|
|
||||||
return (extraUtils.getInt(symbols.get(0).getAddress().add(4)));
|
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 NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1399,7 +1359,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
// this should never happen
|
// this should never happen
|
||||||
if (baseClassArray.size() != 1) {
|
if (baseClassArray.size() != 1) {
|
||||||
throw new Exception(
|
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();
|
Address baseClassArrayAddress = baseClassArray.get(0).getAddress();
|
||||||
|
@ -1407,7 +1367,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
if (!baseClassArrayData.isArray()) {
|
if (!baseClassArrayData.isArray()) {
|
||||||
throw new Exception(
|
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
|
* @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
|
* or if there is no mapping in the offset map for that parent
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
|
* @throws AddressOutOfBoundsException
|
||||||
|
* @throws MemoryAccessException
|
||||||
*/
|
*/
|
||||||
public Integer getSingleVirtualParentOffset(RecoveredClass recoveredClass)
|
public Integer getSingleVirtualParentOffset(RecoveredClass recoveredClass)
|
||||||
throws CancelledException {
|
throws CancelledException, MemoryAccessException, AddressOutOfBoundsException {
|
||||||
|
|
||||||
List<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass);
|
List<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass);
|
||||||
if (virtualParentClasses.size() != 1) {
|
if (virtualParentClasses.size() != 1) {
|
||||||
|
@ -2706,7 +2669,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<RecoveredClass, Integer> getBaseClassOffsetMap(RecoveredClass recoveredClass)
|
private Map<RecoveredClass, Integer> getBaseClassOffsetMap(RecoveredClass recoveredClass)
|
||||||
throws CancelledException {
|
throws CancelledException, MemoryAccessException, AddressOutOfBoundsException {
|
||||||
|
|
||||||
Map<RecoveredClass, Integer> parentOffsetMap = new HashMap<RecoveredClass, Integer>();
|
Map<RecoveredClass, Integer> parentOffsetMap = new HashMap<RecoveredClass, Integer>();
|
||||||
|
|
||||||
|
@ -2727,11 +2690,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
RecoveredClass baseClass = getClassFromBaseClassDescriptor(baseClassDescriptorAddress);
|
||||||
RecoveredClass baseClass =
|
|
||||||
getClassFromBaseClassDescriptor(baseClassDescriptorAddress);
|
|
||||||
if (baseClass == null) {
|
if (baseClass == null) {
|
||||||
// TODO: msg and return null
|
// TODO: return null?
|
||||||
|
Msg.debug(this, "Could not get base class from baseClassDescriptor " +
|
||||||
|
baseClassDescriptorAddress.toString());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2745,7 +2708,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
int pdisp = api.getInt(baseClassDescriptorAddress.add(12));
|
int pdisp = api.getInt(baseClassDescriptorAddress.add(12));
|
||||||
int vdisp = api.getInt(baseClassDescriptorAddress.add(16));
|
int vdisp = api.getInt(baseClassDescriptorAddress.add(16));
|
||||||
if (pdisp == -1) {
|
if (pdisp == -1) {
|
||||||
|
|
||||||
baseClassOffset = mdisp;
|
baseClassOffset = mdisp;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2758,21 +2720,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
recoveredClass.getName());
|
recoveredClass.getName());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
baseClassOffset = api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
|
||||||
baseClassOffset =
|
|
||||||
api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parentOffsetMap.put(baseClass, baseClassOffset);
|
parentOffsetMap.put(baseClass, baseClassOffset);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
|
||||||
Msg.error(this,
|
|
||||||
"Cannot create base class offset map for class " + recoveredClass.getName());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return parentOffsetMap;
|
return parentOffsetMap;
|
||||||
}
|
}
|
||||||
|
@ -2885,9 +2835,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
* order to distinguish which base class the vftable is for.
|
* order to distinguish which base class the vftable is for.
|
||||||
* @param recoveredClasses the list of RecoveredClass objects
|
* @param recoveredClasses the list of RecoveredClass objects
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
|
* @throws InvalidInputException if bad chars trying to label
|
||||||
|
* @throws DuplicateNameException if duplicate name
|
||||||
*/
|
*/
|
||||||
private void updateMultiVftableLabels(List<RecoveredClass> recoveredClasses)
|
private void updateMultiVftableLabels(List<RecoveredClass> recoveredClasses)
|
||||||
throws CancelledException {
|
throws CancelledException, DuplicateNameException, InvalidInputException {
|
||||||
|
|
||||||
if (recoveredClasses.isEmpty()) {
|
if (recoveredClasses.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -2914,20 +2866,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
if (!shortenedTemplateName.isBlank()) {
|
if (!shortenedTemplateName.isBlank()) {
|
||||||
baseClassName = shortenedTemplateName;
|
baseClassName = shortenedTemplateName;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
primarySymbol.setName("vftable_for_" + baseClassName,
|
primarySymbol.setName("vftable_for_" + baseClassName,
|
||||||
primarySymbol.getSource());
|
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,8 @@ public class RecoveredClassUtils {
|
||||||
|
|
||||||
public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool,
|
public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool,
|
||||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||||
boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) {
|
boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
this.monitor = monitor;
|
this.monitor = monitor;
|
||||||
this.program = program;
|
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 recoveredClass the given class
|
||||||
* @param function the given function
|
* @param function the given function
|
||||||
* @return the reference to the class vftable in the given function or null if there isn't one
|
* @return the reference to the class vftable in the given function or null if there isn't one
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
public Address getClassVftableReference(RecoveredClass recoveredClass,
|
public Address getFirstClassVftableReference(RecoveredClass recoveredClass,
|
||||||
Function function) throws CancelledException {
|
Function function) throws CancelledException {
|
||||||
|
|
||||||
List<Address> vftableReferenceList = functionToVftableRefsMap.get(function);
|
List<Address> vftableReferenceList = functionToVftableRefsMap.get(function);
|
||||||
|
@ -566,6 +567,8 @@ public class RecoveredClassUtils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collections.sort(vftableReferenceList);
|
||||||
|
|
||||||
Iterator<Address> vftableRefs = vftableReferenceList.iterator();
|
Iterator<Address> vftableRefs = vftableReferenceList.iterator();
|
||||||
while (vftableRefs.hasNext()) {
|
while (vftableRefs.hasNext()) {
|
||||||
monitor.checkCanceled();
|
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
|
* Method to get a sorted list of both vftable and call refs to ancestor classes of the given
|
||||||
* class in the given function
|
* class in the given function
|
||||||
|
@ -3389,7 +3359,7 @@ public class RecoveredClassUtils {
|
||||||
replaceClassStructure(destructorFunction, className, classStruct);
|
replaceClassStructure(destructorFunction, className, classStruct);
|
||||||
}
|
}
|
||||||
|
|
||||||
destructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
|
destructorFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3445,7 +3415,7 @@ public class RecoveredClassUtils {
|
||||||
classStruct);
|
classStruct);
|
||||||
}
|
}
|
||||||
|
|
||||||
vbaseDestructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
|
vbaseDestructorFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3635,7 +3605,9 @@ public class RecoveredClassUtils {
|
||||||
return true;
|
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
|
// test to see if the data type is an empty structure with "PlaceHolder Class Structure" in
|
||||||
// the description
|
// the description
|
||||||
|
@ -5146,25 +5118,12 @@ public class RecoveredClassUtils {
|
||||||
while (inlinedDestructorIterator.hasNext()) {
|
while (inlinedDestructorIterator.hasNext()) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
Function destructorFunction = inlinedDestructorIterator.next();
|
Function destructorFunction = inlinedDestructorIterator.next();
|
||||||
Address classVftableRef =
|
Address classVftableRef = getFirstClassVftableReference(recoveredClass, destructorFunction);
|
||||||
getClassVftableRefInFunction(destructorFunction, recoveredClass);
|
|
||||||
|
|
||||||
//TODO: use this one instead if testing pans out
|
|
||||||
Address otherWayRef = getClassVftableReference(recoveredClass, destructorFunction);
|
|
||||||
|
|
||||||
if (classVftableRef == null) {
|
if (classVftableRef == null) {
|
||||||
continue;
|
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;
|
String markupString = classNamespace.getName(true) + "::~" + className;
|
||||||
api.setPreComment(classVftableRef, "inlined destructor: " + markupString);
|
api.setPreComment(classVftableRef, "inlined destructor: " + markupString);
|
||||||
|
|
||||||
|
@ -5189,24 +5148,11 @@ public class RecoveredClassUtils {
|
||||||
Function functionContainingInline = functionsContainingInlineIterator.next();
|
Function functionContainingInline = functionsContainingInlineIterator.next();
|
||||||
|
|
||||||
Address classVftableRef =
|
Address classVftableRef =
|
||||||
getClassVftableRefInFunction(functionContainingInline, recoveredClass);
|
getFirstClassVftableReference(recoveredClass, functionContainingInline);
|
||||||
//TODO: use this one if testing more progs gives same results
|
|
||||||
Address otherWayRef =
|
|
||||||
getClassVftableReference(recoveredClass, functionContainingInline);
|
|
||||||
|
|
||||||
if (classVftableRef == null) {
|
if (classVftableRef == null) {
|
||||||
continue;
|
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 " +
|
String markupString = "inlined constructor or destructor (approx location) for " +
|
||||||
classNamespace.getName(true);
|
classNamespace.getName(true);
|
||||||
|
@ -5419,22 +5365,11 @@ public class RecoveredClassUtils {
|
||||||
// Type 4 inlined - inlined class c/d called from other than first function
|
// 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
|
// either just vftable ref before operator delete or vftableref followed by parent call
|
||||||
// before operator delete
|
// 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) {
|
if (vftableReference == null) {
|
||||||
return;
|
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);
|
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
|
* Method to determine if the given data type is the virtual parent class structure for the given class
|
||||||
* @param recoveredClass the given class
|
* @param recoveredClass the given class
|
||||||
|
@ -6552,7 +6450,7 @@ public class RecoveredClassUtils {
|
||||||
if (!atexitCalledFunctions.contains(calledFunction)) {
|
if (!atexitCalledFunctions.contains(calledFunction)) {
|
||||||
atexitCalledFunctions.add(calledFunction);
|
atexitCalledFunctions.add(calledFunction);
|
||||||
}
|
}
|
||||||
calledFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
|
calledFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!atexitCalledFunctions.contains(calledFunction)) {
|
if (!atexitCalledFunctions.contains(calledFunction)) {
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
# 1010 0100 ssss tttt # user_four rs rt user_four rs rt
|
# 1010 0100 ssss tttt # user_four rs rt user_four rs rt
|
||||||
# 1010 0101 nnnn nnnn # user_five n user_five n
|
# 1010 0101 nnnn nnnn # user_five n user_five n
|
||||||
# 1010 0110 ssss 0000 # user_six rs user_six rs
|
# 1010 0110 ssss 0000 # user_six rs user_six rs
|
||||||
|
# 1010 1000 0000 0000 # unimpl
|
||||||
#
|
#
|
||||||
#### RESERVED
|
#### RESERVED
|
||||||
# 1101 1001 xxxx xxxx # RESERVED BANK
|
# 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_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];}
|
: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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue