mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-1044 Fixed promotion of namespaces to only verified classes and added creation of typeinfo structs in stripped gcc binaries
This commit is contained in:
parent
cde02a91eb
commit
020df708e2
5 changed files with 503 additions and 191 deletions
|
@ -163,6 +163,11 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
else if (isGcc()) {
|
else if (isGcc()) {
|
||||||
|
|
||||||
|
boolean runGcc = askYesNo("GCC Class Recovery Still Under Development",
|
||||||
|
"I understand that gcc class recovery is still under development and my results will be incomplete but want to run this anyway.");
|
||||||
|
if (!runGcc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
nameVfunctions = true;
|
nameVfunctions = true;
|
||||||
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
|
recoverClassesFromRTTI = new RTTIGccClassRecoverer(currentProgram, currentLocation,
|
||||||
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
|
state.getTool(), this, BOOKMARK_FOUND_FUNCTIONS,
|
||||||
|
@ -545,25 +550,6 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//TODO: call this before create data in debug mode from script
|
|
||||||
private void findClassesWithErrors(List<RecoveredClass> recoveredClasses)
|
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
Iterator<RecoveredClass> iterator = recoveredClasses.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
monitor.checkCanceled();
|
|
||||||
RecoveredClass recoveredClass = iterator.next();
|
|
||||||
if (hasConstructorDestructorDiscrepancy(recoveredClass)) {
|
|
||||||
println(recoveredClass.getName() + " has function on both c and d lists");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to analyze the program changes with the decompiler parameter ID analyzer
|
* Method to analyze the program changes with the decompiler parameter ID analyzer
|
||||||
* @param set the set of addresses to analyze
|
* @param set the set of addresses to analyze
|
||||||
|
|
|
@ -131,25 +131,25 @@ public class RTTIClassRecoverer extends RecoveredClassUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to promote the namespace is a class namespace.
|
* Method to promote the namespace is a class namespace.
|
||||||
* @param vftableNamespace 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.
|
||||||
*/
|
*/
|
||||||
public Namespace promoteToClassNamespace(Namespace vftableNamespace) {
|
public Namespace promoteToClassNamespace(Namespace namespace) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Namespace newClass = NamespaceUtils.convertNamespaceToClass(vftableNamespace);
|
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
||||||
|
|
||||||
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
||||||
if (symbolType == SymbolType.CLASS) {
|
if (symbolType == SymbolType.CLASS) {
|
||||||
return newClass;
|
return newClass;
|
||||||
}
|
}
|
||||||
Msg.debug(this,
|
Msg.debug(this,
|
||||||
"Could not promote " + vftableNamespace.getName() + " to a class namespace");
|
"Could not promote " + namespace.getName() + " to a class namespace");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
|
|
||||||
Msg.debug(this, "Could not promote " + vftableNamespace.getName() +
|
Msg.debug(this, "Could not promote " + namespace.getName() +
|
||||||
" to a class namespace because " + e.getMessage());
|
" to a class namespace because " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package classrecovery;
|
package classrecovery;
|
||||||
|
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
*
|
*
|
||||||
|
@ -34,18 +35,18 @@ import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import ghidra.app.cmd.label.DemanglerCmd;
|
import ghidra.app.cmd.label.DemanglerCmd;
|
||||||
|
import ghidra.app.util.demangler.*;
|
||||||
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.flatapi.FlatProgramAPI;
|
import ghidra.program.flatapi.FlatProgramAPI;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
@ -70,8 +71,7 @@ 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 nameVfunctions, TaskMonitor monitor) {
|
||||||
TaskMonitor monitor) {
|
|
||||||
|
|
||||||
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
super(program, location, tool, api, createBookmarks, useShortTemplates, nameVfunctions,
|
||||||
monitor);
|
monitor);
|
||||||
|
@ -98,7 +98,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
@Override
|
@Override
|
||||||
public List<RecoveredClass> createRecoveredClasses() {
|
public List<RecoveredClass> createRecoveredClasses() {
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
List<RecoveredClass> recoveredClasses = processGccRTTI();
|
List<RecoveredClass> recoveredClasses = processGccRTTI();
|
||||||
|
@ -111,7 +110,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
createClassHierarchyListAndMapForGcc(recoveredClasses);
|
createClassHierarchyListAndMapForGcc(recoveredClasses);
|
||||||
|
|
||||||
|
//TODO: check for dwarf
|
||||||
|
//boolean isDwarfLoaded = isDwarfLoaded();
|
||||||
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
|
assignConstructorsAndDestructorsUsingExistingName(recoveredClasses);
|
||||||
|
//else
|
||||||
|
// find c/ds other way
|
||||||
|
|
||||||
createVftableOrderMap(recoveredClasses);
|
createVftableOrderMap(recoveredClasses);
|
||||||
|
|
||||||
|
@ -132,8 +135,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isGcc() {
|
private boolean isGcc() {
|
||||||
|
@ -163,8 +164,7 @@ 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().findBytes(commentBlock.getStart(),
|
Address found = program.getMemory().findBytes(commentBlock.getStart(),
|
||||||
commentBlock.getEnd(),
|
commentBlock.getEnd(), gccBytes, maskBytes, true, monitor);
|
||||||
gccBytes, maskBytes, true, monitor);
|
|
||||||
if (found == null) {
|
if (found == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
private List<RecoveredClass> processGccRTTI() throws CancelledException, Exception {
|
private List<RecoveredClass> processGccRTTI() throws CancelledException, Exception {
|
||||||
|
|
||||||
|
|
||||||
// create rtti vtables and typeinfo structs
|
// create rtti vtables and typeinfo structs
|
||||||
// find the three special vtables and replace the incorrectly made array with
|
// find the three special vtables and replace the incorrectly made array with
|
||||||
// data types found in vtable
|
// data types found in vtable
|
||||||
|
@ -266,7 +265,15 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: are all recovered classes in the map?
|
// check map for classes that are not in the recoveredClass list
|
||||||
|
Set<Namespace> keySet = namespaceToClassMap.keySet();
|
||||||
|
for (Namespace namespace : keySet) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
RecoveredClass recoveredClass = namespaceToClassMap.get(namespace);
|
||||||
|
if (!recoveredClasses.contains(recoveredClass)) {
|
||||||
|
recoveredClasses.add(recoveredClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update the recoveredClass list with the typeinfo classes that do not have vtables
|
// update the recoveredClass list with the typeinfo classes that do not have vtables
|
||||||
Set<RecoveredClass> typeinfoClasses = classToTypeinfoMap.keySet();
|
Set<RecoveredClass> typeinfoClasses = classToTypeinfoMap.keySet();
|
||||||
|
@ -308,9 +315,14 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Msg.debug(this, "Shouldn't be a null class here: " + classNamespace.getName());
|
Msg.debug(this, "Shouldn't be a null class here: " + classNamespace.getName());
|
||||||
}
|
}
|
||||||
recoveredClass = addNoVftableClass(classNamespace);
|
recoveredClass = createNewClass(classNamespace, false);
|
||||||
recoveredClasses.add(recoveredClass);
|
recoveredClasses.add(recoveredClass);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (!recoveredClasses.contains(recoveredClass)) {
|
||||||
|
recoveredClasses.add(recoveredClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Address specialTypeinfoRef = extraUtils.getSingleReferencedAddress(typeinfoAddress);
|
Address specialTypeinfoRef = extraUtils.getSingleReferencedAddress(typeinfoAddress);
|
||||||
if (specialTypeinfoRef == null) {
|
if (specialTypeinfoRef == null) {
|
||||||
|
@ -392,21 +404,22 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
recoveredClass.setHasMultipleInheritance(true);
|
recoveredClass.setHasMultipleInheritance(true);
|
||||||
|
|
||||||
|
|
||||||
if (recoveredClass.inheritsVirtualAncestor()) {
|
if (recoveredClass.inheritsVirtualAncestor()) {
|
||||||
recoveredClass.setHasMultipleVirtualInheritance(true);
|
recoveredClass.setHasMultipleVirtualInheritance(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RecoveredClass> parents = addGccClassParents(recoveredClass, typeinfoAddress);
|
List<RecoveredClass> parents = addGccClassParents(recoveredClass, typeinfoAddress);
|
||||||
|
if (parents.isEmpty()) {
|
||||||
if (!recoveredClasses.containsAll(parents)) {
|
continue;
|
||||||
if (DEBUG) {
|
}
|
||||||
Msg.debug(this,
|
for (RecoveredClass parent : parents) {
|
||||||
"missing some parents from " + recoveredClass.getName() + " on list");
|
monitor.checkCanceled();
|
||||||
|
if (!recoveredClasses.contains(parent)) {
|
||||||
|
Msg.debug(this, "adding parent " + parent.getName() + " to list.");
|
||||||
|
recoveredClasses.add(parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// newNonVftableClasses =
|
|
||||||
// addMissingClasses(parents, newNonVftableClasses, recoveredClasses);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +430,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
RecoveredClass recoveredClass = recoveredClassIterator.next();
|
||||||
|
|
||||||
Msg.debug(this, "Processing class " + recoveredClass.getName());
|
Msg.debug(this, "Processing class " + recoveredClass.getClassNamespace().getName(true));
|
||||||
|
|
||||||
List<Address> vftableAddresses = recoveredClass.getVftableAddresses();
|
List<Address> vftableAddresses = recoveredClass.getVftableAddresses();
|
||||||
|
|
||||||
|
@ -443,21 +456,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
private void createGccRttiData() throws CancelledException, Exception {
|
private void createGccRttiData() throws CancelledException, Exception {
|
||||||
|
|
||||||
// TODO: find typeinfo's using other means besides their names since in static case they
|
|
||||||
// aren't named
|
|
||||||
// TODO: either check for DWARF and do below if dwarf and another method to find them first
|
|
||||||
// if not dwarf or combine and either way they are found - immediately call the create typeinfo struct
|
|
||||||
// but for one at a time.
|
|
||||||
// remove the ones in the list that are in the EXTERNAL (space or any non-loaded sapce)
|
|
||||||
// but keep the special ones on symbol list or maybe removet hem here too then don't have
|
|
||||||
// to keep skipping them later
|
|
||||||
|
|
||||||
// find all typeinfo symbols and get their class namespace and create RecoveredClass object
|
|
||||||
List<Symbol> typeinfoSymbols = extraUtils.getListOfSymbolsInAddressSet(
|
|
||||||
program.getAddressFactory().getAddressSet(), "typeinfo", true);
|
|
||||||
|
|
||||||
// create the appropriate type of type info struct at the various typeinfo symbol locations
|
// create the appropriate type of type info struct at the various typeinfo symbol locations
|
||||||
createTypeinfoStructs(typeinfoSymbols);
|
createTypeinfoStructs();
|
||||||
|
|
||||||
// process vtables and create classes for the vtables that have no typeinfo
|
// process vtables and create classes for the vtables that have no typeinfo
|
||||||
processVtables();
|
processVtables();
|
||||||
|
@ -663,8 +663,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: maybe print a warning if the first item is not all zeros bc usually they are -- but pass
|
|
||||||
// it even then
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -906,7 +904,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTypeinfoStructs(List<Symbol> typeinfoSymbols) throws CancelledException {
|
private void createTypeinfoStructs() throws CancelledException {
|
||||||
|
|
||||||
StructureDataType classTypeInfoStructure = createClassTypeInfoStructure();
|
StructureDataType classTypeInfoStructure = createClassTypeInfoStructure();
|
||||||
StructureDataType siClassTypeInfoStructure =
|
StructureDataType siClassTypeInfoStructure =
|
||||||
|
@ -914,23 +912,28 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
StructureDataType baseClassTypeInfoStructure =
|
StructureDataType baseClassTypeInfoStructure =
|
||||||
createBaseClassTypeInfoStructure(classTypeInfoStructure);
|
createBaseClassTypeInfoStructure(classTypeInfoStructure);
|
||||||
|
|
||||||
Iterator<Symbol> typeinfoIterator = typeinfoSymbols.iterator();
|
List<Address> typeinfoAddresses;
|
||||||
while (typeinfoIterator.hasNext()) {
|
// get dwarf option
|
||||||
|
boolean isDwarfLoaded = isDwarfLoaded();
|
||||||
monitor.checkCanceled();
|
// if dwarf get using symbols
|
||||||
|
if (isDwarfLoaded) {
|
||||||
Symbol typeinfoSymbol = typeinfoIterator.next();
|
typeinfoAddresses = getTypeinfoAddressesUsingSymbols();
|
||||||
Address typeinfoAddress = typeinfoSymbol.getAddress();
|
}
|
||||||
|
else {
|
||||||
// skip the typeinfo symbols from the three special typeinfos
|
// if not, get using ref to specials
|
||||||
if (isSpecialTypeinfo(typeinfoAddress)) {
|
if (hasExternalRelocationRefs()) {
|
||||||
continue;
|
typeinfoAddresses = getTypeinfoAddressesUsingRelocationTable();
|
||||||
}
|
}
|
||||||
// check for EXTERNAL block and look for specialTypeinfoRef there
|
else {
|
||||||
// if fix works, put external block error message and to contact us
|
typeinfoAddresses = getTypeinfoAddressesUsingSpecialTypeinfos();
|
||||||
if (hasExternalBlock() && isSpecialVtable(typeinfoAddress)) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeinfoAddresses.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Address typeinfoAddress : typeinfoAddresses) {
|
||||||
|
|
||||||
Address specialTypeinfoRef = extraUtils.getSingleReferencedAddress(typeinfoAddress);
|
Address specialTypeinfoRef = extraUtils.getSingleReferencedAddress(typeinfoAddress);
|
||||||
if (specialTypeinfoRef == null) {
|
if (specialTypeinfoRef == null) {
|
||||||
|
@ -955,52 +958,371 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
Data newStructure = null;
|
||||||
// create a "no inheritance" struct here
|
|
||||||
if (specialTypeinfoRef.equals(class_type_info) ||
|
|
||||||
specialTypeinfoRef.equals(class_type_info_vtable)) {
|
|
||||||
api.clearListing(typeinfoAddress,
|
|
||||||
typeinfoAddress.add(classTypeInfoStructure.getLength()));
|
|
||||||
api.createData(typeinfoAddress, classTypeInfoStructure);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a "single inheritance" struct here
|
// create a "no inheritance" struct here
|
||||||
if (specialTypeinfoRef.equals(si_class_type_info) ||
|
if (specialTypeinfoRef.equals(class_type_info) ||
|
||||||
specialTypeinfoRef.equals(si_class_type_info_vtable)) {
|
specialTypeinfoRef.equals(class_type_info_vtable)) {
|
||||||
api.clearListing(typeinfoAddress,
|
|
||||||
typeinfoAddress.add(siClassTypeInfoStructure.getLength() - 1));
|
|
||||||
api.createData(typeinfoAddress, siClassTypeInfoStructure);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a "virtual multip inheritance" struct here
|
newStructure = applyTypeinfoStructure(classTypeInfoStructure, typeinfoAddress);
|
||||||
if (specialTypeinfoRef.equals(vmi_class_type_info) ||
|
}
|
||||||
specialTypeinfoRef.equals(vmi_class_type_info_vtable)) {
|
|
||||||
|
|
||||||
// get num base classes
|
// create a "single inheritance" struct here
|
||||||
int offsetOfNumBases = 2 * defaultPointerSize + 4;
|
else if (specialTypeinfoRef.equals(si_class_type_info) ||
|
||||||
int numBases = api.getInt(typeinfoAddress.add(offsetOfNumBases));
|
specialTypeinfoRef.equals(si_class_type_info_vtable)) {
|
||||||
|
|
||||||
// get or create the vmiClassTypeInfoStruct
|
newStructure = applyTypeinfoStructure(siClassTypeInfoStructure, typeinfoAddress);
|
||||||
Structure vmiClassTypeinfoStructure =
|
}
|
||||||
(Structure) dataTypeManager.getDataType(classDataTypesCategoryPath,
|
|
||||||
"VmiClassTypeInfoStructure" + numBases);
|
|
||||||
if (vmiClassTypeinfoStructure == null) {
|
|
||||||
vmiClassTypeinfoStructure =
|
|
||||||
createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases);
|
|
||||||
}
|
|
||||||
api.clearListing(typeinfoAddress,
|
|
||||||
typeinfoAddress.add(vmiClassTypeinfoStructure.getLength() - 1));
|
|
||||||
api.createData(typeinfoAddress, vmiClassTypeinfoStructure);
|
|
||||||
|
|
||||||
|
// create a "virtual multip inheritance" struct here
|
||||||
|
else if (specialTypeinfoRef.equals(vmi_class_type_info) ||
|
||||||
|
specialTypeinfoRef.equals(vmi_class_type_info_vtable)) {
|
||||||
|
|
||||||
|
Structure vmiClassTypeinfoStructure =
|
||||||
|
getOrCreateVmiTypeinfoStructure(typeinfoAddress, baseClassTypeInfoStructure);
|
||||||
|
if (vmiClassTypeinfoStructure != null) {
|
||||||
|
newStructure = applyTypeinfoStructure(vmiClassTypeinfoStructure, typeinfoAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
Msg.debug(this, "ERROR: Could not apply structure to " + typeinfoAddress);
|
if (newStructure == null) {
|
||||||
|
Msg.debug(this, "ERROR: Could not apply typeinfo structure to " + typeinfoAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for existing symbol and if none, demangle the name and apply
|
||||||
|
Symbol typeinfoSymbol = api.getSymbolAt(typeinfoAddress);
|
||||||
|
if (typeinfoSymbol == null) {
|
||||||
|
typeinfoSymbol = createDemangledTypeinfoSymbol(typeinfoAddress);
|
||||||
|
if (typeinfoSymbol == null) {
|
||||||
|
Msg.debug(this, "Could not create demangled typeinfo symbol at " +
|
||||||
|
typeinfoAddress.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeinfoSymbol != null && typeinfoSymbol.getName().equals("typeinfo")) {
|
||||||
|
promoteToClassNamespace(typeinfoSymbol.getParentNamespace());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Data applyTypeinfoStructure(Structure typeInfoStructure, Address typeinfoAddress)
|
||||||
|
throws CancelledException, AddressOutOfBoundsException {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return newStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Structure getOrCreateVmiTypeinfoStructure(Address typeinfoAddress,
|
||||||
|
StructureDataType baseClassTypeInfoStructure) {
|
||||||
|
|
||||||
|
// get num base classes
|
||||||
|
int offsetOfNumBases = 2 * defaultPointerSize + 4;
|
||||||
|
int numBases;
|
||||||
|
try {
|
||||||
|
numBases = api.getInt(typeinfoAddress.add(offsetOfNumBases));
|
||||||
|
}
|
||||||
|
catch (MemoryAccessException | AddressOutOfBoundsException e) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get or create the vmiClassTypeInfoStruct
|
||||||
|
Structure vmiClassTypeinfoStructure =
|
||||||
|
(Structure) dataTypeManager.getDataType(classDataTypesCategoryPath,
|
||||||
|
"VmiClassTypeInfoStructure" + numBases);
|
||||||
|
if (vmiClassTypeinfoStructure == null) {
|
||||||
|
vmiClassTypeinfoStructure =
|
||||||
|
createVmiClassTypeInfoStructure(baseClassTypeInfoStructure, numBases);
|
||||||
|
}
|
||||||
|
return vmiClassTypeinfoStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Symbol createDemangledTypeinfoSymbol(Address typeinfoAddress) {
|
||||||
|
|
||||||
|
String mangledTypeinfo = getTypeinfoName(typeinfoAddress);
|
||||||
|
if (mangledTypeinfo == null) {
|
||||||
|
Msg.debug(this, "Could not get typeinfo string from " + typeinfoAddress.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mangledTypeinfo.startsWith("*")) {
|
||||||
|
mangledTypeinfo = mangledTypeinfo.substring(1);
|
||||||
|
}
|
||||||
|
mangledTypeinfo = "_Z" + mangledTypeinfo;
|
||||||
|
|
||||||
|
DemanglerOptions options = new DemanglerOptions();
|
||||||
|
options.setDemangleOnlyKnownPatterns(false);
|
||||||
|
options.setApplySignature(false);
|
||||||
|
options.setDoDisassembly(false);
|
||||||
|
|
||||||
|
DemangledObject demangled = DemanglerUtil.demangle(mangledTypeinfo);
|
||||||
|
if (demangled == null) {
|
||||||
|
Msg.debug(this, "Could not demangle typeinfo string at " + typeinfoAddress.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String namespaceString = demangled.getNamespaceString();
|
||||||
|
|
||||||
|
Namespace classNamespace = createTypeinfoClassNamespace(namespaceString);
|
||||||
|
|
||||||
|
Msg.debug(this, typeinfoAddress.toString() + " " + namespaceString);
|
||||||
|
|
||||||
|
if (classNamespace == null) {
|
||||||
|
Msg.debug(this,
|
||||||
|
typeinfoAddress.toString() +
|
||||||
|
"Could not create a class namespace for demangled namespace string " +
|
||||||
|
namespaceString);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Namespace createTypeinfoClassNamespace(String namespaceString) {
|
||||||
|
|
||||||
|
int indexOfColons = namespaceString.indexOf("::");
|
||||||
|
Namespace namespace = globalNamespace;
|
||||||
|
while (indexOfColons != -1) {
|
||||||
|
String namespaceName = namespaceString.substring(0, indexOfColons);
|
||||||
|
Namespace newNamespace = getOrCreateNamespace(namespaceName, namespace);
|
||||||
|
if (newNamespace == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
namespace = newNamespace;
|
||||||
|
namespaceString = namespaceString.substring(indexOfColons + 2);
|
||||||
|
indexOfColons = namespaceString.indexOf("::");
|
||||||
|
}
|
||||||
|
// the substring after the last :: is the class namespace we want to return
|
||||||
|
Namespace classNamespace = getOrCreateNamespace(namespaceString, namespace);
|
||||||
|
if (classNamespace == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
|
||||||
|
classNamespace = promoteToClassNamespace(classNamespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return classNamespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Namespace getOrCreateNamespace(String namespaceName, Namespace parentNamespace) {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTypeinfoName(Address address) {
|
||||||
|
|
||||||
|
Data dataAt = api.getDataAt(address);
|
||||||
|
if (dataAt == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!(dataAt.getBaseDataType() instanceof Structure)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Structure typeinfoStructure = (Structure) dataAt.getBaseDataType();
|
||||||
|
if (!typeinfoStructure.getName().contains("ClassTypeInfoStructure")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DataTypeComponent typeinfoNameComponent = typeinfoStructure.getComponent(1);
|
||||||
|
DataType typeinfoNameDatatype = typeinfoNameComponent.getDataType();
|
||||||
|
if (!(typeinfoNameDatatype instanceof Pointer)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address stringReference =
|
||||||
|
extraUtils.getSingleReferencedAddress(address.add(typeinfoNameComponent.getOffset()));
|
||||||
|
|
||||||
|
Data stringData = api.getDataAt(stringReference);
|
||||||
|
if (stringData == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int stringLen = stringData.getLength();
|
||||||
|
MemBuffer buf = new DumbMemBufferImpl(program.getMemory(), stringReference);
|
||||||
|
|
||||||
|
StringDataType sdt = new StringDataType();
|
||||||
|
|
||||||
|
String str;
|
||||||
|
try {
|
||||||
|
str = (String) sdt.getValue(buf, sdt.getDefaultSettings(), stringLen);
|
||||||
|
}
|
||||||
|
catch (AddressOutOfBoundsException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get a list typeinfo addresses using symbols
|
||||||
|
* @return a list of non-special typeinfo addresses that have "typeinfo" symbols
|
||||||
|
* @throws CancelledException if cancelled
|
||||||
|
*/
|
||||||
|
private List<Address> getTypeinfoAddressesUsingSymbols() throws CancelledException {
|
||||||
|
|
||||||
|
List<Address> typeinfoAddresses = new ArrayList<Address>();
|
||||||
|
|
||||||
|
List<Symbol> typeinfoSymbols = extraUtils.getListOfSymbolsInAddressSet(
|
||||||
|
program.getAddressFactory().getAddressSet(), "typeinfo", true);
|
||||||
|
|
||||||
|
Iterator<Symbol> typeinfoIterator = typeinfoSymbols.iterator();
|
||||||
|
while (typeinfoIterator.hasNext()) {
|
||||||
|
|
||||||
|
monitor.checkCanceled();
|
||||||
|
|
||||||
|
Symbol typeinfoSymbol = typeinfoIterator.next();
|
||||||
|
Address typeinfoAddress = typeinfoSymbol.getAddress();
|
||||||
|
|
||||||
|
// skip the typeinfo symbols from the three special typeinfos
|
||||||
|
if (isSpecialTypeinfo(typeinfoAddress)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// check for EXTERNAL block and look for specialTypeinfoRef there
|
||||||
|
// if fix works, put external block error message and to contact us
|
||||||
|
if (hasExternalBlock() && isSpecialVtable(typeinfoAddress)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
typeinfoAddresses.add(typeinfoAddress);
|
||||||
|
}
|
||||||
|
return typeinfoAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get a list typeinfo addresses using relocation table info
|
||||||
|
* @return a list of typeinfo addresses
|
||||||
|
* @throws CancelledException if cancelled
|
||||||
|
*/
|
||||||
|
private List<Address> getTypeinfoAddressesUsingRelocationTable() throws CancelledException {
|
||||||
|
|
||||||
|
List<Address> typeinfoAddresses = new ArrayList<Address>();
|
||||||
|
|
||||||
|
Iterator<Bookmark> bookmarksIterator =
|
||||||
|
program.getBookmarkManager().getBookmarksIterator(BookmarkType.ERROR);
|
||||||
|
while (bookmarksIterator.hasNext()) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
Bookmark bookmark = bookmarksIterator.next();
|
||||||
|
if (bookmark.getCategory().equals("EXTERNAL Relocation") &&
|
||||||
|
bookmarkContainsSpecialTypeinfoName(bookmark.getComment())) {
|
||||||
|
typeinfoAddresses.add(bookmark.getAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeinfoAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean bookmarkContainsSpecialTypeinfoName(String bookmarkComment) {
|
||||||
|
|
||||||
|
if (bookmarkComment.contains("class_type_info")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bookmarkComment.contains("si_class_type_info")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (bookmarkComment.contains("vmi_class_type_info")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to check to see if there are any EXTERNAL block relocations
|
||||||
|
* @return true if there are any EXTERNAL block relocations in the program, false otherwise
|
||||||
|
* @throws CancelledException if cancelled
|
||||||
|
*/
|
||||||
|
private boolean hasExternalRelocationRefs() throws CancelledException {
|
||||||
|
// if no external block then there won't be any refernces to special typeinfos in the external
|
||||||
|
// block so return empty list
|
||||||
|
if (!hasExternalBlock()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Iterator<Bookmark> bookmarksIterator =
|
||||||
|
program.getBookmarkManager().getBookmarksIterator(BookmarkType.ERROR);
|
||||||
|
while (bookmarksIterator.hasNext()) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
Bookmark bookmark = bookmarksIterator.next();
|
||||||
|
if (bookmark.getCategory().equals("EXTERNAL Relocation")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
return specialTypeinfoRefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDwarfLoaded() {
|
||||||
|
Options options = program.getOptions("Program Information");
|
||||||
|
boolean isDwarfLoaded = false;
|
||||||
|
Object isPDBLoadedObject = options.getObject("DWARF Loaded", null);
|
||||||
|
if (isPDBLoadedObject != null) {
|
||||||
|
isDwarfLoaded = (boolean) isPDBLoadedObject;
|
||||||
|
}
|
||||||
|
return isDwarfLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructureDataType createClassTypeInfoStructure() {
|
private StructureDataType createClassTypeInfoStructure() {
|
||||||
|
@ -1136,7 +1458,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
Msg.debug(this, "couldn't get int at address " + inheritanceFlagAddress.toString());
|
Msg.debug(this, "couldn't get int at address " + inheritanceFlagAddress.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int baseClassArrayOffset = defaultPointerSize * 3;
|
int baseClassArrayOffset = defaultPointerSize * 3;
|
||||||
Data baseClassArrayData = typeinfoStructure.getComponentAt(baseClassArrayOffset);
|
Data baseClassArrayData = typeinfoStructure.getComponentAt(baseClassArrayOffset);
|
||||||
|
|
||||||
|
@ -1155,9 +1476,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
for (int i = 0; i < numParents; i++) {
|
for (int i = 0; i < numParents; i++) {
|
||||||
// get parent from pointer to parent typeinfo
|
// get parent from pointer to parent typeinfo
|
||||||
Address parentRefAddress =
|
Address parentRefAddress = extraUtils.getAddress(typeinfoAddress,
|
||||||
extraUtils.getAddress(typeinfoAddress,
|
baseClassArrayOffset + (i * 2 * defaultPointerSize));
|
||||||
baseClassArrayOffset + (i * 2 * defaultPointerSize));
|
|
||||||
if (parentRefAddress == null) {
|
if (parentRefAddress == null) {
|
||||||
Msg.debug(this, "Could not access address " + typeinfoAddress.toString() +
|
Msg.debug(this, "Could not access address " + typeinfoAddress.toString() +
|
||||||
" plus offset " + baseClassArrayOffset);
|
" plus offset " + baseClassArrayOffset);
|
||||||
|
@ -1461,7 +1781,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
// previously
|
// previously
|
||||||
RecoveredClass classWithNoTypeinfoStruct = getClass(vtableNamespace);
|
RecoveredClass classWithNoTypeinfoStruct = getClass(vtableNamespace);
|
||||||
if (classWithNoTypeinfoStruct == null) {
|
if (classWithNoTypeinfoStruct == null) {
|
||||||
addNoVftableClass(vtableNamespace);
|
createNewClass(vtableNamespace, false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,7 +1803,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
Address vftableAddress = extraUtils.getAddress(typeinfoAddress, defaultPointerSize);
|
Address vftableAddress = extraUtils.getAddress(typeinfoAddress, defaultPointerSize);
|
||||||
// no valid address here so continue
|
// no valid address here so continue
|
||||||
if (vftableAddress == null) {
|
if (vftableAddress == null) {
|
||||||
addNoVftableClass(vtableNamespace);
|
createNewClass(vtableNamespace, false);
|
||||||
// if so should also add to no vftable class
|
// if so should also add to no vftable class
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1513,8 +1833,7 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSpecialVtable(Address address) {
|
private boolean isSpecialVtable(Address address) {
|
||||||
if (address.equals(class_type_info_vtable) ||
|
if (address.equals(class_type_info_vtable) || address.equals(si_class_type_info_vtable) ||
|
||||||
address.equals(si_class_type_info_vtable) ||
|
|
||||||
address.equals(vmi_class_type_info_vtable)) {
|
address.equals(vmi_class_type_info_vtable)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1546,15 +1865,13 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
// TODO: make sure it is a valid typeinfo
|
// TODO: make sure it is a valid typeinfo
|
||||||
|
|
||||||
|
|
||||||
Namespace classNamespace = typeinfoSymbol.getParentNamespace();
|
Namespace classNamespace = typeinfoSymbol.getParentNamespace();
|
||||||
|
|
||||||
RecoveredClass recoveredClass = getClass(classNamespace);
|
RecoveredClass recoveredClass = getClass(classNamespace);
|
||||||
|
|
||||||
|
|
||||||
// we don't know yet if this class has vftable so just add without for now
|
// we don't know yet if this class has vftable so just add without for now
|
||||||
if (recoveredClass == null) {
|
if (recoveredClass == null) {
|
||||||
recoveredClass = addNoVftableClass(classNamespace);
|
recoveredClass = createNewClass(classNamespace, false);
|
||||||
recoveredClasses.add(recoveredClass);
|
recoveredClasses.add(recoveredClass);
|
||||||
|
|
||||||
classToTypeinfoMap.put(recoveredClass, typeinfoAddress);
|
classToTypeinfoMap.put(recoveredClass, typeinfoAddress);
|
||||||
|
@ -1592,7 +1909,6 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// per docs those on this list
|
// per docs those on this list
|
||||||
// have no bases (ie parents), and is also a base type for the other two class type
|
// have no bases (ie parents), and is also a base type for the other two class type
|
||||||
// representations ie (si and vmi)
|
// representations ie (si and vmi)
|
||||||
|
@ -2113,4 +2429,3 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ import ghidra.program.model.pcode.HighFunction;
|
||||||
import ghidra.program.model.pcode.HighVariable;
|
import ghidra.program.model.pcode.HighVariable;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
@ -937,10 +938,13 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace();
|
Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace();
|
||||||
|
|
||||||
if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
|
if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
|
||||||
// println("RTTI_Class_Hierarchy_Descriptor at " +
|
classNamespace = promoteToClassNamespace(classNamespace);
|
||||||
// classHierarchyDescriptorAddress.toString() +
|
if(classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
|
||||||
// " is not in a class namespace. Cannot process.");
|
Msg.debug(this,
|
||||||
continue;
|
classHierarchyDescriptorAddress.toString() + " Could not promote " +
|
||||||
|
classNamespace.getName(true) + " to a class namespace.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Symbol> vftableSymbolsInNamespace =
|
List<Symbol> vftableSymbolsInNamespace =
|
||||||
|
@ -975,12 +979,12 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
List<RecoveredClass> classesWithVftablesInNamespace =
|
List<RecoveredClass> classesWithVftablesInNamespace =
|
||||||
recoverClassesFromVftables(vftableSymbolsInNamespace, false, false);
|
recoverClassesFromVftables(vftableSymbolsInNamespace, false, false);
|
||||||
if (classesWithVftablesInNamespace.size() == 0) {
|
if (classesWithVftablesInNamespace.size() == 0) {
|
||||||
//println("No class recovered for namespace " + classNamespace.getName());
|
Msg.debug(this,"No class recovered for namespace " + classNamespace.getName());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (classesWithVftablesInNamespace.size() > 1) {
|
if (classesWithVftablesInNamespace.size() > 1) {
|
||||||
// println("Unexpected multiple classes recovered for namespace " +
|
Msg.debug(this,"Unexpected multiple classes recovered for namespace " +
|
||||||
// classNamespace.getName());
|
classNamespace.getName());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1232,7 +1236,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
// if the namespace isn't in the map then it is a class
|
// if the namespace isn't in the map then it is a class
|
||||||
// without a vftable and a new RecoveredClass object needs to be created
|
// without a vftable and a new RecoveredClass object needs to be created
|
||||||
if (getClass(pointedToNamespace) == null) {
|
if (getClass(pointedToNamespace) == null) {
|
||||||
addNoVftableClass(pointedToNamespace);
|
createNewClass(pointedToNamespace, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RecoveredClass pointedToClass = getClass(pointedToNamespace);
|
RecoveredClass pointedToClass = getClass(pointedToNamespace);
|
||||||
|
|
|
@ -2672,26 +2672,29 @@ public class RecoveredClassUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to add class with no vftable to the namespace map
|
* Method to create a new recovered class object and add it to the namespaceToClassMap
|
||||||
* @param namespace the namespace to put the new class in
|
* @param namespace the namespace to put the new class in
|
||||||
* @return the recovered class\
|
* @param hasVftable true if class has at least one vftable, false otherwise
|
||||||
|
* @return the RecoveredClass object
|
||||||
* @throws CancelledException if cancelled
|
* @throws CancelledException if cancelled
|
||||||
*/
|
*/
|
||||||
public RecoveredClass addNoVftableClass(Namespace namespace) throws CancelledException {
|
public RecoveredClass createNewClass(Namespace namespace, boolean hasVftable)
|
||||||
|
throws CancelledException {
|
||||||
|
|
||||||
String className = namespace.getName();
|
String className = namespace.getName();
|
||||||
String classNameWithNamespace = namespace.getName(true);
|
String classNameWithNamespace = namespace.getName(true);
|
||||||
CategoryPath classPath =
|
|
||||||
extraUtils.createDataTypeCategoryPath(classDataTypesCategoryPath,
|
|
||||||
classNameWithNamespace);
|
|
||||||
|
|
||||||
RecoveredClass nonVftableClass =
|
CategoryPath classPath = extraUtils.createDataTypeCategoryPath(classDataTypesCategoryPath,
|
||||||
|
classNameWithNamespace);
|
||||||
|
|
||||||
|
RecoveredClass newClass =
|
||||||
new RecoveredClass(className, classPath, namespace, dataTypeManager);
|
new RecoveredClass(className, classPath, namespace, dataTypeManager);
|
||||||
nonVftableClass.setHasVftable(false);
|
newClass.setHasVftable(hasVftable);
|
||||||
|
|
||||||
updateNamespaceToClassMap(namespace, nonVftableClass);
|
updateNamespaceToClassMap(namespace, newClass);
|
||||||
return nonVftableClass;
|
return newClass;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2736,23 +2739,6 @@ public class RecoveredClassUtils {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// promote any non-class namespaces in the vftableNamespace path to class namespaces
|
|
||||||
boolean success = promoteNamespaces(vftableNamespace.getSymbol());
|
|
||||||
if (!success) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Msg.debug(this, "Unable to promote all non-class namespaces for " +
|
|
||||||
vftableNamespace.getName(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String className = vftableNamespace.getName();
|
|
||||||
String classNameWithNamespace = vftableNamespace.getName(true);
|
|
||||||
|
|
||||||
// Create Data Type Manager Category for given class
|
|
||||||
CategoryPath classPath =
|
|
||||||
extraUtils.createDataTypeCategoryPath(classDataTypesCategoryPath,
|
|
||||||
classNameWithNamespace);
|
|
||||||
|
|
||||||
// get only the functions from the ones that are not already processed structures
|
// get only the functions from the ones that are not already processed structures
|
||||||
// return null if not an unprocessed table
|
// return null if not an unprocessed table
|
||||||
List<Function> virtualFunctions = getFunctionsFromVftable(vftableAddress, vftableSymbol,
|
List<Function> virtualFunctions = getFunctionsFromVftable(vftableAddress, vftableSymbol,
|
||||||
|
@ -2764,24 +2750,24 @@ public class RecoveredClassUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if already have an existing RecoveredClass object for the
|
// Check to see if already have an existing RecoveredClass object for the
|
||||||
// class associated with the current vftable. If so, it indicates multi-inheritance
|
// class associated with the current vftable.
|
||||||
RecoveredClass recoveredClass = getClass(vftableNamespace);
|
RecoveredClass recoveredClass = getClass(vftableNamespace);
|
||||||
|
|
||||||
if (recoveredClass == null) {
|
if (recoveredClass == null) {
|
||||||
// Create a RecoveredClass object for the current class
|
// Create a RecoveredClass object for the current class
|
||||||
recoveredClass =
|
recoveredClass = createNewClass(vftableNamespace, true);
|
||||||
new RecoveredClass(className, classPath, vftableNamespace, dataTypeManager);
|
|
||||||
recoveredClass.addVftableAddress(vftableAddress);
|
recoveredClass.addVftableAddress(vftableAddress);
|
||||||
recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions);
|
recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions);
|
||||||
|
|
||||||
// add recovered class to map
|
|
||||||
updateNamespaceToClassMap(vftableNamespace, recoveredClass);
|
|
||||||
// add it to the running list of RecoveredClass objects
|
// add it to the running list of RecoveredClass objects
|
||||||
recoveredClasses.add(recoveredClass);
|
recoveredClasses.add(recoveredClass);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
recoveredClass.addVftableAddress(vftableAddress);
|
recoveredClass.addVftableAddress(vftableAddress);
|
||||||
recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions);
|
recoveredClass.addVftableVfunctionsMapping(vftableAddress, virtualFunctions);
|
||||||
|
if (!recoveredClasses.contains(recoveredClass)) {
|
||||||
|
recoveredClasses.add(recoveredClass);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2795,8 +2781,6 @@ public class RecoveredClassUtils {
|
||||||
Map<Address, Function> vftableReferenceToFunctionMapping =
|
Map<Address, Function> vftableReferenceToFunctionMapping =
|
||||||
createVftableReferenceToFunctionMapping(referencesToVftable);
|
createVftableReferenceToFunctionMapping(referencesToVftable);
|
||||||
|
|
||||||
// add this smaller mapping set to the global map
|
|
||||||
//vftableRefToFunctionMap.putAll(vftableReferenceToFunctionMapping);
|
|
||||||
|
|
||||||
//vftableReferenceToFunctionMapping
|
//vftableReferenceToFunctionMapping
|
||||||
List<Function> possibleConstructorDestructorsForThisClass =
|
List<Function> possibleConstructorDestructorsForThisClass =
|
||||||
|
@ -2819,25 +2803,38 @@ public class RecoveredClassUtils {
|
||||||
return recoveredClasses;
|
return recoveredClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean promoteNamespaces(Symbol symbol) throws CancelledException {
|
public void promoteClassNamespaces(List<RecoveredClass> recoveredClasses)
|
||||||
|
throws CancelledException {
|
||||||
|
|
||||||
|
Iterator<RecoveredClass> classIterator = recoveredClasses.iterator();
|
||||||
|
while (classIterator.hasNext()) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
|
||||||
|
RecoveredClass recoveredClass = classIterator.next();
|
||||||
|
Namespace classNamespace = recoveredClass.getClassNamespace();
|
||||||
|
promoteNamespaces(classNamespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean promoteNamespaces(Namespace namespace) throws CancelledException {
|
||||||
|
|
||||||
Namespace namespace = symbol.getParentNamespace();
|
|
||||||
while (!namespace.isGlobal()) {
|
while (!namespace.isGlobal()) {
|
||||||
|
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
SymbolType namespaceType = namespace.getSymbol().getSymbolType();
|
SymbolType namespaceType = namespace.getSymbol().getSymbolType();
|
||||||
if (namespaceType != SymbolType.CLASS) {
|
// if it is a namespace but not a class and it is in our namespace map (which makes
|
||||||
// if it is a namespace but not a class we need to promote it to a class namespace
|
// it a valid class) we need to promote it to a class namespace
|
||||||
if (namespaceType == SymbolType.NAMESPACE) {
|
if (namespaceType != SymbolType.CLASS && namespaceType == SymbolType.NAMESPACE &&
|
||||||
namespace = promoteToClassNamespace(namespace);
|
namespaceToClassMap.get(namespace) != null) {
|
||||||
if (namespace == null) {
|
|
||||||
return false;
|
namespace = promoteToClassNamespace(namespace);
|
||||||
}
|
if (namespace == null) {
|
||||||
if (DEBUG) {
|
return false;
|
||||||
Msg.debug(this,
|
|
||||||
"Promoted namespace " + namespace.getName() + " to a class namespace");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//if (DEBUG) {
|
||||||
|
Msg.debug(this,
|
||||||
|
"Promoted namespace " + namespace.getName(true) + " to a class namespace");
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
namespace = namespace.getParentNamespace();
|
namespace = namespace.getParentNamespace();
|
||||||
|
@ -2852,11 +2849,20 @@ public class RecoveredClassUtils {
|
||||||
*/
|
*/
|
||||||
private Namespace promoteToClassNamespace(Namespace namespace) {
|
private Namespace promoteToClassNamespace(Namespace namespace) {
|
||||||
|
|
||||||
|
SymbolType symbolType = namespace.getSymbol().getSymbolType();
|
||||||
|
if (symbolType == SymbolType.CLASS) {
|
||||||
|
return namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbolType != SymbolType.NAMESPACE) {
|
||||||
|
return namespace;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
Namespace newClass = NamespaceUtils.convertNamespaceToClass(namespace);
|
||||||
|
|
||||||
SymbolType symbolType = newClass.getSymbol().getSymbolType();
|
SymbolType newSymbolType = newClass.getSymbol().getSymbolType();
|
||||||
if (symbolType == SymbolType.CLASS) {
|
if (newSymbolType == SymbolType.CLASS) {
|
||||||
return newClass;
|
return newClass;
|
||||||
}
|
}
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -3246,7 +3252,8 @@ public class RecoveredClassUtils {
|
||||||
|
|
||||||
if (parentClasses.isEmpty()) {
|
if (parentClasses.isEmpty()) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
recoveredClass.getName() + " should not have an empty class hierarchy");
|
recoveredClass.getClassNamespace().getName(true) +
|
||||||
|
" should not have an empty class hierarchy");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if size one it only includes self
|
// if size one it only includes self
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue