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:
ghidra007 2021-11-25 19:02:53 +00:00
parent 318f13d9a2
commit 80538d8c49
7 changed files with 428 additions and 631 deletions

View file

@ -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);
} }

View file

@ -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);
} }
/** /**

View file

@ -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("/");

View file

@ -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;
} }

View file

@ -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

View file

@ -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());
}
}
} }
} }
} }

View file

@ -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)) {