GP-4773 - PDB - Standardize namespaces and improve class namespace determination; involved MDMangUtils too; re-instates GP-4595 change

This commit is contained in:
ghizard 2024-07-18 18:21:21 -04:00
parent cc2d53e594
commit c26a290c14
11 changed files with 244 additions and 129 deletions

View file

@ -162,8 +162,12 @@ public class MDMangGhidra extends MDMang {
// what it is // what it is
demangled = new DemangledType(mangledSource, qual.toString(), qual.toString()); demangled = new DemangledType(mangledSource, qual.toString(), qual.toString());
} }
else if (qual.isLocalNamespace()) {
String local =
MDMangUtils.createStandardLocalNamespaceNode(qual.getLocalNamespaceNumber());
demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), local);
}
else { else {
// This takes care of plain and local namespaces
demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString()); demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString());
} }
return demangled; return demangled;

View file

@ -169,7 +169,17 @@ public class MDMangUtils {
return anon; return anon;
} }
Long num = Long.valueOf(str, 16); Long num = Long.valueOf(str, 16);
return String.format("anon_%08X", num); return String.format("_anon_%08X", num);
}
/**
* Given a number in string format as input, creates the standardized local namespace
* node string of the format {@code __l2} where {@code 2} is an an example number.
* @param localNumber the input string
* @return the standardized local namespace component
*/
public static String createStandardLocalNamespaceNode(String localNumber) {
return String.format("__l%s", localNumber);
} }
// @formatter:off // @formatter:off
@ -250,7 +260,7 @@ public class MDMangUtils {
* @param symbolPath the symbol path to standardize * @param symbolPath the symbol path to standardize
* @return the standardized symbol path * @return the standardized symbol path
*/ */
public static SymbolPath standarizeSymbolPath(SymbolPath symbolPath) { public static SymbolPath standarizeSymbolPathTicks(SymbolPath symbolPath) {
List<String> parts = symbolPath.asList(); List<String> parts = symbolPath.asList();
for (int i = 0; i < parts.size(); i++) { for (int i = 0; i < parts.size(); i++) {
String part = parts.get(i); String part = parts.get(i);
@ -283,7 +293,7 @@ public class MDMangUtils {
* @param symbolPath the symbol path to standardize * @param symbolPath the symbol path to standardize
* @return the standardized symbol path * @return the standardized symbol path
*/ */
public static SymbolPath standarizeSymbolPathAlt(SymbolPath symbolPath) { public static SymbolPath standarizeSymbolPathUnderscores(SymbolPath symbolPath) {
List<String> parts = symbolPath.asList(); List<String> parts = symbolPath.asList();
for (int i = 0; i < parts.size(); i++) { for (int i = 0; i < parts.size(); i++) {
String part = parts.get(i); String part = parts.get(i);

View file

@ -108,33 +108,33 @@ public class MDMangUtilsTest extends AbstractGenericTest {
} }
@Test @Test
public void testStandarizeSymbolPath() throws Exception { public void testStandarizeSymbolPathTicks() throws Exception {
SymbolPath sp = new SymbolPath(Arrays.asList("name0", "__l1", "name2")); SymbolPath sp = new SymbolPath(Arrays.asList("name0", "__l1", "name2"));
SymbolPath result = MDMangUtils.standarizeSymbolPath(sp); SymbolPath result = MDMangUtils.standarizeSymbolPathTicks(sp);
String expected = "name0::`1'::name2"; String expected = "name0::`1'::name2";
assertEquals(expected, result.toString()); assertEquals(expected, result.toString());
} }
@Test @Test
public void testStandarizeSymbolPathWithEmbedded() throws Exception { public void testStandarizeSymbolPathWithEmbeddedTicks() throws Exception {
SymbolPath sp = new SymbolPath(Arrays.asList("name0", "__l1", "name2(name3::__l4::name5)")); SymbolPath sp = new SymbolPath(Arrays.asList("name0", "__l1", "name2(name3::__l4::name5)"));
SymbolPath result = MDMangUtils.standarizeSymbolPath(sp); SymbolPath result = MDMangUtils.standarizeSymbolPathTicks(sp);
String expected = "name0::`1'::name2(name3::`4'::name5)"; String expected = "name0::`1'::name2(name3::`4'::name5)";
assertEquals(expected, result.toString()); assertEquals(expected, result.toString());
} }
@Test @Test
public void testStandarizeSymbolPathAlt() throws Exception { public void testStandarizeSymbolPathUnderscores() throws Exception {
SymbolPath sp = new SymbolPath(Arrays.asList("name0", "`1'", "name2")); SymbolPath sp = new SymbolPath(Arrays.asList("name0", "`1'", "name2"));
SymbolPath result = MDMangUtils.standarizeSymbolPathAlt(sp); SymbolPath result = MDMangUtils.standarizeSymbolPathUnderscores(sp);
String expected = "name0::__l1::name2"; String expected = "name0::__l1::name2";
assertEquals(expected, result.toString()); assertEquals(expected, result.toString());
} }
@Test @Test
public void testStandarizeSymbolPathWithEmbeddedAlt() throws Exception { public void testStandarizeSymbolPathWithEmbeddedUnderscores() throws Exception {
SymbolPath sp = new SymbolPath(Arrays.asList("name0", "`1'", "name2(name3::`4'::name5)")); SymbolPath sp = new SymbolPath(Arrays.asList("name0", "`1'", "name2(name3::`4'::name5)"));
SymbolPath result = MDMangUtils.standarizeSymbolPathAlt(sp); SymbolPath result = MDMangUtils.standarizeSymbolPathUnderscores(sp);
String expected = "name0::__l1::name2(name3::__l4::name5)"; String expected = "name0::__l1::name2(name3::__l4::name5)";
assertEquals(expected, result.toString()); assertEquals(expected, result.toString());
} }

View file

@ -19,6 +19,7 @@ import ghidra.app.util.SymbolPath;
import ghidra.app.util.SymbolPathParser; import ghidra.app.util.SymbolPathParser;
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractComplexMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractComplexMsType;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
import ghidra.app.util.pdb.PdbNamespaceUtils; import ghidra.app.util.pdb.PdbNamespaceUtils;
import ghidra.util.Msg; import ghidra.util.Msg;
import mdemangler.*; import mdemangler.*;
@ -45,22 +46,7 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
* @see #getFixedSymbolPath(AbstractComplexMsType type) * @see #getFixedSymbolPath(AbstractComplexMsType type)
*/ */
SymbolPath getSymbolPath(AbstractComplexMsType type) { SymbolPath getSymbolPath(AbstractComplexMsType type) {
SymbolPath symbolPath = null; return getSymbolPath(type.getName(), type.getMangledName());
// We added logic to check the mangled name first because we found some LLVM "lambda"
// symbols where the regular name was a generic "<lambda_0>" with a namespace, but this
// often had a member that also lambda that was marked with the exact same namespace/name
// as the containing structure. We found that the mangled names had more accurate and
// distinguished lambda numbers.
// Temporarily comment out main work of GP-4595 due to namespace/class issues (20240705) TODO: fix
// String mangledName = type.getMangledName();
// if (mangledName != null) {
// symbolPath = getSymbolPathFromMangledTypeName(mangledName);
// }
if (symbolPath == null) {
String fullPathName = type.getName();
symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName));
}
return symbolPath;
} }
/** /**
@ -92,7 +78,45 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
return PdbNamespaceUtils.convertToGhidraPathName(path, num); return PdbNamespaceUtils.convertToGhidraPathName(path, num);
} }
private SymbolPath getSymbolPathFromMangledTypeName(String mangledString) { /**
* Returns the symbol path for the data type referenced by the type record number provided
* @param applicator the applicator
* @param recordNumber the record number
* @return the symbol path
*/
public static SymbolPath getSymbolPath(DefaultPdbApplicator applicator,
RecordNumber recordNumber) {
AbstractMsType t = applicator.getTypeRecord(recordNumber);
if (!(t instanceof AbstractComplexMsType ct)) {
return null;
}
CppCompositeType cpp = applicator.getClassType(ct);
if (cpp != null) {
return cpp.getSymbolPath();
}
return getSymbolPath(ct.getName(), ct.getMangledName());
}
private static SymbolPath getSymbolPath(String name, String mangledName) {
SymbolPath symbolPath = null;
// We added logic to check the mangled name first because we found some LLVM "lambda"
// symbols where the regular name was a generic "<lambda_0>" with a namespace, but this
// often had a member that also lambda that was marked with the exact same namespace/name
// as the containing structure. We found that the mangled names had more accurate and
// distinguished lambda numbers.
if (mangledName != null) {
symbolPath = getSymbolPathFromMangledTypeName(mangledName, name);
}
if (symbolPath == null) {
symbolPath =
MDMangUtils.standarizeSymbolPathUnderscores(
new SymbolPath(SymbolPathParser.parse(name)));
}
return symbolPath;
}
private static SymbolPath getSymbolPathFromMangledTypeName(String mangledString,
String fullPathName) {
MDMang demangler = new MDMangGhidra(); MDMang demangler = new MDMangGhidra();
try { try {
MDDataType mdDataType = demangler.demangleType(mangledString, true); MDDataType mdDataType = demangler.demangleType(mangledString, true);
@ -101,7 +125,7 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
// Namespace that are flagged as functions (not capable at this time) or types or // Namespace that are flagged as functions (not capable at this time) or types or
// raw namespace nodes. Note, however, that the Demangler is still weak in this // raw namespace nodes. Note, however, that the Demangler is still weak in this
// area as there are codes that we still not know how to interpret. // area as there are codes that we still not know how to interpret.
return MDMangUtils.getSymbolPath(mdDataType); return MDMangUtils.consolidateSymbolPath(mdDataType, fullPathName, true);
// Could consider the following simplification method instead // Could consider the following simplification method instead
// return MDMangUtils.getSimpleSymbolPath(mdDataType); // return MDMangUtils.getSimpleSymbolPath(mdDataType);
} }
@ -110,7 +134,7 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
// Message might cause too much noise (we have a fallback, above, to use the regular // Message might cause too much noise (we have a fallback, above, to use the regular
// name, but this could cause an error... see the notes above about why a mangled // name, but this could cause an error... see the notes above about why a mangled
// name is checked first). // name is checked first).
Msg.info(this, Msg.info(AbstractComplexTypeApplier.class,
"PDB issue dmangling type name: " + e.getMessage() + " for : " + mangledString); "PDB issue dmangling type name: " + e.getMessage() + " for : " + mangledString);
} }
return null; return null;

View file

@ -82,19 +82,19 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
myApplicator.predefineClass(fixedSymbolPath); myApplicator.predefineClass(fixedSymbolPath);
myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size, myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size,
myApplicator.getDataTypeManager()); myApplicator.getDataTypeManager());
myClassType = new CppCompositeType(myComposite, mangledName); myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName);
myClassType.setClass(); myClassType.setClass();
} }
else if (compositeMsType instanceof AbstractStructureMsType) { else if (compositeMsType instanceof AbstractStructureMsType) {
myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size, myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size,
myApplicator.getDataTypeManager()); myApplicator.getDataTypeManager());
myClassType = new CppCompositeType(myComposite, mangledName); myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName);
myClassType.setStruct(); myClassType.setStruct();
} }
else if (compositeMsType instanceof AbstractUnionMsType) { else if (compositeMsType instanceof AbstractUnionMsType) {
myComposite = new UnionDataType(categoryPath, fixedSymbolPath.getName(), myComposite = new UnionDataType(categoryPath, fixedSymbolPath.getName(),
myApplicator.getDataTypeManager()); myApplicator.getDataTypeManager());
myClassType = new CppCompositeType(myComposite, mangledName); myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName);
myClassType.setUnion(); myClassType.setUnion();
} }
else { // InterfaceMsType else { // InterfaceMsType
@ -142,6 +142,16 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
boolean isClass = (type instanceof AbstractClassMsType); boolean isClass = (type instanceof AbstractClassMsType);
int size = getSizeInt(type); int size = getSizeInt(type);
clearComponents(composite); clearComponents(composite);
if (!lists.methods().isEmpty()) {
// See applyCpp where we store sp in CppCompositeType so we don't have to determine
// this again (including possible demangling)... need a place to store this or
// make sure our CppCompositeType (or its replacement) can be the union solution as
// well. Note that the namespace convention of making a Class namespace is what
// allows the "this" pointer to be a pointer to the appropriate container type (even
// though this is a "union").
SymbolPath sp = getFixedSymbolPath(type);
applicator.predefineClass(sp);
}
List<DefaultPdbUniversalMember> myMembers = new ArrayList<>(); List<DefaultPdbUniversalMember> myMembers = new ArrayList<>();
addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers); addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers);
addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers); addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers);
@ -159,6 +169,10 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
Composite composite = combo.dt(); Composite composite = combo.dt();
CppCompositeType classType = combo.ct(); CppCompositeType classType = combo.ct();
clearComponents(composite); clearComponents(composite);
if (!lists.bases().isEmpty() || !lists.methods().isEmpty()) {
SymbolPath sp = classType.getSymbolPath();
applicator.predefineClass(sp);
}
List<DefaultPdbUniversalMember> myMembers = new ArrayList<>(); List<DefaultPdbUniversalMember> myMembers = new ArrayList<>();
addClassTypeBaseClasses(composite, classType, lists.bases(), type); addClassTypeBaseClasses(composite, classType, lists.bases(), type);
addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers); addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers);

