mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-14 14:40:13 +00:00
Merge remote-tracking branch 'origin/GP-1962_ghidra007_better_check_for_existing_classes_SQUASHED'
This commit is contained in:
commit
864321a060
@ -326,6 +326,12 @@ public class RecoverClassesFromRTTIScript extends GhidraScript {
|
||||
return ("There is no open program");
|
||||
}
|
||||
|
||||
CategoryPath path =
|
||||
new CategoryPath(CategoryPath.ROOT, RecoveredClassHelper.DTM_CLASS_DATA_FOLDER_NAME);
|
||||
if (currentProgram.getDataTypeManager().containsCategory(path)) {
|
||||
return ("This script has already been run on this program");
|
||||
}
|
||||
|
||||
if (!checkGhidraVersion()) {
|
||||
return ("This script only works with Ghidra version 9.2, 9.2.2 and later. It does not work on Ghidra 9.2.1 or on versions prior to 9.2");
|
||||
}
|
||||
|
@ -1031,72 +1031,22 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create data type manager path that will be used when data types are created to place them in the correct folder
|
||||
* @param parent parent CategoryPath
|
||||
* @param categoryName name of the new category in the parent path
|
||||
* Create data type manager path combining the given parent category path and namespace
|
||||
* @param parent the given parent CategoryPath
|
||||
* @param namespace the given namespace
|
||||
* @return CategoryPath for new categoryName
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public CategoryPath createDataTypeCategoryPath(CategoryPath parent, String categoryName) throws CancelledException {
|
||||
public CategoryPath createDataTypeCategoryPath(CategoryPath parent, Namespace namespace)
|
||||
throws CancelledException {
|
||||
|
||||
CategoryPath dataTypePath;
|
||||
CategoryPath dataTypePath = parent;
|
||||
|
||||
// if single namespace no parsing necessary, just create using given categoryName
|
||||
if (!categoryName.contains("::")) {
|
||||
dataTypePath = new CategoryPath(parent, categoryName);
|
||||
return dataTypePath;
|
||||
for (String name : namespace.getPathList(true)) {
|
||||
monitor.checkCanceled();
|
||||
|
||||
dataTypePath = new CategoryPath(dataTypePath, name);
|
||||
}
|
||||
|
||||
// if category name contains :: but not valid template info then just
|
||||
// replace ::'s with /'s to form multi level path
|
||||
if (!containsTemplate(categoryName)) {
|
||||
categoryName = categoryName.replace("::", "/");
|
||||
}
|
||||
|
||||
// if category name contains both :: and matched template brackets then only replace the
|
||||
// :: that are not contained inside template brackets
|
||||
else {
|
||||
boolean insideBrackets = false;
|
||||
int numOpenedBrackets = 0;
|
||||
int index = 0;
|
||||
String newCategoryName = new String();
|
||||
while (index < categoryName.length()) {
|
||||
monitor.checkCanceled();
|
||||
|
||||
if (categoryName.substring(index).startsWith("::") && !insideBrackets) {
|
||||
newCategoryName = newCategoryName.concat("/");
|
||||
index += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
String character = categoryName.substring(index, index + 1);
|
||||
|
||||
newCategoryName = newCategoryName.concat(character);
|
||||
index++;
|
||||
|
||||
if (character.equals("<")) {
|
||||
insideBrackets = true;
|
||||
numOpenedBrackets++;
|
||||
}
|
||||
if (character.equals(">")) {
|
||||
numOpenedBrackets--;
|
||||
}
|
||||
if (numOpenedBrackets == 0) {
|
||||
insideBrackets = false;
|
||||
}
|
||||
}
|
||||
categoryName = newCategoryName;
|
||||
}
|
||||
|
||||
String path;
|
||||
if (parent.getName().equals("")) {
|
||||
path = "/" + categoryName;
|
||||
}
|
||||
else {
|
||||
path = "/" + parent.getName() + "/" + categoryName;
|
||||
}
|
||||
dataTypePath = new CategoryPath(path);
|
||||
|
||||
return dataTypePath;
|
||||
|
||||
}
|
||||
|
@ -112,6 +112,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||
Msg.debug(this, "Could not recover gcc rtti classes");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (recoveredClasses.isEmpty()) {
|
||||
return recoveredClasses;
|
||||
}
|
||||
|
||||
createCalledFunctionMap(recoveredClasses);
|
||||
|
||||
@ -781,6 +785,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This has to be "contains" to get all types of class structures some begin and end
|
||||
// with other things
|
||||
Structure structure = (Structure) baseDataType;
|
||||
if (structure.getName().contains(CLASS_TYPE_INFO_STRUCTURE)) {
|
||||
return true;
|
||||
@ -1403,9 +1409,17 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||
if (typeinfoAddresses.isEmpty()) {
|
||||
return typeinfoAddresses;
|
||||
}
|
||||
|
||||
List<Address> typeinfoAddressesToProcess = new ArrayList<Address>();
|
||||
|
||||
for (Address typeinfoAddress : typeinfoAddresses) {
|
||||
|
||||
monitor.checkCanceled();
|
||||
|
||||
if (hasExistingTypeinfoStructure(typeinfoAddress)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Address specialTypeinfoRef =
|
||||
extendedFlatAPI.getSingleReferencedAddress(typeinfoAddress);
|
||||
if (specialTypeinfoRef == null) {
|
||||
@ -1457,6 +1471,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||
throw new Exception(
|
||||
"ERROR: Could not apply typeinfo structure to " + typeinfoAddress);
|
||||
}
|
||||
|
||||
typeinfoAddressesToProcess.add(typeinfoAddress);
|
||||
|
||||
// check for existing symbol and if none, demangle the name and apply
|
||||
Symbol typeinfoSymbol = api.getSymbolAt(typeinfoAddress);
|
||||
@ -1474,7 +1490,40 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||
}
|
||||
|
||||
}
|
||||
return typeinfoAddresses;
|
||||
return typeinfoAddressesToProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to determine if the given address has one of the ClassTypeinfoDataType types applied
|
||||
* @param address the given address
|
||||
* @return true if already has a class data type applied or false if not
|
||||
*/
|
||||
private boolean hasExistingTypeinfoStructure(Address address) {
|
||||
|
||||
|
||||
Data dataAt = api.getDataAt(address);
|
||||
|
||||
if (dataAt == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataType dataType = dataAt.getDataType();
|
||||
|
||||
if (!(dataType instanceof Structure)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This has to be "contains" to get all types of class structures some begin and end
|
||||
// with other things
|
||||
if (!dataType.getName().contains(CLASS_TYPE_INFO_STRUCTURE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dataType.getPathName().startsWith(DTM_CLASS_DATA_FOLDER_PATH)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private Data applyTypeinfoStructure(Structure typeInfoStructure, Address typeinfoAddress)
|
||||
|
@ -885,6 +885,14 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||
// Get class name from class vftable is in
|
||||
Namespace classNamespace = classHierarchyDescriptorSymbol.getParentNamespace();
|
||||
|
||||
// get the data type category associated with the given class namespace
|
||||
Category category = getDataTypeCategory(classNamespace);
|
||||
|
||||
// if it already exists, continue since this class has already been recovered
|
||||
if (category != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
|
||||
classNamespace = promoteToClassNamespace(classNamespace);
|
||||
if (classNamespace.getSymbol().getSymbolType() != SymbolType.CLASS) {
|
||||
@ -901,13 +909,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||
// non-vftable class
|
||||
if (vftableSymbolsInNamespace.size() == 0) {
|
||||
String className = classNamespace.getName();
|
||||
String classNameWithNamespace = classNamespace.getName(true);
|
||||
|
||||
// Create Data Type Manager Category for given class
|
||||
// TODO: make this global and check it for null
|
||||
CategoryPath classPath =
|
||||
extendedFlatAPI.createDataTypeCategoryPath(classDataTypesCategoryPath,
|
||||
classNameWithNamespace);
|
||||
// Make a CategoryPath for given class
|
||||
CategoryPath classPath = extendedFlatAPI
|
||||
.createDataTypeCategoryPath(classDataTypesCategoryPath, classNamespace);
|
||||
|
||||
RecoveredClass nonVftableClass =
|
||||
new RecoveredClass(className, classPath, classNamespace, dataTypeManager);
|
||||
@ -1009,12 +1014,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||
* Method to figure out the class hierarchies either with RTTI if it is present or with vftable
|
||||
* references
|
||||
* @param recoveredClasses List of classes to process
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws AddressOutOfBoundsException AddressOutOfBoundsException
|
||||
* @throws MemoryAccessException if memory cannot be read
|
||||
* @throws Exception various exceptions
|
||||
*/
|
||||
private void assignClassInheritanceAndHierarchies(List<RecoveredClass> recoveredClasses)
|
||||
throws CancelledException, MemoryAccessException, AddressOutOfBoundsException {
|
||||
throws Exception {
|
||||
|
||||
// Use RTTI information to determine inheritance type and
|
||||
// class hierarchy
|
||||
|
@ -51,6 +51,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
public class RecoveredClassHelper {
|
||||
|
||||
public static final String DTM_CLASS_DATA_FOLDER_NAME = "ClassDataTypes";
|
||||
public static final String DTM_CLASS_DATA_FOLDER_PATH = "/" + DTM_CLASS_DATA_FOLDER_NAME + "/";
|
||||
private static final String CLASS_DATA_STRUCT_NAME = "_data";
|
||||
private static final String DEFAULT_VFUNCTION_PREFIX = "vfunction";
|
||||
private static final String VFUNCTION_COMMENT = "virtual function #";
|
||||
@ -158,9 +159,9 @@ public class RecoveredClassHelper {
|
||||
|
||||
extendedFlatAPI = new ExtendedFlatProgramAPI(program, monitor);
|
||||
|
||||
this.classDataTypesCategoryPath = extendedFlatAPI
|
||||
.createDataTypeCategoryPath(CategoryPath.ROOT, DTM_CLASS_DATA_FOLDER_NAME);
|
||||
CategoryPath path = new CategoryPath(CategoryPath.ROOT, DTM_CLASS_DATA_FOLDER_NAME);
|
||||
|
||||
this.classDataTypesCategoryPath = path;
|
||||
this.createBookmarks = createBookmarks;
|
||||
this.useShortTemplates = useShortTemplates;
|
||||
this.nameVfunctions = nameVunctions;
|
||||
@ -2637,10 +2638,9 @@ public class RecoveredClassHelper {
|
||||
throws CancelledException {
|
||||
|
||||
String className = namespace.getName();
|
||||
String classNameWithNamespace = namespace.getName(true);
|
||||
|
||||
CategoryPath classPath = extendedFlatAPI
|
||||
.createDataTypeCategoryPath(classDataTypesCategoryPath, classNameWithNamespace);
|
||||
.createDataTypeCategoryPath(classDataTypesCategoryPath, namespace);
|
||||
|
||||
RecoveredClass newClass =
|
||||
new RecoveredClass(className, classPath, namespace, dataTypeManager);
|
||||
@ -7287,7 +7287,7 @@ public class RecoveredClassHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!category.getCategoryPath().getPath().contains(DTM_CLASS_DATA_FOLDER_NAME)) {
|
||||
if (!category.getCategoryPath().getPath().startsWith(DTM_CLASS_DATA_FOLDER_PATH)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -7705,7 +7705,6 @@ public class RecoveredClassHelper {
|
||||
|
||||
// get the corresponding existing pointer for this function definition from the dtManager
|
||||
Pointer pointer = getPointerDataType(functionDefinition);
|
||||
|
||||
if (pointer == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot find existing pointer data type for " + functionDefinition.getName());
|
||||
@ -7730,6 +7729,11 @@ public class RecoveredClassHelper {
|
||||
// get class namespace using the vftable structure
|
||||
Namespace vfunctionStructureNamespace = getClassNamespace(vftableStructure);
|
||||
|
||||
//skip if not in the class data type folder so cannot get corresponding namespace
|
||||
if (vfunctionStructureNamespace == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Data vftableData =
|
||||
getVftableStructureFromListing(vfunctionStructureNamespace, vftableStructure);
|
||||
|
||||
@ -7803,32 +7807,16 @@ public class RecoveredClassHelper {
|
||||
* the given data type. This is getting an existing pointer not trying to create a new one.
|
||||
* @param dataType the given data type
|
||||
* @return the existing pointer data type to the given data type in the same class dt folder
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private Pointer getPointerDataType(DataType dataType) throws CancelledException {
|
||||
private Pointer getPointerDataType(DataType dataType) {
|
||||
|
||||
CategoryPath classPath = dataType.getCategoryPath();
|
||||
Category category = dataTypeManager.getCategory(dataType.getCategoryPath());
|
||||
|
||||
Category category = dataTypeManager.getCategory(classPath);
|
||||
DataType pointer = new PointerDataType(dataType, dataTypeManager);
|
||||
|
||||
DataType[] classDataTypes = category.getDataTypes();
|
||||
for (DataType classDataType : classDataTypes) {
|
||||
DataType dt = category.getDataType(pointer.getName());
|
||||
|
||||
monitor.checkCanceled();
|
||||
|
||||
if (!(classDataType instanceof Pointer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Pointer pointer = (Pointer) classDataType;
|
||||
|
||||
DataType pointedToDataType = pointer.getDataType();
|
||||
|
||||
if (pointedToDataType.equals(dataType)) {
|
||||
return pointer;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return (dt instanceof Pointer) ? (Pointer) dt : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7871,14 +7859,15 @@ public class RecoveredClassHelper {
|
||||
public List<FunctionDefinition> getClassFunctionDefinitions(Namespace classNamespace)
|
||||
throws CancelledException {
|
||||
|
||||
CategoryPath classPath = getClassDataFolder(classNamespace);
|
||||
|
||||
Category category = dataTypeManager.getCategory(classPath);
|
||||
// get the data type category associated with the given class namespace
|
||||
Category category = getDataTypeCategory(classNamespace);
|
||||
|
||||
// return null if there isn't one
|
||||
if (category == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the function definitions in the given data type category and add them to the list
|
||||
List<FunctionDefinition> functionDefs = new ArrayList<FunctionDefinition>();
|
||||
|
||||
DataType[] classDataTypes = category.getDataTypes();
|
||||
@ -7896,22 +7885,30 @@ public class RecoveredClassHelper {
|
||||
return functionDefs;
|
||||
}
|
||||
|
||||
private CategoryPath getClassDataFolder(Namespace classNamespace) throws CancelledException {
|
||||
/**
|
||||
* Get the associated data type category for the given class namespace
|
||||
* @param classNamespace the given class namespace
|
||||
* @return the associated data type category or null if it doesn't exist
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public Category getDataTypeCategory(Namespace classNamespace) throws CancelledException {
|
||||
|
||||
String classNameWithNamespace = classNamespace.getName(true);
|
||||
// Make a CategoryPath for the given namespace
|
||||
CategoryPath classPath =
|
||||
extendedFlatAPI.createDataTypeCategoryPath(classDataTypesCategoryPath, classNamespace);
|
||||
|
||||
// Create Data Type Manager Category for given class
|
||||
CategoryPath classPath = extendedFlatAPI
|
||||
.createDataTypeCategoryPath(classDataTypesCategoryPath, classNameWithNamespace);
|
||||
|
||||
return classPath;
|
||||
// check to see if it exists in the data type manager and return it (it will return null
|
||||
// if it is not in the dtman
|
||||
Category category = dataTypeManager.getCategory(classPath);
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the class Namespace corresponding to the given data type. NOTE: The data type
|
||||
* must be in the DTM_CLASS_DATA_FOLDER_NAME folder in the data type manager.
|
||||
* @param dataType the given data type
|
||||
* @return the class Namespace corresponding to the given data type
|
||||
* @return the class Namespace corresponding to the given data type or null if the data type
|
||||
* is not in the DTM_CLASS_DATA_FOLDER_NAME folder or if class doesn't exist
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public Namespace getClassNamespace(DataType dataType) throws CancelledException {
|
||||
@ -7922,32 +7919,29 @@ public class RecoveredClassHelper {
|
||||
|
||||
CategoryPath categoryPath = dataType.getCategoryPath();
|
||||
|
||||
String className = categoryPath.getName();
|
||||
|
||||
String path = categoryPath.getPath();
|
||||
|
||||
if (!path.contains(DTM_CLASS_DATA_FOLDER_NAME)) {
|
||||
throw new IllegalArgumentException("DataType must be in the " +
|
||||
DTM_CLASS_DATA_FOLDER_NAME + " data type manager folder");
|
||||
if (!path.startsWith(DTM_CLASS_DATA_FOLDER_PATH)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
path = path.replace("/" + DTM_CLASS_DATA_FOLDER_NAME + "/", "");
|
||||
// strip off the leading class folder path and replace /'s with ::'s to get
|
||||
// class namespace path
|
||||
path = path.substring(DTM_CLASS_DATA_FOLDER_PATH.length());
|
||||
// TODO: update with regex to exclude very unlikely \/ case
|
||||
path = path.replace("/", "::");
|
||||
|
||||
Iterator<GhidraClass> classNamespaces = program.getSymbolTable().getClassNamespaces();
|
||||
List<Namespace> namespaceByPath =
|
||||
NamespaceUtils.getNamespaceByPath(program, null, path);
|
||||
|
||||
while (classNamespaces.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
Namespace namespace = classNamespaces.next();
|
||||
if (!namespace.getName().equals(className)) {
|
||||
continue;
|
||||
}
|
||||
String fullName = namespace.getName(true);
|
||||
if (fullName.equals(path)) {
|
||||
// ignore namespaces contained within libraries
|
||||
for (Namespace namespace : namespaceByPath) {
|
||||
if (!namespace.isExternal()) {
|
||||
return namespace;
|
||||
}
|
||||
}
|
||||
|
||||
Msg.debug(this, "Expected clas namespace not found: " + path);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user