Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/GP-4723_ghizard_cleanup_RTTIAnal…
Browse files Browse the repository at this point in the history
…yzer_and_TypeDescriptorModel_use_of_Demangler--SQUASHED'
  • Loading branch information
ryanmkurtz committed Jul 5, 2024
2 parents 280174c + 9860291 commit 4b125c5
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class CreateTypeDescriptorBackgroundCmd
private static final String RTTI_0_NAME = "RTTI Type Descriptor";

/**
* Constructs a command for applying a TypeDescriptor data type at an address using the
* Constructs a command for applying a TypeDescriptor data type at an address using the
* default validation and apply options.
* @param address the address where the data should be created using the data type.
*/
Expand All @@ -46,13 +46,13 @@ public CreateTypeDescriptorBackgroundCmd(Address address) {
}

/**
* Constructs a command for applying a TypeDescriptor data type at an address using the
* Constructs a command for applying a TypeDescriptor data type at an address using the
* indicated options.
* @param address the address where the data should be created using the data type.
* @param validationOptions the options for controlling how validation is performed when
* @param validationOptions the options for controlling how validation is performed when
* determining whether or not to create the data structure at the indicated address.
* @param applyOptions the options for creating the new data structure and its associated
* markup in the program as well as whether to follow other data references and create their
* markup in the program as well as whether to follow other data references and create their
* data too.
*/
public CreateTypeDescriptorBackgroundCmd(Address address,
Expand All @@ -65,7 +65,7 @@ public CreateTypeDescriptorBackgroundCmd(Address address,
* by the model and using the indicated options.
* @param model the model indicating the TypeDescriptor data to be created by this command.
* @param applyOptions the options for creating the new data structure and its associated
* markup in the program as well as whether to follow other data references and create their
* markup in the program as well as whether to follow other data references and create their
* data too.
*/
public CreateTypeDescriptorBackgroundCmd(TypeDescriptorModel model,
Expand Down Expand Up @@ -152,13 +152,14 @@ protected boolean createMarkup() throws CancelledException, InvalidInputExceptio
return false;
}

// If PDB had been run, then the namespace here might already have been promoted to
// a class type. At this point in processing, we know that the model only has a type
// with a "class" or "struct" tag (see TypeDescriptorModel).
// <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) {
// whether or not they are actually classes.
if (!(classNamespace instanceof GhidraClass)) {
classNamespace = RttiUtil.promoteToClassNamespace(program, classNamespace);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
import ghidra.app.cmd.data.rtti.RttiUtil;
import ghidra.app.util.datatype.microsoft.DataValidationOptions;
import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.DemangledType;
import ghidra.app.util.demangler.*;
import ghidra.docking.settings.SettingsImpl;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
Expand All @@ -30,14 +29,12 @@
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import mdemangler.*;
import mdemangler.datatype.MDDataType;
import mdemangler.datatype.complex.MDComplexType;
import mdemangler.datatype.modifier.MDModifierType;
import mdemangler.naming.MDQualifiedName;
import mdemangler.MDException;
import mdemangler.MDMangGhidra;

/**
* Model for the TypeDescriptor data type.
Expand All @@ -57,14 +54,16 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel {
private boolean hasVFPointer;

private String originalTypeName;
private MDComplexType mdComplexType;
private DemangledDataType demangledDataType;
private boolean hasProcessedName = false;
private Namespace namespace;

/**
* Creates the model for the exception handling TypeDescriptor data type.
* @param program the program
* @param address the address in the program for the TypeDescriptor data type.
* @param validationOptions options indicating how to validate the data type at the indicated
* address
*/
public TypeDescriptorModel(Program program, Address address,
DataValidationOptions validationOptions) {
Expand Down Expand Up @@ -204,8 +203,9 @@ private boolean containsWhitespace(String s) {
}

/**
* Gets the TypeDescriptor structure for the indicated program.
* @return the TypeDescriptor structure.
* Gets the TypeDescriptor structure for the indicated program
* @param program the program which will contain this model's data type
* @return the TypeDescriptor structure
*/
public static DataType getDataType(Program program) {

Expand Down Expand Up @@ -247,9 +247,10 @@ public static DataType getDataType(Program program) {
}

/**
* Determine if this model's data type has a vf table pointer.
* @param program the program which will contain this model's data type.
* @return true if the data type has a vf table pointer. Otherwise, it has a hash value.
* Determines if this model's data type program-wide TypeInfo Vftable pointer. This is used
* as an indication as to whether the particular data type has a Vftable pointer
* @param program the program which will contain this model's data type
* @return true if the data type has a vf table pointer. Otherwise, it has a hash value
*/
private static boolean hasVFPointer(Program program) {

Expand Down Expand Up @@ -374,7 +375,7 @@ public Address getVFTableAddress() throws InvalidDataTypeException, UndefinedVal
*/
public Scalar getHashValue() throws InvalidDataTypeException, UndefinedValueException {
checkValidity();
if (hasVFPointer) {
if (!hasVFPointer) {
throw new UndefinedValueException(
"No hash value is defined for this TypeDescriptor model.");
}
Expand Down Expand Up @@ -429,6 +430,9 @@ public String getTypeName() throws InvalidDataTypeException {
* model's address.
*/
private String doGetTypeName() throws InvalidDataTypeException {
if (hasProcessedName) {
return originalTypeName;
}
// last component is the type descriptor name.
Address nameAddress = getComponentAddressOfTypeName(); // Could be null.
if (nameAddress == null) {
Expand All @@ -442,9 +446,7 @@ private String doGetTypeName() throws InvalidDataTypeException {
Object value = terminatedStringDt.getValue(nameMemBuffer, SettingsImpl.NO_SETTINGS, 1);
if (value instanceof String) {
originalTypeName = (String) value;
if (originalTypeName != null) {
mdComplexType = getMDComplexType(program, originalTypeName); // Can be null.
}
demangledDataType = getDemangledDataType(originalTypeName); // Can be null
}
hasProcessedName = true;
return originalTypeName;
Expand All @@ -453,13 +455,13 @@ private String doGetTypeName() throws InvalidDataTypeException {
private boolean hasComplexType() {
if (!hasProcessedName) {
try {
getTypeName(); // Initialize originalTypeName & mdComplexType if possible.
getTypeName(); // Initialize originalTypeName & demangledDataType if possible.
}
catch (InvalidDataTypeException e) {
return false;
}
}
return (mdComplexType != null);
return (demangledDataType != null);
}

/**
Expand All @@ -468,16 +470,7 @@ private boolean hasComplexType() {
* @return the full demangled type name or null.
*/
public String getDemangledTypeDescriptor() {
return hasComplexType() ? mdComplexType.toString() : null;
}

/**
* Gets the reference type of the type descriptor. (i.e. class, struct, union, enum)
* @return the type of thing referred to by this descriptor, or null if it couldn't be
* determined.
*/
public String getRefType() {
return hasComplexType() ? mdComplexType.getTypeName() : null;
return hasComplexType() ? demangledDataType.getOriginalDemangled() : null;
}

/**
Expand All @@ -486,24 +479,15 @@ public String getRefType() {
* be determined.
*/
public String getDescriptorName() {
if (!hasComplexType()) {
return null;
}
MDQualifiedName qualifiedName = mdComplexType.getNamespace();
return qualifiedName.getName();
return hasComplexType() ? demangledDataType.getName() : null;
}

/**
* Gets the parent namespace of the type descriptor.
* @return the parent namespace as a DemangledType or null.
*/
public DemangledType getParentNamespace() {
if (!hasComplexType()) {
return null;
}
MDQualifiedName qualifiedName = mdComplexType.getNamespace();
MDMangGhidra demangler = new MDMangGhidra();
return demangler.processNamespace(qualifiedName);
public Demangled getParentNamespace() {
return hasComplexType() ? demangledDataType.getNamespace() : null;
}

/**
Expand All @@ -512,7 +496,7 @@ public DemangledType getParentNamespace() {
* @return the full pathname or null.
*/
public String getDescriptorTypeNamespace() {
return hasComplexType() ? mdComplexType.getTypeNamespace() : null;
return hasComplexType() ? demangledDataType.getNamespaceString() : null;
}

/**
Expand Down Expand Up @@ -585,27 +569,20 @@ public void validate(Address expectedVFTableAddress)
}

/**
* Gets the namespace for this descriptor. It will create the namespace if it doesn't already exist.
* @return the descriptor's namespace, or null if it couldn't be determined.
* Gets the namespace for this descriptor. It will create the namespace if it doesn't already
* exist
* @return the descriptor's namespace or null if it couldn't be determined
*/
public Namespace getDescriptorAsNamespace() {
if (namespace == null || isNamespaceDeleted(namespace)) {
String descriptorName = getDescriptorName(); // Can be null.
if (descriptorName == null) {
return null;
}

String demangledSource = mdComplexType.toString();
DemangledType typeNamespace =
new DemangledType(originalTypeName, demangledSource, descriptorName);
DemangledType parentNamespace = getParentNamespace(); // Can be null;
if (parentNamespace != null) {
typeNamespace.setNamespace(parentNamespace);
}
Program program = getProgram();
namespace = DemangledObject.createNamespace(program, typeNamespace,
program.getGlobalNamespace(), false);
if (namespace != null && !isNamespaceDeleted(namespace)) {
return namespace;
}
if (hasComplexType() && demangledDataType == null) {
return null;
}
Program program = getProgram();
namespace = DemangledObject.createNamespace(program, demangledDataType,
program.getGlobalNamespace(), false);
return namespace;
}

Expand All @@ -618,27 +595,37 @@ private boolean isNamespaceDeleted(Namespace other) {
}

/**
* Gets a demangler complex type for the indicated mangled string.
* @param program the program containing the mangled string
* @param mangledString the mangled string to be decoded
* @return the associated complex type or null if the string couldn't be demangled.
* Gets a DemangledDataType for the indicated mangled string
* @param mangledString the mangled string to be demangled
* @return the DemangledDataType or null if couldn't demangle or is not a class type
*/
private static MDComplexType getMDComplexType(Program program, String mangledString) {
private static DemangledDataType getDemangledDataType(String mangledString) {
MDMangGhidra demangler = new MDMangGhidra();
try {
MDDataType mangledDt = demangler.demangleType(mangledString, true);
if (mangledDt instanceof MDModifierType modifierType) {
MDType refType = modifierType.getReferencedType();
if (refType instanceof MDComplexType complexType) {
return complexType;
}
// Note that we could play with the return value, but it is not needed; instead, we
// get the DemangledDataType by calling the appropriate method
demangler.demangleType(mangledString, true);
DemangledDataType demangledType = demangler.getDataType();
if (isPermittedType(demangledType)) {
return demangledType;
}
return null; // Not an MDComplexType
}
catch (MDException e) {
// Couldn't demangle.
return null;
}
return null;
}

private static boolean isPermittedType(DemangledDataType demangledDataType) {
if (demangledDataType == null) {
return false;
}
if (demangledDataType.isClass() || demangledDataType.isStruct()) {
return true;
}
Msg.info(TypeDescriptorModel.class,
"Unprocessed TypeDescriptor: " + demangledDataType.getSignature());
return false;
}

}
Loading

0 comments on commit 4b125c5

Please sign in to comment.