View file

@ -20,6 +20,7 @@ import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import ghidra.app.util.SymbolPath;
import ghidra.app.util.bin.format.pdb.*; import ghidra.app.util.bin.format.pdb.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog;
@ -48,6 +49,7 @@ public class CppCompositeType {
private String className; // String for now. private String className; // String for now.
private String mangledName; private String mangledName;
private int size; private int size;
private SymbolPath symbolPath;
private Composite composite; private Composite composite;
private CategoryPath categoryPath; private CategoryPath categoryPath;
@ -78,7 +80,8 @@ public class CppCompositeType {
private Map<Integer, PlaceholderVirtualBaseTable> placeholderVirtualBaseTables; private Map<Integer, PlaceholderVirtualBaseTable> placeholderVirtualBaseTables;
//---------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------
public CppCompositeType(Composite composite, String mangledName) { public CppCompositeType(SymbolPath symbolPath, Composite composite, String mangledName) {
Objects.requireNonNull(symbolPath, "symbolPath may not be null");
Objects.requireNonNull(composite, "composite may not be null"); Objects.requireNonNull(composite, "composite may not be null");
syntacticBaseClasses = new ArrayList<>(); syntacticBaseClasses = new ArrayList<>();
layoutBaseClasses = new ArrayList<>(); layoutBaseClasses = new ArrayList<>();
@ -90,46 +93,49 @@ public class CppCompositeType {
isFinal = false; isFinal = false;
type = Type.UNKNOWN; type = Type.UNKNOWN;
this.symbolPath = symbolPath;
this.composite = composite; this.composite = composite;
placeholderVirtualBaseTables = new HashMap<>(); placeholderVirtualBaseTables = new HashMap<>();
categoryPath = new CategoryPath(composite.getCategoryPath(), composite.getName()); categoryPath = new CategoryPath(composite.getCategoryPath(), composite.getName());
this.mangledName = mangledName; this.mangledName = mangledName;
} }
public static CppClassType createCppClassType(Composite composite, String mangledName) { public static CppClassType createCppClassType(SymbolPath symbolPath, Composite composite,
return new CppClassType(composite, mangledName); String mangledName) {
return new CppClassType(symbolPath, composite, mangledName);
} }
public static CppClassType createCppClassType(Composite composite, String name, public static CppClassType createCppClassType(SymbolPath symbolPath, Composite composite,
String mangledName, int size) { String name, String mangledName, int size) {
CppClassType cppType = new CppClassType(composite, mangledName); CppClassType cppType = new CppClassType(symbolPath, composite, mangledName);
cppType.setName(name); cppType.setName(name);
cppType.setSize(size); cppType.setSize(size);
return cppType; return cppType;
} }
public static CppStructType createCppStructType(Composite composite, String mangledName) { public static CppStructType createCppStructType(SymbolPath symbolPath, Composite composite,
return new CppStructType(composite, mangledName); String mangledName) {
return new CppStructType(symbolPath, composite, mangledName);
} }
public static CppStructType createCppStructType(Composite composite, String name, public static CppStructType createCppStructType(SymbolPath symbolPath, Composite composite,
String mangledName, int size) { String name, String mangledName, int size) {
CppStructType cppType = new CppStructType(composite, mangledName); CppStructType cppType = new CppStructType(symbolPath, composite, mangledName);
cppType.setName(name); cppType.setName(name);
cppType.setSize(size); cppType.setSize(size);
return cppType; return cppType;
} }
private static class CppClassType extends CppCompositeType { private static class CppClassType extends CppCompositeType {
private CppClassType(Composite composite, String mangledName) { private CppClassType(SymbolPath symbolPath, Composite composite, String mangledName) {
super(composite, mangledName); super(symbolPath, composite, mangledName);
setClass(); setClass();
} }
} }
private static class CppStructType extends CppCompositeType { private static class CppStructType extends CppCompositeType {
private CppStructType(Composite composite, String mangledName) { private CppStructType(SymbolPath symbolPath, Composite composite, String mangledName) {
super(composite, mangledName); super(symbolPath, composite, mangledName);
setStruct(); setStruct();
} }
} }
@ -186,6 +192,10 @@ public class CppCompositeType {
return layoutBaseClasses; return layoutBaseClasses;
} }
SymbolPath getSymbolPath() {
return symbolPath;
}
Composite getComposite() { Composite getComposite() {
return composite; return composite;
} }

View file

@ -49,6 +49,7 @@ import ghidra.util.Msg;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.CancelOnlyWrappingTaskMonitor; import ghidra.util.task.CancelOnlyWrappingTaskMonitor;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import mdemangler.MDMangUtils;
/** /**
* The main engine for applying an AbstractPdb to Ghidra, whether a Program or DataTypeManager. * The main engine for applying an AbstractPdb to Ghidra, whether a Program or DataTypeManager.
@ -2249,42 +2250,23 @@ public class DefaultPdbApplicator implements PdbApplicator {
} }
//============================================================================================== //==============================================================================================
@SuppressWarnings("unused") // For method not being called. In process of removing this version boolean addToPlateUnique(Address address, String comment) {
boolean createSymbolOld(Address address, String symbolPathString, boolean forcePrimary) { if (StringUtils.isBlank(comment)) {
return false;
// storeLabelByAddress(address, symbolPathString); }
String plate = program.getListing().getComment(CodeUnit.PLATE_COMMENT, address);
try { if (plate == null) {
Namespace namespace = program.getGlobalNamespace(); plate = "";
if (symbolPathString.startsWith(THUNK_NAME_PREFIX)) { }
symbolPathString = symbolPathString.substring(THUNK_NAME_PREFIX.length(), else if (plate.contains(comment)) {
symbolPathString.length());
}
SymbolPath symbolPath = new SymbolPath(symbolPathString);
symbolPath = symbolPath.replaceInvalidChars();
String name = symbolPath.getName();
String namespacePath = symbolPath.getParentPath();
if (namespacePath != null) {
namespace = NamespaceUtils.createNamespaceHierarchy(namespacePath, namespace,
program, address, SourceType.IMPORTED);
}
Symbol s = SymbolUtilities.createPreferredLabelOrFunctionSymbol(program, address,
namespace, name, SourceType.IMPORTED);
if (s != null && forcePrimary) {
// PDB contains both mangled, namespace names, and global names
// If mangled name does not remain primary it will not get demamgled
// and we may not get signature information applied
SetLabelPrimaryCmd cmd =
new SetLabelPrimaryCmd(address, s.getName(), s.getParentNamespace());
cmd.applyTo(program);
}
return true; return true;
} }
catch (InvalidInputException e) { else if (!comment.endsWith("\n")) {
log.appendMsg("PDB Warning: Unable to create symbol: " + e.getMessage()); comment += '\n';
} }
return false; plate = comment + plate; // putting new comment at top of existing plate
SetCommentCmd.createComment(program, address, plate, CodeUnit.PLATE_COMMENT);
return true;
} }
//============================================================================================== //==============================================================================================
@ -2292,48 +2274,59 @@ public class DefaultPdbApplicator implements PdbApplicator {
return createSymbol(address, symbolPathString, isNewFunctionSignature, null); return createSymbol(address, symbolPathString, isNewFunctionSignature, null);
} }
Symbol createSymbol(Address address, SymbolPath symbolPath, boolean isNewFunctionSignature) {
symbolPath = MDMangUtils.standarizeSymbolPathUnderscores(symbolPath);
symbolPath = symbolPath.replaceInvalidChars();
return createSymbolInternal(address, symbolPath, isNewFunctionSignature, null);
}
Symbol createSymbol(Address address, String symbolPathString, boolean isNewFunctionSignature, Symbol createSymbol(Address address, String symbolPathString, boolean isNewFunctionSignature,
String plateAddition) { String plateAddition) {
SymbolPath symbolPath = getCleanSymbolPath(symbolPathString);
return createSymbolInternal(address, symbolPath, isNewFunctionSignature, plateAddition);
}
SymbolPath newSymbolPath = getCleanSymbolPath(symbolPathString); private Symbol createSymbolInternal(Address address, SymbolPath symbolPath,
boolean isNewFunctionSignature,
String plateAddition) {
Symbol existingSymbol = program.getSymbolTable().getPrimarySymbol(address); Symbol existingSymbol = program.getSymbolTable().getPrimarySymbol(address);
if (existingSymbol == null || isNewFunctionSignature) { if (existingSymbol == null || isNewFunctionSignature) {
return createSymbol(address, newSymbolPath, true, plateAddition); return doCreateSymbol(address, symbolPath, true, plateAddition);
} }
if (existingSymbol.getSymbolType() == SymbolType.FUNCTION && if (existingSymbol.getSymbolType() == SymbolType.FUNCTION &&
existingSymbol.getSource() == SourceType.DEFAULT) { existingSymbol.getSource() == SourceType.DEFAULT) {
return createSymbol(address, newSymbolPath, true, plateAddition); return doCreateSymbol(address, symbolPath, true, plateAddition);
} }
Function existingFunction = program.getListing().getFunctionAt(address); Function existingFunction = program.getListing().getFunctionAt(address);
if (existingFunction != null) { // Maybe I should care if there is a data type there too. if (existingFunction != null) { // Maybe I should care if there is a data type there too.
if (existingFunction.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) { if (existingFunction.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) {
// Existing is USER or IMPORTED // Existing is USER or IMPORTED
return createSymbol(address, newSymbolPath, false, plateAddition); return doCreateSymbol(address, symbolPath, false, plateAddition);
} }
} }
if (!existingSymbol.getParentNamespace().equals(program.getGlobalNamespace())) { if (!existingSymbol.getParentNamespace().equals(program.getGlobalNamespace())) {
// existing symbol has a non-global namespace // existing symbol has a non-global namespace
return createSymbol(address, newSymbolPath, false, plateAddition); return doCreateSymbol(address, symbolPath, false, plateAddition);
} }
if (newSymbolPath.getParent() != null) { if (symbolPath.getParent() != null) {
// new symbol has non-global namespace // new symbol has non-global namespace
return createSymbol(address, newSymbolPath, true, plateAddition); return doCreateSymbol(address, symbolPath, true, plateAddition);
} }
// Both existing and new symbols are in global namespace at this point // Both existing and new symbols are in global namespace at this point
if (isMangled(symbolPathString) && !isMangled(existingSymbol.getName())) { if (isMangled(symbolPath.getName()) && !isMangled(existingSymbol.getName())) {
// new symbol is mangled, but don't override existing one if it is mangled // new symbol is mangled, but don't override existing one if it is mangled
return createSymbol(address, newSymbolPath, true, plateAddition); return doCreateSymbol(address, symbolPath, true, plateAddition);
} }
return createSymbol(address, newSymbolPath, false, plateAddition); return doCreateSymbol(address, symbolPath, false, plateAddition);
} }
private Symbol createSymbol(Address address, SymbolPath symbolPath, boolean makePrimary, private Symbol doCreateSymbol(Address address, SymbolPath symbolPath, boolean makePrimary,
String plateAddition) { String plateAddition) {
Symbol symbol = null; Symbol symbol = null;
try { try {
@ -2362,25 +2355,6 @@ public class DefaultPdbApplicator implements PdbApplicator {
return symbol; return symbol;
} }
public boolean addToPlateUnique(Address address, String comment) {
if (StringUtils.isBlank(comment)) {
return false;
}
String plate = program.getListing().getComment(CodeUnit.PLATE_COMMENT, address);
if (plate == null) {
plate = "";
}
else if (plate.contains(comment)) {
return true;
}
else if (!comment.endsWith("\n")) {
comment += '\n';
}
plate = comment + plate; // putting new comment at top of existing plate
SetCommentCmd.createComment(program, address, plate, CodeUnit.PLATE_COMMENT);
return true;
}
private static boolean isMangled(String name) { private static boolean isMangled(String name) {
return name.startsWith("?"); return name.startsWith("?");
} }

View file

@ -123,6 +123,14 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier {
FieldListTypeApplier.FieldLists lists = FieldListTypeApplier.FieldLists lists =
fieldListApplier.getFieldLists(fieldListRecordNumber); fieldListApplier.getFieldLists(fieldListRecordNumber);
if (!lists.methods().isEmpty()) {
// See applyCpp where we store sp in CppCompositeType so we don't have to determine
// this again (including possible demangling)... can we store this symbol path
// somewhere as well so we do not need to re-create it?
SymbolPath sp = getFixedSymbolPath(type);
applicator.predefineClass(sp);
}
// Note: not doing anything with getNamespaceList() or getMethodsList() at this time. // Note: not doing anything with getNamespaceList() or getMethodsList() at this time.
List<AbstractEnumerateMsType> enumerates = lists.enumerates(); List<AbstractEnumerateMsType> enumerates = lists.enumerates();

View file

@ -15,11 +15,14 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; package ghidra.app.util.pdb.pdbapplicator;
import java.util.List;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd; import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
import ghidra.app.cmd.function.CallDepthChangeInfo; import ghidra.app.cmd.function.CallDepthChangeInfo;
import ghidra.app.util.SymbolPath;
import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
@ -28,6 +31,7 @@ import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.SourceType;
import ghidra.util.InvalidNameException; import ghidra.util.InvalidNameException;
import ghidra.util.Msg;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -103,7 +107,68 @@ public class FunctionSymbolApplier extends AbstractBlockContextApplier
// If signature was set, then override existing primary mangled symbol with // If signature was set, then override existing primary mangled symbol with
// the global symbol that provided this signature so that Demangler does not overwrite // the global symbol that provided this signature so that Demangler does not overwrite
// the richer data type we get with global symbols. // the richer data type we get with global symbols.
applicator.createSymbol(address, name, succeededSetFunctionSignature); applicator.createSymbol(address, getReconciledSymbolPath(), succeededSetFunctionSignature);
}
private SymbolPath getReconciledSymbolPath() {
String name = symbol.getName();
SymbolPath symbolPath = new SymbolPath(name);
RecordNumber typeRecordNumber = symbol.getTypeRecordNumber();
AbstractMsType fType = applicator.getTypeRecord(typeRecordNumber);
if (!(fType instanceof AbstractMemberFunctionMsType memberFunction)) {
return symbolPath;
}
// Get containing type, and while we are at it, ensure that it is defined as a class
// namespace.
// This has likely already been done, but we want to be sure that it has.
RecordNumber rc = memberFunction.getContainingClassRecordNumber();
SymbolPath containerSymbolPath = AbstractComplexTypeApplier.getSymbolPath(applicator, rc);
applicator.predefineClass(containerSymbolPath);
// Make sure that the symbol path of the underlying type of the this pointer is also
// defined as a class namespace.
// Probably does not need to be done, as it likely was done for the underlying data type.
AbstractMsType p = memberFunction.getThisPointerType();
if (p instanceof AbstractPointerMsType ptr) {
RecordNumber rpt = ptr.getUnderlyingRecordNumber();
if (!rpt.equals(rc)) {
SymbolPath underlyingSymbolPath =
AbstractComplexTypeApplier.getSymbolPath(applicator, rc);
applicator.predefineClass(underlyingSymbolPath);
}
}
// Only trying to fix up anonymous namespaces
if (!name.startsWith("`anonymous namespace'") && !name.startsWith("anonymous-namespace")) {
return symbolPath;
}
// Reconcile path of function with path of container type.
// Logic is a little different from what is in MDMangUtils.
// Want all namespace nodes to match except possibly the first one, which should be
// the anonymous namespace one.
List<String> containerParts = containerSymbolPath.asList();
List<String> parts = symbolPath.asList();
if (containerParts.size() != parts.size() - 1) {
Msg.info(this, "Unmatched symbol path size during fn name reconcilation");
return symbolPath;
}
for (int i = 0; i < containerParts.size(); i++) {
String containerPart = containerParts.get(i);
String part = parts.get(i);
if (!containerPart.equals(part)) {
if (i == 0) {
parts.set(i, containerPart);
}
else {
Msg.info(this, "Mismatch symbol path nodes during fn name reconcilation");
return symbolPath;
}
}
}
return new SymbolPath(parts);
} }
/** /**

View file

@ -99,6 +99,9 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier {
if (!(applier instanceof CompositeTypeApplier compApplier)) { if (!(applier instanceof CompositeTypeApplier compApplier)) {
return; return;
} }
// 20240709: found example of "this" pointer of method that referenced a composite that
// did not have any base classes or methods. So we want to make sure we take the
// opportunity here to promote the namespace to a class.
SymbolPath sp = compApplier.getFixedSymbolPath(msComposite); SymbolPath sp = compApplier.getFixedSymbolPath(msComposite);
applicator.predefineClass(sp); applicator.predefineClass(sp);
} }

View file

@ -15,7 +15,7 @@
*/ */
package ghidra.app.util.pdb.pdbapplicator; package ghidra.app.util.pdb.pdbapplicator;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import java.util.*; import java.util.*;
@ -24,6 +24,7 @@ import org.junit.Test;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.app.plugin.core.checksums.MyTestMemory; import ghidra.app.plugin.core.checksums.MyTestMemory;
import ghidra.app.util.SymbolPath;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressIterator; import ghidra.program.model.address.AddressIterator;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
@ -476,14 +477,16 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
private static CppCompositeType createStruct32(String name, int size) { private static CppCompositeType createStruct32(String name, int size) {
Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm32); Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm32);
SymbolPath symbolPath = new SymbolPath(name);
String mangledName = createMangledName(name, CppCompositeType.Type.STRUCT); String mangledName = createMangledName(name, CppCompositeType.Type.STRUCT);
return CppCompositeType.createCppStructType(composite, name, mangledName, size); return CppCompositeType.createCppStructType(symbolPath, composite, name, mangledName, size);
} }
private static CppCompositeType createStruct64(String name, int size) { private static CppCompositeType createStruct64(String name, int size) {
Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm64); Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm64);
SymbolPath symbolPath = new SymbolPath(name);
String mangledName = createMangledName(name, CppCompositeType.Type.STRUCT); String mangledName = createMangledName(name, CppCompositeType.Type.STRUCT);
return CppCompositeType.createCppStructType(composite, name, mangledName, 0); return CppCompositeType.createCppStructType(symbolPath, composite, name, mangledName, 0);
} }
private static String createMangledName(String className, CppCompositeType.Type type) { private static String createMangledName(String className, CppCompositeType.Type type) {