mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-1499 Recover classes script various improvements. Updated checks for whether program has DWARF and whether DWARF has been applied so it works for old and new cases.
Improved error handling. Updated deprecated graph methods which were no longer using defined colors. Various code cleanup.
This commit is contained in:
parent
318f13d9a2
commit
80538d8c49
7 changed files with 428 additions and 631 deletions
|
@ -24,11 +24,18 @@ import ghidra.app.services.GraphDisplayBroker;
|
|||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.service.graph.*;
|
||||
import ghidra.util.WebColors;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class GraphClassesScript extends GhidraScript {
|
||||
|
||||
private static final String NO_INHERITANCE = "No Inheritance";
|
||||
private static final String SINGLE_INHERITANCE = "Single Inheritance";
|
||||
private static final String MULTIPLE_INHERITANCE = "Multiple Inheritance";
|
||||
private static final String VIRTUAL_INHERITANCE = "Virtual Inheritance";
|
||||
private static final String NON_VIRTUAL_INHERITANCE = "Non-virtual Inheritance";
|
||||
|
||||
List<Structure> classStructures = new ArrayList<Structure>();
|
||||
|
||||
@Override
|
||||
|
@ -107,7 +114,15 @@ public class GraphClassesScript extends GhidraScript {
|
|||
*/
|
||||
private AttributedGraph createGraph() throws Exception {
|
||||
|
||||
AttributedGraph g = new AttributedGraph("Test Graph", new EmptyGraphType());
|
||||
GraphType graphType =
|
||||
new GraphTypeBuilder("Class Hierarchy Graph").vertexType(NO_INHERITANCE)
|
||||
.vertexType(SINGLE_INHERITANCE)
|
||||
.vertexType(MULTIPLE_INHERITANCE)
|
||||
.edgeType(NON_VIRTUAL_INHERITANCE)
|
||||
.edgeType(VIRTUAL_INHERITANCE)
|
||||
.build();
|
||||
|
||||
AttributedGraph g = new AttributedGraph("Recovered Classes Graph", graphType);
|
||||
|
||||
for (Structure classStructure : classStructures) {
|
||||
|
||||
|
@ -176,24 +191,27 @@ public class GraphClassesScript extends GhidraScript {
|
|||
|
||||
AttributedEdge edge = g.addEdge(parentVertex, classVertex);
|
||||
if (isVirtualParent) {
|
||||
edge.setAttribute("Color", "Orange");
|
||||
edge.setEdgeType(VIRTUAL_INHERITANCE);
|
||||
}
|
||||
else {
|
||||
// else leave it default lime green
|
||||
edge.setEdgeType(NON_VIRTUAL_INHERITANCE);
|
||||
}
|
||||
// else leave it default lime green
|
||||
|
||||
description = removeClassSubstring(description, parentName);
|
||||
}
|
||||
|
||||
// no parent = blue vertex
|
||||
if (numParents == 0) {
|
||||
classVertex.setAttribute("Color", "Blue");
|
||||
classVertex.setVertexType(NO_INHERITANCE);
|
||||
}
|
||||
// single parent = green vertex
|
||||
else if (numParents == 1) {
|
||||
classVertex.setAttribute("Color", "Green");
|
||||
classVertex.setVertexType(SINGLE_INHERITANCE);
|
||||
}
|
||||
// multiple parents = red vertex
|
||||
else {
|
||||
classVertex.setAttribute("Color", "Red");
|
||||
classVertex.setVertexType(MULTIPLE_INHERITANCE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +313,20 @@ public class GraphClassesScript extends GhidraScript {
|
|||
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
|
||||
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
|
||||
display = service.getGraphDisplay(false, TaskMonitor.DUMMY);
|
||||
display.setGraph(graph, "test graph", false, TaskMonitor.DUMMY);
|
||||
|
||||
GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType())
|
||||
.vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE)
|
||||
.vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN)
|
||||
.vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED)
|
||||
.edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN)
|
||||
.edge(VIRTUAL_INHERITANCE, WebColors.ORANGE)
|
||||
.defaultVertexColor(WebColors.PURPLE)
|
||||
.defaultEdgeColor(WebColors.PURPLE)
|
||||
.defaultLayoutAlgorithm("Compact Hierarchical")
|
||||
.build();
|
||||
|
||||
display.setGraph(graph, graphOptions,
|
||||
"Recovered Classes Graph", false, TaskMonitor.DUMMY);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
// this script and default vfunctions named by this script are likely to change in the future
|
||||
// once an official design for Object Oriented representation is determined.
|
||||
// NOTE: Windows class recovery is more complete and tested than gcc class recovery, which is still
|
||||
// in early stages of development. Gcc class data types are only recovered for classes without multiple or
|
||||
// in early stages of development. Gcc class data types are only recovered for classes without
|
||||
// virtual inheritance but if the program contains DWARF, there will be some amount of data recovered
|
||||
// by the DWARF analyzer.
|
||||
// NOTE: For likely the best results, run this script on freshly analyzed programs. No testing has been
|
||||
|
@ -65,6 +65,8 @@ import ghidra.app.services.Analyzer;
|
|||
import ghidra.app.services.GraphDisplayBroker;
|
||||
import ghidra.app.util.bin.format.dwarf4.next.DWARFFunctionImporter;
|
||||
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
|
||||
import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProvider;
|
||||
import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProviderFactory;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserConstants;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.Options;
|
||||
|
@ -74,6 +76,7 @@ import ghidra.program.model.data.*;
|
|||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.service.graph.*;
|
||||
import ghidra.util.WebColors;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.GraphException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -117,6 +120,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
// edge between child and parent is orange if child inherits the parent virtually
|
||||
// edge between child and parent is lime green if child inherits the parent non-virtually
|
||||
private static final boolean GRAPH_CLASS_HIERARCHIES = false;
|
||||
private static final String NO_INHERITANCE = "No Inheritance";
|
||||
private static final String SINGLE_INHERITANCE = "Single Inheritance";
|
||||
private static final String MULTIPLE_INHERITANCE = "Multiple Inheritance";
|
||||
private static final String VIRTUAL_INHERITANCE = "Virtual Inheritance";
|
||||
private static final String NON_VIRTUAL_INHERITANCE = "Non-virtual Inheritance";
|
||||
|
||||
// show shortened class template names in class structure field names
|
||||
private static final boolean USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS = true;
|
||||
|
@ -134,23 +142,29 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
|
||||
private static final String INDETERMINATE_BOOKMARK = "INDETERMINATE";
|
||||
|
||||
// DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES
|
||||
// If replacedClassStructuresOption is set to the following, no replaced structures will be removed
|
||||
// from the data type manager
|
||||
private static final int DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES = 0;
|
||||
|
||||
// REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES
|
||||
// If replacedClassStructuresOption is set to the following, only empty existing class structures
|
||||
// that were replaced by this script will be removed from the data type manager
|
||||
private static final int REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES = 1;
|
||||
|
||||
// REMOVE_ALL_REPLACED_CLASS_STRUCTURES
|
||||
// If replacedClassStructuresOption is set to the following, all existing class structures that
|
||||
// were replaced by this script, including non-emtpy ones, will be removed from the data type
|
||||
// manager
|
||||
private static final int REMOVE_ALL_REPLACED_CLASS_STRUCTURES = 2;
|
||||
private static enum removeOption {
|
||||
DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES,
|
||||
REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES,
|
||||
REMOVE_ALL_REPLACED_CLASS_STRUCTURES
|
||||
}
|
||||
|
||||
// NEW OPTION -
|
||||
// This option allows the user to decide whether and how to remove replaced existing class structures
|
||||
// using one of the above three flags
|
||||
int replacedClassStructuresOption = DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES;
|
||||
removeOption replacedClassStructuresOption =
|
||||
removeOption.DO_NOT_REMOVE_REPLACED_CLASS_STRUCTURES;
|
||||
|
||||
boolean programHasRTTIApplied = false;
|
||||
boolean hasDebugSymbols;
|
||||
|
@ -178,16 +192,14 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (isWindows()) {
|
||||
|
||||
hasDebugSymbols = isPDBLoadedInProgram();
|
||||
nameVfunctions = !hasDebugSymbols;
|
||||
recoverClassesFromRTTI = new RTTIWindowsClassRecoverer(currentProgram,
|
||||
currentLocation, state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
|
||||
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
|
||||
REPLACE_EXISTING_CLASS_STRUCTURES,
|
||||
monitor);
|
||||
recoverClassesFromRTTI =
|
||||
new RTTIWindowsClassRecoverer(currentProgram, currentLocation, state.getTool(),
|
||||
this, BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, REPLACE_EXISTING_CLASS_STRUCTURES, monitor);
|
||||
}
|
||||
else if (isGcc()) {
|
||||
|
||||
|
@ -204,11 +216,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
return;
|
||||
}
|
||||
nameVfunctions = !hasDebugSymbols;
|
||||
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
|
||||
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
|
||||
USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS, nameVfunctions, hasDebugSymbols,
|
||||
REPLACE_EXISTING_CLASS_STRUCTURES,
|
||||
monitor);
|
||||
recoverClassesFromRTTI =
|
||||
new RTTIGccClassRecoverer(currentProgram, currentLocation, state.getTool(), this,
|
||||
BOOKMARK_FOUND_FUNCTIONS, USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS,
|
||||
nameVfunctions, hasDebugSymbols, REPLACE_EXISTING_CLASS_STRUCTURES, monitor);
|
||||
}
|
||||
else {
|
||||
println("This script will not work on this program type");
|
||||
|
@ -281,7 +292,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
getNumberOfConstructorsOrDestructors(recoveredClasses) +
|
||||
" class member functions to assign.");
|
||||
|
||||
|
||||
if (!hasDebugSymbols) {
|
||||
|
||||
if (BOOKMARK_FOUND_FUNCTIONS) {
|
||||
|
@ -301,23 +311,32 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
showGraph(graph);
|
||||
}
|
||||
|
||||
if (replacedClassStructuresOption == REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES) {
|
||||
if (replacedClassStructuresOption == removeOption.REMOVE_EMPTY_REPLACED_CLASS_STRUCTURES) {
|
||||
println("Removing all empty replaced class structures from the data type manager");
|
||||
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, false);
|
||||
}
|
||||
|
||||
if (replacedClassStructuresOption == REMOVE_ALL_REPLACED_CLASS_STRUCTURES) {
|
||||
if (replacedClassStructuresOption == removeOption.REMOVE_ALL_REPLACED_CLASS_STRUCTURES) {
|
||||
println(
|
||||
"Removing all replaced class structures from the data type manager, including non-empty ones");
|
||||
recoverClassesFromRTTI.removeReplacedClassStructures(recoveredClasses, true);
|
||||
}
|
||||
|
||||
|
||||
decompilerUtils.disposeDecompilerInterface();
|
||||
|
||||
}
|
||||
|
||||
private boolean hasDwarf() {
|
||||
return DWARFProgram.isDWARF(currentProgram);
|
||||
if (DWARFProgram.isDWARF(currentProgram)) {
|
||||
DWARFSectionProvider dsp =
|
||||
DWARFSectionProviderFactory.createSectionProviderFor(currentProgram, monitor);
|
||||
if (dsp == null) {
|
||||
return false;
|
||||
}
|
||||
dsp.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,8 +350,10 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
|
||||
private boolean isDwarfLoadedInProgram() {
|
||||
|
||||
return DWARFFunctionImporter.hasDWARFProgModule(currentProgram,
|
||||
DWARFProgram.DWARF_ROOT_NAME);
|
||||
Options options = currentProgram.getOptions(Program.PROGRAM_INFO);
|
||||
|
||||
return (DWARFFunctionImporter.hasDWARFProgModule(currentProgram,
|
||||
DWARFProgram.DWARF_ROOT_NAME) || options.getBoolean("DWARF Loaded", false));
|
||||
}
|
||||
|
||||
public String validate() {
|
||||
|
@ -392,7 +413,15 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
private AttributedGraph createGraph(List<RecoveredClass> recoveredClasses)
|
||||
throws CancelledException {
|
||||
|
||||
AttributedGraph g = new AttributedGraph("Test Graph", new EmptyGraphType());
|
||||
GraphType graphType =
|
||||
new GraphTypeBuilder("Class Hierarchy Graph").vertexType(NO_INHERITANCE)
|
||||
.vertexType(SINGLE_INHERITANCE)
|
||||
.vertexType(MULTIPLE_INHERITANCE)
|
||||
.edgeType(NON_VIRTUAL_INHERITANCE)
|
||||
.edgeType(VIRTUAL_INHERITANCE)
|
||||
.build();
|
||||
|
||||
AttributedGraph g = new AttributedGraph("Recovered Classes Graph", graphType);
|
||||
|
||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
||||
while (recoveredClassIterator.hasNext()) {
|
||||
|
@ -408,7 +437,7 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
|
||||
// no parent = blue vertex
|
||||
if (classHierarchyMap.isEmpty()) {
|
||||
classVertex.setAttribute("Color", "Blue");
|
||||
classVertex.setVertexType(NO_INHERITANCE);
|
||||
classVertex.setDescription(recoveredClass.getClassPath().getPath());
|
||||
continue;
|
||||
}
|
||||
|
@ -417,11 +446,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
|
||||
// single parent = green vertex
|
||||
if (parents.size() == 1) {
|
||||
classVertex.setAttribute("Color", "Green");
|
||||
classVertex.setVertexType(SINGLE_INHERITANCE);
|
||||
}
|
||||
// multiple parents = red vertex
|
||||
else {
|
||||
classVertex.setAttribute("Color", "Red");
|
||||
classVertex.setVertexType(MULTIPLE_INHERITANCE);
|
||||
}
|
||||
|
||||
classVertex.setDescription(recoveredClass.getClassPath().getPath());
|
||||
|
@ -448,9 +477,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
|
||||
// edge between child and parent is orange if child inherits the parent virtually
|
||||
if (isVirtualParent) {
|
||||
edge.setAttribute("Color", "Orange");
|
||||
edge.setEdgeType(VIRTUAL_INHERITANCE);
|
||||
}
|
||||
// else edge between child and parent is lime green if child inherits the parent non-virtually
|
||||
else {
|
||||
edge.setEdgeType(NON_VIRTUAL_INHERITANCE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -471,7 +503,20 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
|||
GraphDisplayBroker broker = tool.getService(GraphDisplayBroker.class);
|
||||
GraphDisplayProvider service = broker.getGraphDisplayProvider("Default Graph Display");
|
||||
display = service.getGraphDisplay(false, TaskMonitor.DUMMY);
|
||||
display.setGraph(graph, "test graph", false, TaskMonitor.DUMMY);
|
||||
|
||||
GraphDisplayOptions graphOptions = new GraphDisplayOptionsBuilder(graph.getGraphType())
|
||||
.vertex(NO_INHERITANCE, VertexShape.RECTANGLE, WebColors.BLUE)
|
||||
.vertex(SINGLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.GREEN)
|
||||
.vertex(MULTIPLE_INHERITANCE, VertexShape.RECTANGLE, WebColors.RED)
|
||||
.edge(NON_VIRTUAL_INHERITANCE, WebColors.LIME_GREEN)
|
||||
.edge(VIRTUAL_INHERITANCE, WebColors.ORANGE)
|
||||
.defaultVertexColor(WebColors.PURPLE)
|
||||
.defaultEdgeColor(WebColors.PURPLE)
|
||||
.defaultLayoutAlgorithm("Compact Hierarchical")
|
||||
.build();
|
||||
|
||||
display.setGraph(graph, graphOptions,
|
||||
"Recovered Classes Graph", false, TaskMonitor.DUMMY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1045,8 +1045,10 @@ public class ExtraScriptUtils extends FlatProgramAPI {
|
|||
* @param parent parent CategoryPath
|
||||
* @param categoryName name of the new category in the parent path
|
||||
* @return CategoryPath for new categoryName
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public CategoryPath createDataTypeCategoryPath(CategoryPath parent, String categoryName) {
|
||||
public CategoryPath createDataTypeCategoryPath(CategoryPath parent, String categoryName)
|
||||
throws CancelledException {
|
||||
|
||||
CategoryPath dataTypePath;
|
||||
|
||||
|
@ -1070,12 +1072,8 @@ public class ExtraScriptUtils extends FlatProgramAPI {
|
|||
int index = 0;
|
||||
String newCategoryName = new String();
|
||||
while (index < categoryName.length()) {
|
||||
try {
|
||||
monitor.checkCanceled();
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
monitor.checkCanceled();
|
||||
|
||||
if (categoryName.substring(index).startsWith("::") && !insideBrackets) {
|
||||
newCategoryName = newCategoryName.concat("/");
|
||||
|
|
|
@ -44,7 +44,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
|||
RTTIClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||
boolean nameVfunctions, boolean hasDebugSymbols, boolean replaceClassStructures,
|
||||
TaskMonitor monitor) {
|
||||
TaskMonitor monitor) throws Exception {
|
||||
|
||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||
replaceClassStructures,
|
||||
|
@ -76,7 +76,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
|||
return dataTypeManager;
|
||||
}
|
||||
|
||||
public boolean containsRTTI() throws CancelledException {
|
||||
public boolean containsRTTI() throws CancelledException, InvalidInputException {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -104,12 +104,12 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
|||
|
||||
|
||||
|
||||
public void fixUpProgram() {
|
||||
public void fixUpProgram() throws CancelledException, Exception {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
public List<RecoveredClass> createRecoveredClasses() {
|
||||
public List<RecoveredClass> createRecoveredClasses() throws Exception {
|
||||
|
||||
return new ArrayList<RecoveredClass>();
|
||||
}
|
||||
|
@ -121,10 +121,10 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
|||
* Method to promote the namespace is a class namespace.
|
||||
* @param namespace the namespace for the vftable
|
||||
* @return true if namespace is (now) a class namespace or false if it could not be promoted.
|
||||
* @throws InvalidInputException if namespace was contained in function and could not be promoted
|
||||
*/
|
||||
public Namespace promoteToClassNamespace(Namespace namespace) {
|
||||
public Namespace promoteToClassNamespace(Namespace namespace) throws InvalidInputException {
|
||||
|
||||
try {
|
||||
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
||||
|
||||
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
||||
|
@ -134,13 +134,6 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
|||
Msg.debug(this,
|
||||
"Could not promote " + namespace.getName() + " to a class namespace");
|
||||
return null;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
|
||||
Msg.debug(this, "Could not promote " + namespace.getName() +
|
||||
" to a class namespace because " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -221,7 +214,7 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
|||
Structure existingClassStructure =
|
||||
(Structure) dataTypeManager.getDataType(dataTypePath, dataTypeName);
|
||||
|
||||
if (!existingClassStructure.isNotYetDefined()) {
|
||||
if (existingClassStructure != null && !existingClassStructure.isNotYetDefined()) {
|
||||
recoveredClass.addExistingClassStructure(existingClassStructure);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -74,18 +74,16 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
public RTTIGccClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||
boolean nameVfunctions, boolean isDwarfLoaded, boolean replaceExistingClassStructures,
|
||||
TaskMonitor monitor) {
|
||||
TaskMonitor monitor) throws Exception {
|
||||
|
||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||
replaceExistingClassStructures,
|
||||
isDwarfLoaded,
|
||||
monitor);
|
||||
replaceExistingClassStructures, isDwarfLoaded, monitor);
|
||||
this.isDwarfLoaded = isDwarfLoaded;
|
||||
this.replaceClassStructs = replaceExistingClassStructures;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsRTTI() throws CancelledException {
|
||||
public boolean containsRTTI() throws CancelledException, InvalidInputException {
|
||||
|
||||
if (!hasSpecialVtable()) {
|
||||
return false;
|
||||
|
@ -103,44 +101,33 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<RecoveredClass> createRecoveredClasses() {
|
||||
public List<RecoveredClass> createRecoveredClasses() throws CancelledException, Exception {
|
||||
|
||||
try {
|
||||
|
||||
processGccRTTI();
|
||||
if (recoveredClasses == null) {
|
||||
Msg.debug(this, "Could not recover gcc rtti classes");
|
||||
return null;
|
||||
}
|
||||
|
||||
createCalledFunctionMap(recoveredClasses);
|
||||
|
||||
createClassHierarchyListAndMapForGcc();
|
||||
|
||||
if (isDwarfLoaded) {
|
||||
retrieveExistingClassStructures(recoveredClasses);
|
||||
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
|
||||
}
|
||||
else {
|
||||
processConstructorAndDestructors();
|
||||
}
|
||||
|
||||
createVftableOrderMap(recoveredClasses);
|
||||
|
||||
figureOutClassDataMembers(recoveredClasses);
|
||||
|
||||
createAndApplyClassStructures();
|
||||
|
||||
return recoveredClasses;
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
e.printStackTrace();
|
||||
processGccRTTI();
|
||||
if (recoveredClasses == null) {
|
||||
Msg.debug(this, "Could not recover gcc rtti classes");
|
||||
return null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
|
||||
createCalledFunctionMap(recoveredClasses);
|
||||
|
||||
createClassHierarchyListAndMapForGcc();
|
||||
|
||||
if (isDwarfLoaded) {
|
||||
retrieveExistingClassStructures(recoveredClasses);
|
||||
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
|
||||
}
|
||||
else {
|
||||
processConstructorAndDestructors();
|
||||
}
|
||||
|
||||
createVftableOrderMap(recoveredClasses);
|
||||
|
||||
figureOutClassDataMembers(recoveredClasses);
|
||||
|
||||
createAndApplyClassStructures();
|
||||
|
||||
return recoveredClasses;
|
||||
|
||||
}
|
||||
|
||||
|
@ -171,8 +158,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
byte[] maskBytes = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
||||
|
||||
Address found = program.getMemory()
|
||||
.findBytes(commentBlock.getStart(),
|
||||
commentBlock.getEnd(), gccBytes, maskBytes, true, monitor);
|
||||
.findBytes(commentBlock.getStart(), commentBlock.getEnd(), gccBytes, maskBytes,
|
||||
true, monitor);
|
||||
if (found == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -184,8 +171,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
* Method to check for at least one special RTTI vtable
|
||||
* @return true if the program has at least one special vtable, false if none
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws InvalidInputException if bad characters creating labels
|
||||
*/
|
||||
private boolean hasSpecialVtable() throws CancelledException {
|
||||
private boolean hasSpecialVtable() throws CancelledException, InvalidInputException {
|
||||
|
||||
boolean hasSpecialVtable = createSpecialVtables();
|
||||
return hasSpecialVtable;
|
||||
|
@ -287,8 +275,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
}
|
||||
|
||||
private void updateClassesWithParentsAndFlags(List<Symbol> typeinfoSymbols)
|
||||
throws Exception {
|
||||
private void updateClassesWithParentsAndFlags(List<Symbol> typeinfoSymbols) throws Exception {
|
||||
|
||||
// add properties and parents to each class
|
||||
Iterator<Symbol> typeinfoIterator = typeinfoSymbols.iterator();
|
||||
|
@ -464,6 +451,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
while (vtableIterator.hasNext()) {
|
||||
|
||||
|
||||
monitor.checkCanceled();
|
||||
|
||||
Symbol vtableSymbol = vtableIterator.next();
|
||||
|
@ -534,14 +522,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
throw new Exception("typeinfo has global namespace " + typeinfoAddress);
|
||||
}
|
||||
|
||||
try {
|
||||
Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
|
||||
classNamespace, SourceType.ANALYSIS);
|
||||
vtableSymbols.add(vtableSymbol);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
continue;
|
||||
}
|
||||
Symbol vtableSymbol = symbolTable.createLabel(vtableAddress, VTABLE_LABEL,
|
||||
classNamespace, SourceType.ANALYSIS);
|
||||
vtableSymbols.add(vtableSymbol);
|
||||
|
||||
api.setPlateComment(vtableAddress, "vtable for " + classNamespace.getName(true));
|
||||
}
|
||||
|
@ -631,16 +614,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
if (namespacesByPath.isEmpty()) {
|
||||
|
||||
try {
|
||||
Namespace newNamespace =
|
||||
NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace,
|
||||
program, SourceType.ANALYSIS);
|
||||
return newNamespace;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
Namespace newNamespace = NamespaceUtils.createNamespaceHierarchy(name, vtableNamespace,
|
||||
program, SourceType.ANALYSIS);
|
||||
return newNamespace;
|
||||
|
||||
}
|
||||
if (namespacesByPath.size() == 1) {
|
||||
return namespacesByPath.get(0);
|
||||
|
@ -684,8 +661,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
// check direct refs to see if they are in undefined area or not in function
|
||||
byte[] bytes = ProgramMemoryUtil.getDirectAddressBytes(program, typeinfoAddress);
|
||||
|
||||
addByteSearchPattern(searcher, validTypeinfoRefs, typeinfoAddress, bytes,
|
||||
monitor);
|
||||
addByteSearchPattern(searcher, validTypeinfoRefs, typeinfoAddress, bytes, monitor);
|
||||
|
||||
}
|
||||
searcher.search(program, searchSet, monitor);
|
||||
|
@ -780,10 +756,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
* @param vtableNamespace the namespace of the given vtable
|
||||
* @param isPrimary true if the vtable is the primary one for the class
|
||||
* @param listOfAllVtables list of all vtables
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private void processVtable(Address vtableAddress, Namespace vtableNamespace, boolean isPrimary,
|
||||
List<Symbol> listOfAllVtables)
|
||||
throws Exception {
|
||||
List<Symbol> listOfAllVtables) throws CancelledException, Exception {
|
||||
|
||||
// skip the special tables
|
||||
if (vtableAddress.equals(class_type_info_vtable) ||
|
||||
|
@ -818,13 +794,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
Data typeinfoPtr = api.getDataAt(typeinfoAddress);
|
||||
if (typeinfoPtr == null) {
|
||||
DataType nullPointer = dataTypeManager.getPointer(null);
|
||||
try {
|
||||
api.createData(typeinfoAddress, nullPointer);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.debug(this,
|
||||
"Could not create typeinfo pointer at " + typeinfoAddress.toString());
|
||||
}
|
||||
|
||||
api.createData(typeinfoAddress, nullPointer);
|
||||
|
||||
}
|
||||
|
||||
// if not already named a construction-vtable then check to see if it is one so it can
|
||||
|
@ -850,33 +822,19 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
Namespace classNamespace = createConstructionNamespace(vtableSymbol,
|
||||
vttSymbolBeforeConstructionVtable);
|
||||
|
||||
try {
|
||||
vtableSymbol.setNameAndNamespace("construction-vtable",
|
||||
classNamespace, SourceType.ANALYSIS);
|
||||
vtableNamespace = vtableSymbol.getParentNamespace();
|
||||
// label the subVTTaddress
|
||||
symbolTable.createLabel(subVTTAddress, "subVTT_" + n,
|
||||
vttSymbolBeforeConstructionVtable.getParentNamespace(),
|
||||
SourceType.ANALYSIS);
|
||||
vtableSymbol.setNameAndNamespace("construction-vtable", classNamespace,
|
||||
SourceType.ANALYSIS);
|
||||
vtableNamespace = vtableSymbol.getParentNamespace();
|
||||
// label the subVTTaddress
|
||||
symbolTable.createLabel(subVTTAddress, "subVTT_" + n,
|
||||
vttSymbolBeforeConstructionVtable.getParentNamespace(),
|
||||
SourceType.ANALYSIS);
|
||||
|
||||
api.setPlateComment(vtableAddress, "construction vtable " + n +
|
||||
" for class " +
|
||||
api.setPlateComment(vtableAddress,
|
||||
"construction vtable " + n + " for class " +
|
||||
vttSymbolBeforeConstructionVtable.getParentNamespace()
|
||||
.getName(
|
||||
true));
|
||||
.getName(true));
|
||||
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.debug(this, e.getMessage());
|
||||
continue;
|
||||
}
|
||||
catch (CircularDependencyException e) {
|
||||
Msg.debug(this, e.getMessage());
|
||||
continue;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -919,25 +877,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
vftableLabel = "internal_" + vftableLabel;
|
||||
}
|
||||
|
||||
try {
|
||||
symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace,
|
||||
SourceType.ANALYSIS);
|
||||
symbolTable.createLabel(possibleVftableAddress, vftableLabel, vtableNamespace,
|
||||
SourceType.ANALYSIS);
|
||||
|
||||
createVftableArray(possibleVftableAddress, numFunctionPointers);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
Msg.debug(this, "Could not label vftable at " + possibleVftableAddress.toString());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.debug(this, "Could not label vftable at " + possibleVftableAddress.toString());
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return;
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
Msg.debug(this, "Couldn't create vftable due to Address out of bounds issue");
|
||||
return;
|
||||
}
|
||||
createVftableArray(possibleVftableAddress, numFunctionPointers);
|
||||
|
||||
// check for an internal vtable after the vftable and make a symbol there if there is one
|
||||
// will process them later
|
||||
|
@ -1050,7 +993,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
|
||||
private boolean createInternalVtable(Address possibleInternalVtableAddress,
|
||||
Namespace vtableNamespace) throws CancelledException {
|
||||
Namespace vtableNamespace) throws CancelledException, InvalidInputException, Exception {
|
||||
// check to see if it is a pointer and if so, it cannot be an internal vtable
|
||||
// as they contain at least one long
|
||||
Address pointer = getPointerToDefinedMemory(possibleInternalVtableAddress);
|
||||
|
@ -1071,27 +1014,12 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
(possibleInternalVtableSymbol.getSource() == SourceType.DEFAULT &&
|
||||
(isValidVtableStart(possibleInternalVtableAddress) ||
|
||||
isValidVftableStart(possibleInternalVtableAddress)))) {
|
||||
try {
|
||||
symbolTable.createLabel(possibleInternalVtableAddress,
|
||||
"internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace,
|
||||
SourceType.ANALYSIS);
|
||||
processVtable(possibleInternalVtableAddress, vtableNamespace, false, null);
|
||||
return true;
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
Msg.debug(this, "Could not label internal vtable at " +
|
||||
possibleInternalVtableAddress.toString());
|
||||
return true; // still created vtable, just couldn't name it
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.debug(this, "Could not label internal vtable at " +
|
||||
possibleInternalVtableAddress.toString());
|
||||
return true; // still created vtable, just couldn't name it
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
symbolTable.createLabel(possibleInternalVtableAddress,
|
||||
"internal_vtable_" + possibleInternalVtableAddress.toString(), vtableNamespace,
|
||||
SourceType.ANALYSIS);
|
||||
processVtable(possibleInternalVtableAddress, vtableNamespace, false, null);
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
|
@ -1102,8 +1030,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
* @param classNamespace the given namespace
|
||||
* @param address the address of the potential VTT table
|
||||
* @return true if a valid VTT has been discovered and label created
|
||||
* @throws Exception if data creation results in an exception
|
||||
*/
|
||||
private boolean createVTT(Namespace classNamespace, Address address) {
|
||||
private boolean createVTT(Namespace classNamespace, Address address) throws Exception {
|
||||
|
||||
// get pointer at address
|
||||
Address pointer = getPointerToDefinedMemory(address);
|
||||
|
@ -1120,22 +1049,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
|
||||
// if it is then create the VTT symbol and create pointer there
|
||||
try {
|
||||
symbolTable.createLabel(address, "VTT", classNamespace, SourceType.ANALYSIS);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
Msg.debug(this, "Could not label VTT at " + address.toString());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.debug(this, "Could not label VTT at " + address.toString());
|
||||
}
|
||||
|
||||
symbolTable.createLabel(address, "VTT", classNamespace, SourceType.ANALYSIS);
|
||||
|
||||
DataType nullPointer = dataTypeManager.getPointer(null);
|
||||
try {
|
||||
api.createData(pointer, nullPointer);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// already data there
|
||||
// already data there so don't try and overwrite it
|
||||
}
|
||||
|
||||
api.setPlateComment(address, "VTT for " + classNamespace.getName(true));
|
||||
|
@ -1144,7 +1066,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
|
||||
private Data createVftableArray(Address vftableAddress, int numFunctionPointers)
|
||||
throws CancelledException, AddressOutOfBoundsException {
|
||||
throws Exception {
|
||||
|
||||
api.clearListing(vftableAddress,
|
||||
vftableAddress.add((numFunctionPointers * defaultPointerSize - 1)));
|
||||
|
@ -1152,14 +1074,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
DataType pointerDataType = dataTypeManager.getPointer(null);
|
||||
ArrayDataType vftableArrayDataType =
|
||||
new ArrayDataType(pointerDataType, numFunctionPointers, defaultPointerSize);
|
||||
try {
|
||||
Data vftableArrayData = api.createData(vftableAddress, vftableArrayDataType);
|
||||
return vftableArrayData;
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Data vftableArrayData = api.createData(vftableAddress, vftableArrayDataType);
|
||||
return vftableArrayData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1349,35 +1266,25 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
* @param vtableAddress the given special vtable address
|
||||
* @return the address of the typeinfo in the vtable if replace was successful, null otherwise
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws InvalidInputException if bad characters when creating label
|
||||
*/
|
||||
private Address createSpecialVtable(Address vtableAddress) throws CancelledException {
|
||||
private Address createSpecialVtable(Address vtableAddress)
|
||||
throws CancelledException, InvalidInputException {
|
||||
|
||||
Symbol vtableSymbol = symbolTable.getPrimarySymbol(vtableAddress);
|
||||
|
||||
api.clearListing(vtableAddress);
|
||||
try {
|
||||
int vtableLongs = createVtableLongs(vtableAddress);
|
||||
|
||||
if (vtableLongs > 0) {
|
||||
int vtableLongs = createVtableLongs(vtableAddress);
|
||||
|
||||
Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize);
|
||||
symbolTable.createLabel(typeinfoAddress, "typeinfo",
|
||||
vtableSymbol.getParentNamespace(), SourceType.ANALYSIS);
|
||||
return typeinfoAddress;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (vtableLongs > 0) {
|
||||
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
return null;
|
||||
Address typeinfoAddress = vtableAddress.add(vtableLongs * defaultPointerSize);
|
||||
symbolTable.createLabel(typeinfoAddress, "typeinfo", vtableSymbol.getParentNamespace(),
|
||||
SourceType.ANALYSIS);
|
||||
return typeinfoAddress;
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1409,7 +1316,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
api.createData(address, pointer);
|
||||
Address referencedAddress = extraUtils.getSingleReferencedAddress(address);
|
||||
|
||||
// if it isn't valid, clear what we just created and increment to offset so
|
||||
// if it isn't a valid pointer, clear what we just created and increment to offset so
|
||||
// the next can be checked
|
||||
if (referencedAddress == null || !programAddressSet.contains(referencedAddress)) {
|
||||
api.clearListing(address);
|
||||
|
@ -1422,6 +1329,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
return numLongs;
|
||||
}
|
||||
}
|
||||
// if bump into existing data return the number found so far
|
||||
catch (Exception e) {
|
||||
return numLongs;
|
||||
}
|
||||
|
@ -1534,20 +1442,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
|
||||
private Data applyTypeinfoStructure(Structure typeInfoStructure, Address typeinfoAddress)
|
||||
throws CancelledException, AddressOutOfBoundsException {
|
||||
throws CancelledException, AddressOutOfBoundsException, Exception {
|
||||
|
||||
api.clearListing(typeinfoAddress, typeinfoAddress.add(typeInfoStructure.getLength() - 1));
|
||||
Data newStructure;
|
||||
try {
|
||||
newStructure = api.createData(typeinfoAddress, typeInfoStructure);
|
||||
}
|
||||
catch (Exception e) {
|
||||
newStructure = null;
|
||||
}
|
||||
if (newStructure == null) {
|
||||
Msg.debug(this,
|
||||
"Could not create " + typeInfoStructure.getName() + " at " + typeinfoAddress);
|
||||
}
|
||||
|
||||
newStructure = api.createData(typeinfoAddress, typeInfoStructure);
|
||||
|
||||
return newStructure;
|
||||
}
|
||||
|
||||
|
@ -1560,14 +1461,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
try {
|
||||
numBases = api.getInt(typeinfoAddress.add(offsetOfNumBases));
|
||||
}
|
||||
// if there isn't enough memory to get the int then return null
|
||||
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get or create the vmiClassTypeInfoStruct
|
||||
Structure vmiClassTypeinfoStructure =
|
||||
(Structure) dataTypeManager.getDataType(classDataTypesCategoryPath,
|
||||
VMI_CLASS_TYPE_INFO_STRUCTURE + numBases);
|
||||
Structure vmiClassTypeinfoStructure = (Structure) dataTypeManager
|
||||
.getDataType(classDataTypesCategoryPath, VMI_CLASS_TYPE_INFO_STRUCTURE + numBases);
|
||||
if (vmiClassTypeinfoStructure == null) {
|
||||
vmiClassTypeinfoStructure =
|
||||
createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases);
|
||||
|
@ -1575,7 +1476,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
return vmiClassTypeinfoStructure;
|
||||
}
|
||||
|
||||
private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) {
|
||||
private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
String mangledTypeinfo = getTypeinfoName(typeinfoAddress);
|
||||
if (mangledTypeinfo == null) {
|
||||
|
@ -1614,25 +1516,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
|
||||
// create the new typeinfo symbol in the demangled namespace
|
||||
try {
|
||||
Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace,
|
||||
SourceType.ANALYSIS);
|
||||
return newSymbol;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(this,
|
||||
typeinfoAddress.toString() + " invalid input exception " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
Msg.debug(this,
|
||||
typeinfoAddress.toString() + " illegal argument exception " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
Symbol newSymbol = symbolTable.createLabel(typeinfoAddress, "typeinfo", classNamespace,
|
||||
SourceType.ANALYSIS);
|
||||
return newSymbol;
|
||||
}
|
||||
|
||||
private Namespace createTypeinfoClassNamespace(String namespaceString) {
|
||||
private Namespace createTypeinfoClassNamespace(String namespaceString)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
int indexOfColons = namespaceString.indexOf("::");
|
||||
Namespace namespace = globalNamespace;
|
||||
|
@ -1659,20 +1550,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
return classNamespace;
|
||||
}
|
||||
|
||||
private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace) {
|
||||
private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
Namespace namespace = symbolTable.getNamespace(namespaceName, parentNamespace);
|
||||
if (namespace == null) {
|
||||
try {
|
||||
namespace = symbolTable.createNameSpace(parentNamespace, namespaceName,
|
||||
SourceType.ANALYSIS);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// shouldn't happen since it only gets here if the symbol didn't exist in the first place
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
namespace =
|
||||
symbolTable.createNameSpace(parentNamespace, namespaceName, SourceType.ANALYSIS);
|
||||
}
|
||||
return namespace;
|
||||
}
|
||||
|
@ -1710,12 +1595,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
StringDataType sdt = new StringDataType();
|
||||
|
||||
String str;
|
||||
try {
|
||||
str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen);
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -1814,26 +1696,37 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the references to the special type infos that exist in the current program.
|
||||
* @return the references to the special type infos that exist in the current program
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private List<Address> getTypeinfoAddressesUsingSpecialTypeinfos() throws CancelledException {
|
||||
|
||||
List<Address> specialTypeinfoRefs = new ArrayList<Address>();
|
||||
|
||||
Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info);
|
||||
for (Reference ref : refsToClassTypeinfo) {
|
||||
monitor.checkCanceled();
|
||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||
if (class_type_info != null) {
|
||||
Reference[] refsToClassTypeinfo = api.getReferencesTo(class_type_info);
|
||||
for (Reference ref : refsToClassTypeinfo) {
|
||||
monitor.checkCanceled();
|
||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||
}
|
||||
}
|
||||
|
||||
Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info);
|
||||
for (Reference ref : refsToSiClassTypeinfo) {
|
||||
monitor.checkCanceled();
|
||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||
if (si_class_type_info != null) {
|
||||
Reference[] refsToSiClassTypeinfo = api.getReferencesTo(si_class_type_info);
|
||||
for (Reference ref : refsToSiClassTypeinfo) {
|
||||
monitor.checkCanceled();
|
||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||
}
|
||||
}
|
||||
|
||||
Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info);
|
||||
for (Reference ref : refsToVmiClassTypeinfo) {
|
||||
monitor.checkCanceled();
|
||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||
if (vmi_class_type_info != null) {
|
||||
Reference[] refsToVmiClassTypeinfo = api.getReferencesTo(vmi_class_type_info);
|
||||
for (Reference ref : refsToVmiClassTypeinfo) {
|
||||
monitor.checkCanceled();
|
||||
specialTypeinfoRefs.add(ref.getFromAddress());
|
||||
}
|
||||
}
|
||||
|
||||
return specialTypeinfoRefs;
|
||||
|
@ -2153,8 +2046,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
//virtual base offset for the virtual base referenced (negative).
|
||||
long offset = (publicVirtualOffsetFlag & offsetMask) >> 8;
|
||||
|
||||
Msg.debug(this, "typeinfo " + typeinfoAddress + " base [" + i + "] isVirtual = " +
|
||||
isVirtual + " isPublic = " + isPublic + " offset = " + offset);
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "typeinfo " + typeinfoAddress + " base [" + i + "] isVirtual = " +
|
||||
isVirtual + " isPublic = " + isPublic + " offset = " + offset);
|
||||
}
|
||||
|
||||
// add order to parent and parent offset
|
||||
orderToParentMap.put(i, parentClass);
|
||||
|
@ -2232,8 +2127,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
* correct data types. Also creates a type info symbol at the correct offset in the table.
|
||||
* @return true if all found tables have a typeinfo symbol created successfully
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws InvalidInputException if bad characters creating labels
|
||||
*/
|
||||
private boolean createSpecialVtables() throws CancelledException {
|
||||
private boolean createSpecialVtables() throws CancelledException, InvalidInputException {
|
||||
|
||||
class_type_info_vtable = findSpecialVtable("__cxxabiv1", "__class_type_info");
|
||||
class_type_info = null;
|
||||
|
@ -2517,8 +2413,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
* Use information from RTTI Base class Arrays to create class hierarchy lists and maps
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private void createClassHierarchyListAndMapForGcc()
|
||||
throws CancelledException, Exception {
|
||||
private void createClassHierarchyListAndMapForGcc() throws CancelledException, Exception {
|
||||
|
||||
Iterator<RecoveredClass> recoveredClassIterator = recoveredClasses.iterator();
|
||||
while (recoveredClassIterator.hasNext()) {
|
||||
|
@ -2683,22 +2578,20 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
* address
|
||||
* @param start the starting address
|
||||
* @param end the ending address
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws Exception if data has conflict when created
|
||||
*/
|
||||
private void createLongs(Address start, Address end) {
|
||||
private void createLongs(Address start, Address end) throws CancelledException, Exception {
|
||||
|
||||
LongDataType longDT = new LongDataType();
|
||||
int offset = 0;
|
||||
Address address = start;
|
||||
while (address != null && !address.equals(end)) {
|
||||
try {
|
||||
api.clearListing(address);
|
||||
api.createData(address, longDT);
|
||||
offset += defaultPointerSize;
|
||||
address = getAddress(start, offset);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
|
||||
api.clearListing(address, address.add(defaultPointerSize - 1));
|
||||
api.createData(address, longDT);
|
||||
offset += defaultPointerSize;
|
||||
address = getAddress(start, offset);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2868,9 +2761,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
// can't handle creating class data types for classes with virtual parents yet
|
||||
if (recoveredClass.inheritsVirtualAncestor()) {
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, "Cannot create class data type for " +
|
||||
recoveredClass.getClassNamespace().getName(true) +
|
||||
" because it has virtual ancestors and we don't yet handle that use case.");
|
||||
Msg.debug(this,
|
||||
"Cannot create class data type for " +
|
||||
recoveredClass.getClassNamespace().getName(true) +
|
||||
" because it has virtual ancestors and we don't yet handle that use case.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -2901,27 +2795,23 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
// and class member data structure
|
||||
Structure classStruct = createSimpleClassStructure(recoveredClass, vfPointerDataTypes);
|
||||
|
||||
// check for DWARF -- if none add c/d/etc to class
|
||||
//TODO: if decide to replace dwarf data types then remove this check so the replaces
|
||||
// in the following methods can replace the dwarf data types
|
||||
if (!isDwarfLoaded) {
|
||||
|
||||
// Now that we have a class data type
|
||||
// name constructor and destructor functions and put into the class namespace
|
||||
addConstructorsToClassNamespace(recoveredClass, classStruct);
|
||||
addDestructorsToClassNamespace(recoveredClass, classStruct);
|
||||
// Now that we have a class data type
|
||||
// name constructor and destructor functions and put into the class namespace
|
||||
addConstructorsToClassNamespace(recoveredClass, classStruct);
|
||||
addDestructorsToClassNamespace(recoveredClass, classStruct);
|
||||
//TODO:
|
||||
// addNonThisDestructorsToClassNamespace(recoveredClass);
|
||||
// addVbaseDestructorsToClassNamespace(recoveredClass);
|
||||
// addVbtableToClassNamespace(recoveredClass);
|
||||
//
|
||||
//TODO:
|
||||
// // add secondary label on functions with inlined constructors or destructors
|
||||
// createInlinedConstructorComments(recoveredClass);
|
||||
// createInlinedDestructorComments(recoveredClass);
|
||||
// createIndeterminateInlineComments(recoveredClass);
|
||||
|
||||
// add label on constructor destructor functions that could not be determined which were which
|
||||
createIndeterminateLabels(recoveredClass, classStruct);
|
||||
}
|
||||
// add label on constructor destructor functions that could not be determined which were which
|
||||
createIndeterminateLabels(recoveredClass, classStruct);
|
||||
|
||||
|
||||
// This is done after the class structure is created and added to the dtmanager
|
||||
// because if done before the class structures are created
|
||||
|
|
|
@ -70,7 +70,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
public RTTIWindowsClassRecoverer(Program program, ProgramLocation location, PluginTool tool,
|
||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||
boolean nameVFunctions, boolean isPDBLoaded, boolean replaceClassStructures,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
TaskMonitor monitor) throws Exception {
|
||||
|
||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVFunctions,
|
||||
isPDBLoaded, replaceClassStructures, monitor);
|
||||
|
@ -98,121 +98,98 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void fixUpProgram() {
|
||||
public void fixUpProgram() throws CancelledException, Exception {
|
||||
|
||||
if (ghidraVersion.compareTo("10.0") < 0) {
|
||||
try {
|
||||
fixUpRttiAnalysis();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
fixUpRttiAnalysis();
|
||||
|
||||
}
|
||||
// if there are undefined areas that reference vftables attempt to create functions
|
||||
// containing them
|
||||
List<Symbol> vftableSymbols;
|
||||
try {
|
||||
vftableSymbols = getListOfVftableSymbols();
|
||||
createMissingFunctions(vftableSymbols);
|
||||
}
|
||||
catch (CancelledException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
List<Symbol> vftableSymbols = getListOfVftableSymbols();
|
||||
|
||||
createMissingFunctions(vftableSymbols);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RecoveredClass> createRecoveredClasses() {
|
||||
public List<RecoveredClass> createRecoveredClasses() throws Exception {
|
||||
|
||||
List<Symbol> vftableSymbols;
|
||||
try {
|
||||
vftableSymbols = getListOfVftableSymbols();
|
||||
|
||||
List<RecoveredClass> recoveredClasses =
|
||||
recoverClassesFromClassHierarchyDescriptors(vftableSymbols);
|
||||
vftableSymbols = getListOfVftableSymbols();
|
||||
|
||||
determineVftableOffsetsfromRTTI(recoveredClasses);
|
||||
List<RecoveredClass> recoveredClasses =
|
||||
recoverClassesFromClassHierarchyDescriptors(vftableSymbols);
|
||||
|
||||
// If no new classes have been recovered, no need to continue. Return out of script.
|
||||
if (recoveredClasses.isEmpty()) {
|
||||
determineVftableOffsetsfromRTTI(recoveredClasses);
|
||||
|
||||
return recoveredClasses;
|
||||
}
|
||||
|
||||
createCalledFunctionMap(recoveredClasses);
|
||||
|
||||
// figure out class hierarchies using either RTTI or vftable refs
|
||||
|
||||
monitor.setMessage("Assigning class inheritance and hierarchies");
|
||||
assignClassInheritanceAndHierarchies(recoveredClasses);
|
||||
|
||||
// Since PDB has applied so much information, use it to figure out the class member data 4
|
||||
// items (if it has them) and the constructors and destructors.
|
||||
if (isPDBLoaded) {
|
||||
monitor.setMessage(
|
||||
"Attempting to use pdb to assign class hierarchies and extend known pdb data " +
|
||||
"type information ...");
|
||||
|
||||
retrieveExistingClassStructures(recoveredClasses);
|
||||
|
||||
// assign constructors and destructors based on name
|
||||
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
|
||||
}
|
||||
// otherwise figure everything out from scratch
|
||||
else {
|
||||
monitor.setMessage("Figuring out class method types");
|
||||
// println(
|
||||
// "Figuring out class method types (constructor, destructor, inline constructor, " +
|
||||
// "inline destructor, deleting destructor, clone) ...");
|
||||
processConstructorAndDestructors(recoveredClasses);
|
||||
|
||||
}
|
||||
|
||||
// create order of vftable in constructor map for each class that has a constructor so far
|
||||
createVftableOrderMap(recoveredClasses);
|
||||
|
||||
determineParentClassInfoFromBaseClassArray(recoveredClasses);
|
||||
|
||||
assignParentClassToVftables(recoveredClasses);
|
||||
|
||||
// using all the information found above, create the class structures, add the constructor,
|
||||
// destructor, vfunctions to class which finds the appropriate class structure and assigns
|
||||
// to "this" param
|
||||
//println("Creating class data types and applying class structures...");
|
||||
monitor.setMessage("Creating class data types and applying class structures");
|
||||
figureOutClassDataMembers(recoveredClasses);
|
||||
|
||||
if (USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS) {
|
||||
extraUtils.createShortenedTemplateNamesForClasses(recoveredClasses);
|
||||
}
|
||||
|
||||
createAndApplyClassStructures(recoveredClasses);
|
||||
|
||||
if (!isPDBLoaded) {
|
||||
// create better vftable labels for multi vftable classes
|
||||
updateMultiVftableLabels(recoveredClasses);
|
||||
//println("Removing erroneous FID namespaces and corresponding class data types");
|
||||
removeEmptyClassesAndStructures();
|
||||
}
|
||||
// If no new classes have been recovered, no need to continue. Return out of script.
|
||||
if (recoveredClasses.isEmpty()) {
|
||||
|
||||
return recoveredClasses;
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
|
||||
createCalledFunctionMap(recoveredClasses);
|
||||
|
||||
// figure out class hierarchies using either RTTI or vftable refs
|
||||
|
||||
monitor.setMessage("Assigning class inheritance and hierarchies");
|
||||
assignClassInheritanceAndHierarchies(recoveredClasses);
|
||||
|
||||
// Since PDB has applied so much information, use it to figure out the class member data 4
|
||||
// items (if it has them) and the constructors and destructors.
|
||||
if (isPDBLoaded) {
|
||||
monitor.setMessage(
|
||||
"Attempting to use pdb to assign class hierarchies and extend known pdb data " +
|
||||
"type information ...");
|
||||
|
||||
retrieveExistingClassStructures(recoveredClasses);
|
||||
|
||||
// assign constructors and destructors based on name
|
||||
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
// otherwise figure everything out from scratch
|
||||
else {
|
||||
monitor.setMessage("Figuring out class method types");
|
||||
// println(
|
||||
// "Figuring out class method types (constructor, destructor, inline constructor, " +
|
||||
// "inline destructor, deleting destructor, clone) ...");
|
||||
processConstructorAndDestructors(recoveredClasses);
|
||||
|
||||
}
|
||||
|
||||
// create order of vftable in constructor map for each class that has a constructor so far
|
||||
createVftableOrderMap(recoveredClasses);
|
||||
|
||||
determineParentClassInfoFromBaseClassArray(recoveredClasses);
|
||||
|
||||
assignParentClassToVftables(recoveredClasses);
|
||||
|
||||
// using all the information found above, create the class structures, add the constructor,
|
||||
// destructor, vfunctions to class which finds the appropriate class structure and assigns
|
||||
// to "this" param
|
||||
//println("Creating class data types and applying class structures...");
|
||||
monitor.setMessage("Creating class data types and applying class structures");
|
||||
figureOutClassDataMembers(recoveredClasses);
|
||||
|
||||
if (USE_SHORT_TEMPLATE_NAMES_IN_STRUCTURE_FIELDS) {
|
||||
extraUtils.createShortenedTemplateNamesForClasses(recoveredClasses);
|
||||
}
|
||||
|
||||
createAndApplyClassStructures(recoveredClasses);
|
||||
|
||||
if (!isPDBLoaded) {
|
||||
// create better vftable labels for multi vftable classes
|
||||
updateMultiVftableLabels(recoveredClasses);
|
||||
//println("Removing erroneous FID namespaces and corresponding class data types");
|
||||
removeEmptyClassesAndStructures();
|
||||
}
|
||||
|
||||
return recoveredClasses;
|
||||
|
||||
}
|
||||
|
||||
private boolean isVisualStudioOrClangPe() {
|
||||
|
@ -351,7 +328,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
continue;
|
||||
}
|
||||
|
||||
//println("Cannot create RTTI_CompleteObjectLocator at " + symbol.getAddress());
|
||||
Msg.debug(this, "Cannot create RTTI_CompleteObjectLocator at " + symbol.getAddress());
|
||||
|
||||
}
|
||||
return completeObjectLocatorSymbols;
|
||||
|
@ -417,7 +394,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
continue;
|
||||
}
|
||||
|
||||
//println("Cannot create RTTI_Base_Class_Descriptor at " + symbol.getAddress());
|
||||
Msg.debug(this, "Cannot create RTTI_Base_Class_Descriptor at " + symbol.getAddress());
|
||||
|
||||
}
|
||||
return baseClassDescriptorSymbols;
|
||||
|
@ -661,8 +638,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
continue;
|
||||
}
|
||||
|
||||
// println("Failed to create a baseClassDescArray structure at " +
|
||||
// baseClassArrayAddress.toString());
|
||||
Msg.debug(this, "Failed to create a baseClassDescArray structure at " +
|
||||
baseClassArrayAddress.toString());
|
||||
}
|
||||
return baseClassArrayAddresses;
|
||||
}
|
||||
|
@ -736,13 +713,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
Namespace classNamespace = completeObjectLocatorSymbol.getParentNamespace();
|
||||
if (classNamespace.equals(globalNamespace)) {
|
||||
//println("no class namespace for " + completeObjectLocatorAddress.toString());
|
||||
Msg.debug(this,
|
||||
"No class namespace for " + completeObjectLocatorAddress.toString());
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference[] referencesTo = extraUtils.getReferencesTo(completeObjectLocatorAddress);
|
||||
if (referencesTo.length == 0) {
|
||||
//println("no refs to " + completeObjectLocatorAddress.toString());
|
||||
Msg.debug(this, "No refs to " + completeObjectLocatorAddress.toString());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -995,7 +973,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
* @throws Exception when cancelled
|
||||
*/
|
||||
private void determineVftableOffsetsfromRTTI(List<RecoveredClass> recoveredClasses)
|
||||
throws Exception {
|
||||
throws AddressOutOfBoundsException, Exception {
|
||||
|
||||
PointerDataType pointerDataType = new PointerDataType();
|
||||
|
||||
|
@ -1020,22 +998,16 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
Address colAddress = extraUtils.getReferencedAddress(ptrToColAddress, false);
|
||||
|
||||
if (colAddress == null) {
|
||||
// println(recoveredClass.getName() + " couldn't get referenced col from " +
|
||||
// ptrToColAddress.toString());
|
||||
Msg.debug(this, recoveredClass.getName() +
|
||||
" couldn't get referenced col from " + ptrToColAddress.toString());
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Address addressOfOffset = colAddress.add(4);
|
||||
Address addressOfOffset = colAddress.add(4);
|
||||
|
||||
int offset = extraUtils.getInt(addressOfOffset);
|
||||
int offset = extraUtils.getInt(addressOfOffset);
|
||||
|
||||
recoveredClass.addClassOffsetToVftableMapping(offset, vftableAddress);
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
// println(recoveredClass.getName() + "error getting offset at address " +
|
||||
// colAddress.toString() + " + 4");
|
||||
}
|
||||
recoveredClass.addClassOffsetToVftableMapping(offset, vftableAddress);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1063,9 +1035,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
int inheritanceFlag = getClassInheritanceFlag(recoveredClass.getClassNamespace());
|
||||
if (inheritanceFlag == NONE) {
|
||||
// println(
|
||||
// "Could not get inheritance attribute from class hierarchy structure for " +
|
||||
// "class " + recoveredClass.getName());
|
||||
Msg.debug(this,
|
||||
"Could not get inheritance attribute from class hierarchy structure for " +
|
||||
"class " + recoveredClass.getName());
|
||||
recoveredClassesIterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
@ -1250,21 +1222,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
RTTI_CLASS_HIERARCHY_DESCRIPTOR_LABEL, classNamespace, false);
|
||||
|
||||
if (symbols.size() >= 1) {
|
||||
|
||||
try {
|
||||
return (extraUtils.getInt(symbols.get(0).getAddress().add(4)));
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
// println("Could not get class inheritance flag at address " +
|
||||
// symbols.get(0).getAddress().toString());
|
||||
return NONE;
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
// println("Could not get class inheritance flag at address " +
|
||||
// symbols.get(0).getAddress().toString());
|
||||
return NONE;
|
||||
}
|
||||
return (extraUtils.getInt(symbols.get(0).getAddress().add(4)));
|
||||
}
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
|
@ -1399,7 +1359,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
// this should never happen
|
||||
if (baseClassArray.size() != 1) {
|
||||
throw new Exception(
|
||||
recoveredClass.getName() + " has more than one base class array");
|
||||
recoveredClass.getName() + " has more than one RTTI base class array");
|
||||
}
|
||||
|
||||
Address baseClassArrayAddress = baseClassArray.get(0).getAddress();
|
||||
|
@ -1407,7 +1367,8 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
if (!baseClassArrayData.isArray()) {
|
||||
throw new Exception(
|
||||
recoveredClass.getName() + " base class array is not an array data type");
|
||||
recoveredClass.getName() + " RTTI base class array is not an array data type " +
|
||||
baseClassArrayAddress.toString());
|
||||
|
||||
}
|
||||
|
||||
|
@ -2690,9 +2651,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
* @return the offset of the single virtual parent or null if there is not a single virtual parent
|
||||
* or if there is no mapping in the offset map for that parent
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws AddressOutOfBoundsException
|
||||
* @throws MemoryAccessException
|
||||
*/
|
||||
public Integer getSingleVirtualParentOffset(RecoveredClass recoveredClass)
|
||||
throws CancelledException {
|
||||
throws CancelledException, MemoryAccessException, AddressOutOfBoundsException {
|
||||
|
||||
List<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass);
|
||||
if (virtualParentClasses.size() != 1) {
|
||||
|
@ -2706,7 +2669,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
}
|
||||
|
||||
private Map<RecoveredClass, Integer> getBaseClassOffsetMap(RecoveredClass recoveredClass)
|
||||
throws CancelledException {
|
||||
throws CancelledException, MemoryAccessException, AddressOutOfBoundsException {
|
||||
|
||||
Map<RecoveredClass, Integer> parentOffsetMap = new HashMap<RecoveredClass, Integer>();
|
||||
|
||||
|
@ -2727,52 +2690,39 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
RecoveredClass baseClass =
|
||||
getClassFromBaseClassDescriptor(baseClassDescriptorAddress);
|
||||
if (baseClass == null) {
|
||||
// TODO: msg and return null
|
||||
continue;
|
||||
}
|
||||
|
||||
// Continue if the class has mult inh but base class is not on the parent list
|
||||
//TODO: possibly update to include all base classes
|
||||
if (!recoveredClass.getParentList().contains(baseClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int mdisp = api.getInt(baseClassDescriptorAddress.add(8));
|
||||
int pdisp = api.getInt(baseClassDescriptorAddress.add(12));
|
||||
int vdisp = api.getInt(baseClassDescriptorAddress.add(16));
|
||||
if (pdisp == -1) {
|
||||
|
||||
baseClassOffset = mdisp;
|
||||
}
|
||||
else {
|
||||
// else need to fill in the virtually inherited ones
|
||||
// get the offset of this base class in the class using the vbtable
|
||||
Address vbtableAddress = recoveredClass.getVbtableAddress();
|
||||
if (vbtableAddress == null) {
|
||||
Msg.error(this,
|
||||
"Cannot retrieve vbtable address so cannot create base class offset map for class " +
|
||||
recoveredClass.getName());
|
||||
return null;
|
||||
}
|
||||
|
||||
baseClassOffset =
|
||||
api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
|
||||
}
|
||||
|
||||
parentOffsetMap.put(baseClass, baseClassOffset);
|
||||
|
||||
RecoveredClass baseClass = getClassFromBaseClassDescriptor(baseClassDescriptorAddress);
|
||||
if (baseClass == null) {
|
||||
// TODO: return null?
|
||||
Msg.debug(this, "Could not get base class from baseClassDescriptor " +
|
||||
baseClassDescriptorAddress.toString());
|
||||
continue;
|
||||
}
|
||||
|
||||
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
||||
Msg.error(this,
|
||||
"Cannot create base class offset map for class " + recoveredClass.getName());
|
||||
return null;
|
||||
// Continue if the class has mult inh but base class is not on the parent list
|
||||
//TODO: possibly update to include all base classes
|
||||
if (!recoveredClass.getParentList().contains(baseClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int mdisp = api.getInt(baseClassDescriptorAddress.add(8));
|
||||
int pdisp = api.getInt(baseClassDescriptorAddress.add(12));
|
||||
int vdisp = api.getInt(baseClassDescriptorAddress.add(16));
|
||||
if (pdisp == -1) {
|
||||
baseClassOffset = mdisp;
|
||||
}
|
||||
else {
|
||||
// else need to fill in the virtually inherited ones
|
||||
// get the offset of this base class in the class using the vbtable
|
||||
Address vbtableAddress = recoveredClass.getVbtableAddress();
|
||||
if (vbtableAddress == null) {
|
||||
Msg.error(this,
|
||||
"Cannot retrieve vbtable address so cannot create base class offset map for class " +
|
||||
recoveredClass.getName());
|
||||
return null;
|
||||
}
|
||||
baseClassOffset = api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
|
||||
}
|
||||
parentOffsetMap.put(baseClass, baseClassOffset);
|
||||
}
|
||||
return parentOffsetMap;
|
||||
}
|
||||
|
@ -2885,9 +2835,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
* order to distinguish which base class the vftable is for.
|
||||
* @param recoveredClasses the list of RecoveredClass objects
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws InvalidInputException if bad chars trying to label
|
||||
* @throws DuplicateNameException if duplicate name
|
||||
*/
|
||||
private void updateMultiVftableLabels(List<RecoveredClass> recoveredClasses)
|
||||
throws CancelledException {
|
||||
throws CancelledException, DuplicateNameException, InvalidInputException {
|
||||
|
||||
if (recoveredClasses.isEmpty()) {
|
||||
return;
|
||||
|
@ -2914,19 +2866,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
if (!shortenedTemplateName.isBlank()) {
|
||||
baseClassName = shortenedTemplateName;
|
||||
}
|
||||
try {
|
||||
primarySymbol.setName("vftable_for_" + baseClassName,
|
||||
primarySymbol.getSource());
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// skip if it's already the correct name
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.debug(this,
|
||||
"Could not create vftable_for_" + baseClassName +
|
||||
" due to invalid input exeption at address " +
|
||||
vftableAddress.toString());
|
||||
}
|
||||
|
||||
primarySymbol.setName("vftable_for_" + baseClassName,
|
||||
primarySymbol.getSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,8 @@ public class RecoveredClassUtils {
|
|||
|
||||
public RecoveredClassUtils(Program program, ProgramLocation location, PluginTool tool,
|
||||
FlatProgramAPI api, boolean createBookmarks, boolean useShortTemplates,
|
||||
boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor) {
|
||||
boolean nameVunctions, boolean replaceClassStructures, TaskMonitor monitor)
|
||||
throws Exception {
|
||||
|
||||
this.monitor = monitor;
|
||||
this.program = program;
|
||||
|
@ -551,13 +552,13 @@ public class RecoveredClassUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Method to return reference to the class vftable in the given function
|
||||
* Method to return the first reference to the class vftable in the given function
|
||||
* @param recoveredClass the given class
|
||||
* @param function the given function
|
||||
* @return the reference to the class vftable in the given function or null if there isn't one
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public Address getClassVftableReference(RecoveredClass recoveredClass,
|
||||
public Address getFirstClassVftableReference(RecoveredClass recoveredClass,
|
||||
Function function) throws CancelledException {
|
||||
|
||||
List<Address> vftableReferenceList = functionToVftableRefsMap.get(function);
|
||||
|
@ -566,6 +567,8 @@ public class RecoveredClassUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
Collections.sort(vftableReferenceList);
|
||||
|
||||
Iterator<Address> vftableRefs = vftableReferenceList.iterator();
|
||||
while (vftableRefs.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
|
@ -589,39 +592,6 @@ public class RecoveredClassUtils {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return the vftable reference in the given function that corresponds to the given class
|
||||
* @param function the given function
|
||||
* @param recoveredClass the given class
|
||||
* @return the vftableRef address in the given function that corresponds to the given class
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public Address getClassVftableRefInFunction(Function function, RecoveredClass recoveredClass)
|
||||
throws CancelledException {
|
||||
|
||||
List<Address> listOfClassRefsInFunction =
|
||||
getSortedListOfAncestorRefsInFunction(function, recoveredClass);
|
||||
|
||||
Iterator<Address> iterator = listOfClassRefsInFunction.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
Address classRef = iterator.next();
|
||||
Address vftableAddress = vftableRefToVftableMap.get(classRef);
|
||||
|
||||
// skip the ones that aren't vftable refs
|
||||
if (vftableAddress == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// return the first one that is a vftable ref to the given class
|
||||
RecoveredClass vftableClass = vftableToClassMap.get(vftableAddress);
|
||||
if (vftableClass.equals(recoveredClass)) {
|
||||
return classRef;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a sorted list of both vftable and call refs to ancestor classes of the given
|
||||
* class in the given function
|
||||
|
@ -3389,7 +3359,7 @@ public class RecoveredClassUtils {
|
|||
replaceClassStructure(destructorFunction, className, classStruct);
|
||||
}
|
||||
|
||||
destructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
|
||||
destructorFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3445,7 +3415,7 @@ public class RecoveredClassUtils {
|
|||
classStruct);
|
||||
}
|
||||
|
||||
vbaseDestructorFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
|
||||
vbaseDestructorFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3635,7 +3605,9 @@ public class RecoveredClassUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
//TODO: decide whether to replace dwarf or not
|
||||
if (categoryPath.contains("DWARF")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// test to see if the data type is an empty structure with "PlaceHolder Class Structure" in
|
||||
// the description
|
||||
|
@ -5146,25 +5118,12 @@ public class RecoveredClassUtils {
|
|||
while (inlinedDestructorIterator.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
Function destructorFunction = inlinedDestructorIterator.next();
|
||||
Address classVftableRef =
|
||||
getClassVftableRefInFunction(destructorFunction, recoveredClass);
|
||||
|
||||
//TODO: use this one instead if testing pans out
|
||||
Address otherWayRef = getClassVftableReference(recoveredClass, destructorFunction);
|
||||
Address classVftableRef = getFirstClassVftableReference(recoveredClass, destructorFunction);
|
||||
|
||||
if (classVftableRef == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO: remove after testing
|
||||
if (!classVftableRef.equals(otherWayRef)) {
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, recoveredClass.getName() + " function " +
|
||||
destructorFunction.getEntryPoint().toString() + " first ref: " +
|
||||
classVftableRef.toString() + " other way ref: " + otherWayRef.toString());
|
||||
}
|
||||
}
|
||||
|
||||
String markupString = classNamespace.getName(true) + "::~" + className;
|
||||
api.setPreComment(classVftableRef, "inlined destructor: " + markupString);
|
||||
|
||||
|
@ -5189,24 +5148,11 @@ public class RecoveredClassUtils {
|
|||
Function functionContainingInline = functionsContainingInlineIterator.next();
|
||||
|
||||
Address classVftableRef =
|
||||
getClassVftableRefInFunction(functionContainingInline, recoveredClass);
|
||||
//TODO: use this one if testing more progs gives same results
|
||||
Address otherWayRef =
|
||||
getClassVftableReference(recoveredClass, functionContainingInline);
|
||||
getFirstClassVftableReference(recoveredClass, functionContainingInline);
|
||||
|
||||
if (classVftableRef == null) {
|
||||
continue;
|
||||
}
|
||||
//TODO: remove after testing
|
||||
if (!classVftableRef.equals(otherWayRef)) {
|
||||
if (DEBUG) {
|
||||
Msg.debug(this,
|
||||
recoveredClass.getName() + " function " +
|
||||
functionContainingInline.getEntryPoint().toString() + " first ref: " +
|
||||
classVftableRef.toString() + " other way ref: " +
|
||||
otherWayRef.toString());
|
||||
}
|
||||
}
|
||||
|
||||
String markupString = "inlined constructor or destructor (approx location) for " +
|
||||
classNamespace.getName(true);
|
||||
|
@ -5419,22 +5365,11 @@ public class RecoveredClassUtils {
|
|||
// Type 4 inlined - inlined class c/d called from other than first function
|
||||
// either just vftable ref before operator delete or vftableref followed by parent call
|
||||
// before operator delete
|
||||
Address vftableReference = getFirstClassVftableReference(recoveredClass, virtualFunction);
|
||||
|
||||
Address vftableReference = getClassVftableReference(recoveredClass, virtualFunction);
|
||||
|
||||
//TODO remove after testing against prev method in more progs
|
||||
Address otherWayRef = getClassVftableRefInFunction(virtualFunction, recoveredClass);
|
||||
if (vftableReference == null) {
|
||||
return;
|
||||
}
|
||||
if (!vftableReference.equals(otherWayRef)) {
|
||||
if (DEBUG) {
|
||||
Msg.debug(this, recoveredClass.getName() + " function " +
|
||||
virtualFunction.getEntryPoint().toString() + " first ref: " +
|
||||
vftableReference.toString() + " other way ref (with ances): " +
|
||||
otherWayRef.toString());
|
||||
}
|
||||
}
|
||||
|
||||
List<Function> possibleParentDestructors = getPossibleParentDestructors(virtualFunction);
|
||||
|
||||
|
@ -5725,43 +5660,6 @@ public class RecoveredClassUtils {
|
|||
|
||||
}
|
||||
|
||||
private boolean isDataAtOffsetEquivalentToStructure(Structure outerStructure,
|
||||
Structure innerStructure, int offset) {
|
||||
|
||||
DataTypeComponent[] innerStructComponents = innerStructure.getDefinedComponents();
|
||||
for (DataTypeComponent innerComponent : innerStructComponents) {
|
||||
int innerOffset = innerComponent.getOffset();
|
||||
|
||||
DataTypeComponent outerComponent = outerStructure.getComponentAt(offset + innerOffset);
|
||||
if (outerComponent == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (innerComponent.getFieldName().equals("vftablePtr")) {
|
||||
|
||||
// if one is vftablePtr and other isn't - return false
|
||||
if (!outerComponent.getFieldName().equals("vftablePtr")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if both are vftablePtrs they should both contain the innerStructure name (ie the class name) in
|
||||
// the vftablePtr data type name (either <some_class_name>_vftable_for_<innerStruct name> or <innerStruct name>_vftable *
|
||||
if (outerComponent.getDataType().getDisplayName().contains(
|
||||
innerStructure.getName()) &&
|
||||
!innerComponent.getDataType().getDisplayName().contains(
|
||||
innerStructure.getName())) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!innerComponent.getDataType().equals(outerComponent.getDataType())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to determine if the given data type is the virtual parent class structure for the given class
|
||||
* @param recoveredClass the given class
|
||||
|
@ -6552,7 +6450,7 @@ public class RecoveredClassUtils {
|
|||
if (!atexitCalledFunctions.contains(calledFunction)) {
|
||||
atexitCalledFunctions.add(calledFunction);
|
||||
}
|
||||
calledFunction.setReturnType(DataType.VOID, SourceType.ANALYSIS);
|
||||
calledFunction.setReturnType(new VoidDataType(), SourceType.ANALYSIS);
|
||||
}
|
||||
else {
|
||||
if (!atexitCalledFunctions.contains(calledFunction)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue