GP-1703 Updated RTTI analyzer to create correctly formed TypeDescriptor symbols in correct class namespace and to apply own symbols as primary to prevent pdb symbols from being created with tick marks. Also fixes double label issue in GP-854.

This commit is contained in:
ghidra007
2022-02-25 18:20:51 +00:00
parent 15234dfea6
commit 7d34668633
3 changed files with 65 additions and 40 deletions

View File

@@ -15,12 +15,15 @@
*/
package ghidra.app.cmd.data;
import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.app.util.datatype.microsoft.DataApplyOptions;
import ghidra.app.util.datatype.microsoft.DataValidationOptions;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
@@ -90,8 +93,8 @@ public class CreateTypeDescriptorBackgroundCmd
* be applied as a sized character array immediately following the structure whose size does not include
* the char array bytes.
* @return false if the data type was not created because it already exists, true otherwise
* @throws CodeUnitInsertionException
* @throws CancelledException
* @throws CodeUnitInsertionException if creating data throws exception
* @throws CancelledException if cancelled
*/
@Override
protected boolean createData() throws CodeUnitInsertionException, CancelledException {
@@ -142,7 +145,26 @@ public class CreateTypeDescriptorBackgroundCmd
monitor.checkCanceled();
// Label
EHDataTypeUtilities.createSymbolIfNeeded(program, prefix, RTTI_0_NAME, null,
Namespace classNamespace = model.getDescriptorAsNamespace();
if (classNamespace == null) {
Msg.error(RttiUtil.class, "Cannot get namespace from model " + model.getAddress());
return false;
}
// <br>Note: For now this assumes all classes and structs with RTTI data must
// actually be classes. In the future this might need additional checking before
// promoting some "struct" ref types to being a class, if we can better determine
// whether or not they are actually classes.
String refType = model.getRefType(); // Can be null.
boolean makeClass = "class".equals(refType) || "struct".equals(refType);
if (makeClass) {
classNamespace = RttiUtil.promoteToClassNamespace(program, classNamespace);
}
// Make the symbol even if the namespace couldn't be promoted
// the method to promote spits out debug error if it cannot be promoted
EHDataTypeUtilities.createSymbolIfNeeded(program, classNamespace, RTTI_0_NAME,
getDataAddress(), applyOptions);
return true;

View File

@@ -256,9 +256,8 @@ public class EHDataTypeUtilities {
* the specified address in the program.
*
* @param program the program.
* @param prefix the symbol prefix to be used in the symbol name.
* @param classNamespace the class Namespace to create the symbol in
* @param dataTypeName the dataTypeName to be used in the symbol name.
* @param suffix the symbol suffix to be used in the symbol name.
* @param address the address where the symbol should be created in the program.
* @param applyOptions options indicating whether or not to apply comments.
*
@@ -266,8 +265,8 @@ public class EHDataTypeUtilities {
*
* @throws InvalidInputException thrown if symbol can't be created as specified.
*/
public static Symbol createSymbolIfNeeded(Program program, String prefix, String dataTypeName,
String suffix, Address address, DataApplyOptions applyOptions)
public static Symbol createSymbolIfNeeded(Program program, Namespace classNamespace,
String dataTypeName, Address address, DataApplyOptions applyOptions)
throws InvalidInputException {
if (dataTypeName == null || !applyOptions.shouldCreateLabel()) {
@@ -277,20 +276,21 @@ public class EHDataTypeUtilities {
// Make sure we have underscores in name
dataTypeName = SymbolUtilities.replaceInvalidChars(dataTypeName, true);
SymbolTable symbolTable = program.getSymbolTable();
SymbolIterator symbols = symbolTable.getSymbolsAsIterator(address);
for (Symbol symbol : symbols) {
if (symbol.getName().contains(dataTypeName)) {
if (symbol.getName().contains(dataTypeName) &&
symbol.getParentNamespace().equals(classNamespace)) {
return null; // Already have one with dataTypeName.
}
}
String appliedPrefix = (prefix != null) ? (prefix) : "";
String appliedSuffix = (suffix != null) ? (suffix) : "";
String appliedSymbol = appliedPrefix + dataTypeName + appliedSuffix;
appliedSymbol = SymbolUtilities.replaceInvalidChars(appliedSymbol, true);
Symbol symbol =
symbolTable.createLabel(address, dataTypeName, classNamespace, SourceType.IMPORTED);
symbol.setPrimary();
return symbolTable.createLabel(address, appliedSymbol, SourceType.ANALYSIS);
return symbol;
}
/**

View File

@@ -68,28 +68,11 @@ public class RttiUtil {
rttiSuffix = SymbolUtilities.replaceInvalidChars(rttiSuffix, true);
// Get or create the namespace for this RTTI's type descriptor.
// Get the namespace for this RTTI's type descriptor.
Namespace classNamespace = typeDescriptorModel.getDescriptorAsNamespace();
// If the RTTI's type descriptor is for a class or struct then promote its
// namespace to a class.
// <br>Note: For now this assumes all classes and structs with RTTI data must
// actually be classes. In the future this might need additional checking before
// promoting some "struct" ref types to being a class, if we can better determine
// whether or not they are actually classes.
String refType = typeDescriptorModel.getRefType(); // Can be null.
boolean makeClass = "class".equals(refType) || "struct".equals(refType);
SymbolTable symbolTable = program.getSymbolTable();
if (makeClass && (classNamespace != null) && !(classNamespace instanceof GhidraClass)) {
try {
classNamespace = NamespaceUtils.convertNamespaceToClass(classNamespace);
}
catch (InvalidInputException iie) {
Msg.error(RttiUtil.class,
"Unable to convert namespace to class for namespace " + classNamespace + ".",
iie);
}
}
// See if the symbol already exists for the RTTI data.
Symbol matchingSymbol = symbolTable.getSymbol(rttiSuffix, rttiAddress, classNamespace);
@@ -103,17 +86,15 @@ public class RttiUtil {
if (name.contains(rttiSuffix)) {
return false; // Similar symbol already exists.
}
// assume any imported symbol is better than what we would put down
// if mangled, it will get demangled later
SourceType source = symbol.getSource();
if (source == SourceType.IMPORTED) {
return false;
}
}
try {
// Didn't find the symbol, so create it.
symbolTable.createLabel(rttiAddress, rttiSuffix, classNamespace,
// Ignore imported mangled symbol because demangling would add tick marks into the name.
// The name created here is better. Set the symbol to be primary so that the demangler
// won't demangle.
Symbol symbol = symbolTable.createLabel(rttiAddress, rttiSuffix, classNamespace,
SourceType.IMPORTED);
symbol.setPrimary();
return true;
}
catch (InvalidInputException e) {
@@ -123,6 +104,26 @@ public class RttiUtil {
}
}
/**
* Method to promote the given namespace to a class namespace
* @param program the given program
* @param namespace the given namespace
* @return the promoted class namespace
*/
public static Namespace promoteToClassNamespace(Program program, Namespace namespace) {
if (!(namespace instanceof GhidraClass)) {
try {
namespace = NamespaceUtils.convertNamespaceToClass(namespace);
}
catch (InvalidInputException iie) {
Msg.error(RttiUtil.class,
"Unable to convert namespace to class for namespace " + namespace + ".", iie);
}
}
return namespace;
}
/**
* Determines the number of vf addresses in the vf table that begins at the specified base
* address.
@@ -377,6 +378,8 @@ public class RttiUtil {
program.getName() + " Couldn't create type_info vftable symbol. ");
return;
}
// This fixes the double label issue that happens when there is pdb
vftableSymbol.setPrimary();
}
catch (InvalidInputException e) {
Msg.error(RttiUtil.class,