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

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -162,8 +162,12 @@ public class MDMangGhidra extends MDMang {
// what it is
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 {
// This takes care of plain and local namespaces
demangled = new DemangledNamespaceNode(mangledSource, qual.toString(), qual.toString());
}
return demangled;

View File

@ -169,7 +169,17 @@ public class MDMangUtils {
return anon;
}
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
@ -250,7 +260,7 @@ public class MDMangUtils {
* @param symbolPath the symbol path to standardize
* @return the standardized symbol path
*/
public static SymbolPath standarizeSymbolPath(SymbolPath symbolPath) {
public static SymbolPath standarizeSymbolPathTicks(SymbolPath symbolPath) {
List<String> parts = symbolPath.asList();
for (int i = 0; i < parts.size(); i++) {
String part = parts.get(i);
@ -283,7 +293,7 @@ public class MDMangUtils {
* @param symbolPath the symbol path to standardize
* @return the standardized symbol path
*/
public static SymbolPath standarizeSymbolPathAlt(SymbolPath symbolPath) {
public static SymbolPath standarizeSymbolPathUnderscores(SymbolPath symbolPath) {
List<String> parts = symbolPath.asList();
for (int i = 0; i < parts.size(); i++) {
String part = parts.get(i);

View File

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

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,6 +19,7 @@ import ghidra.app.util.SymbolPath;
import ghidra.app.util.SymbolPathParser;
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.AbstractMsType;
import ghidra.app.util.pdb.PdbNamespaceUtils;
import ghidra.util.Msg;
import mdemangler.*;
@ -45,22 +46,7 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
* @see #getFixedSymbolPath(AbstractComplexMsType type)
*/
SymbolPath getSymbolPath(AbstractComplexMsType type) {
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.
// 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;
return getSymbolPath(type.getName(), type.getMangledName());
}
/**
@ -92,7 +78,45 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
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();
try {
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
// 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.
return MDMangUtils.getSymbolPath(mdDataType);
return MDMangUtils.consolidateSymbolPath(mdDataType, fullPathName, true);
// Could consider the following simplification method instead
// 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
// name, but this could cause an error... see the notes above about why a mangled
// name is checked first).
Msg.info(this,
Msg.info(AbstractComplexTypeApplier.class,
"PDB issue dmangling type name: " + e.getMessage() + " for : " + mangledString);
}
return null;

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -82,19 +82,19 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
myApplicator.predefineClass(fixedSymbolPath);
myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size,
myApplicator.getDataTypeManager());
myClassType = new CppCompositeType(myComposite, mangledName);
myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName);
myClassType.setClass();
}
else if (compositeMsType instanceof AbstractStructureMsType) {
myComposite = new StructureDataType(categoryPath, fixedSymbolPath.getName(), size,
myApplicator.getDataTypeManager());
myClassType = new CppCompositeType(myComposite, mangledName);
myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName);
myClassType.setStruct();
}
else if (compositeMsType instanceof AbstractUnionMsType) {
myComposite = new UnionDataType(categoryPath, fixedSymbolPath.getName(),
myApplicator.getDataTypeManager());
myClassType = new CppCompositeType(myComposite, mangledName);
myClassType = new CppCompositeType(fixedSymbolPath, myComposite, mangledName);
myClassType.setUnion();
}
else { // InterfaceMsType
@ -142,6 +142,16 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
boolean isClass = (type instanceof AbstractClassMsType);
int size = getSizeInt(type);
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<>();
addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers);
addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers);
@ -159,6 +169,10 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
Composite composite = combo.dt();
CppCompositeType classType = combo.ct();
clearComponents(composite);
if (!lists.bases().isEmpty() || !lists.methods().isEmpty()) {
SymbolPath sp = classType.getSymbolPath();
applicator.predefineClass(sp);
}
List<DefaultPdbUniversalMember> myMembers = new ArrayList<>();
addClassTypeBaseClasses(composite, classType, lists.bases(), type);
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 ghidra.app.util.SymbolPath;
import ghidra.app.util.bin.format.pdb.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog;
@ -48,6 +49,7 @@ public class CppCompositeType {
private String className; // String for now.
private String mangledName;
private int size;
private SymbolPath symbolPath;
private Composite composite;
private CategoryPath categoryPath;
@ -78,7 +80,8 @@ public class CppCompositeType {
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");
syntacticBaseClasses = new ArrayList<>();
layoutBaseClasses = new ArrayList<>();
@ -90,46 +93,49 @@ public class CppCompositeType {
isFinal = false;
type = Type.UNKNOWN;
this.symbolPath = symbolPath;
this.composite = composite;
placeholderVirtualBaseTables = new HashMap<>();
categoryPath = new CategoryPath(composite.getCategoryPath(), composite.getName());
this.mangledName = mangledName;
}
public static CppClassType createCppClassType(Composite composite, String mangledName) {
return new CppClassType(composite, mangledName);
public static CppClassType createCppClassType(SymbolPath symbolPath, Composite composite,
String mangledName) {
return new CppClassType(symbolPath, composite, mangledName);
}
public static CppClassType createCppClassType(Composite composite, String name,
String mangledName, int size) {
CppClassType cppType = new CppClassType(composite, mangledName);
public static CppClassType createCppClassType(SymbolPath symbolPath, Composite composite,
String name, String mangledName, int size) {
CppClassType cppType = new CppClassType(symbolPath, composite, mangledName);
cppType.setName(name);
cppType.setSize(size);
return cppType;
}
public static CppStructType createCppStructType(Composite composite, String mangledName) {
return new CppStructType(composite, mangledName);
public static CppStructType createCppStructType(SymbolPath symbolPath, Composite composite,
String mangledName) {
return new CppStructType(symbolPath, composite, mangledName);
}
public static CppStructType createCppStructType(Composite composite, String name,
String mangledName, int size) {
CppStructType cppType = new CppStructType(composite, mangledName);
public static CppStructType createCppStructType(SymbolPath symbolPath, Composite composite,
String name, String mangledName, int size) {
CppStructType cppType = new CppStructType(symbolPath, composite, mangledName);
cppType.setName(name);
cppType.setSize(size);
return cppType;
}
private static class CppClassType extends CppCompositeType {
private CppClassType(Composite composite, String mangledName) {
super(composite, mangledName);
private CppClassType(SymbolPath symbolPath, Composite composite, String mangledName) {
super(symbolPath, composite, mangledName);
setClass();
}
}
private static class CppStructType extends CppCompositeType {
private CppStructType(Composite composite, String mangledName) {
super(composite, mangledName);
private CppStructType(SymbolPath symbolPath, Composite composite, String mangledName) {
super(symbolPath, composite, mangledName);
setStruct();
}
}
@ -186,6 +192,10 @@ public class CppCompositeType {
return layoutBaseClasses;
}
SymbolPath getSymbolPath() {
return symbolPath;
}
Composite getComposite() {
return composite;
}

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -49,6 +49,7 @@ import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.CancelOnlyWrappingTaskMonitor;
import ghidra.util.task.TaskMonitor;
import mdemangler.MDMangUtils;
/**
* 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 createSymbolOld(Address address, String symbolPathString, boolean forcePrimary) {
// storeLabelByAddress(address, symbolPathString);
try {
Namespace namespace = program.getGlobalNamespace();
if (symbolPathString.startsWith(THUNK_NAME_PREFIX)) {
symbolPathString = symbolPathString.substring(THUNK_NAME_PREFIX.length(),
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);
}
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;
}
catch (InvalidInputException e) {
log.appendMsg("PDB Warning: Unable to create symbol: " + e.getMessage());
else if (!comment.endsWith("\n")) {
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);
}
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,
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);
if (existingSymbol == null || isNewFunctionSignature) {
return createSymbol(address, newSymbolPath, true, plateAddition);
return doCreateSymbol(address, symbolPath, true, plateAddition);
}
if (existingSymbol.getSymbolType() == SymbolType.FUNCTION &&
existingSymbol.getSource() == SourceType.DEFAULT) {
return createSymbol(address, newSymbolPath, true, plateAddition);
return doCreateSymbol(address, symbolPath, true, plateAddition);
}
Function existingFunction = program.getListing().getFunctionAt(address);
if (existingFunction != null) { // Maybe I should care if there is a data type there too.
if (existingFunction.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) {
// Existing is USER or IMPORTED
return createSymbol(address, newSymbolPath, false, plateAddition);
return doCreateSymbol(address, symbolPath, false, plateAddition);
}
}
if (!existingSymbol.getParentNamespace().equals(program.getGlobalNamespace())) {
// 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
return createSymbol(address, newSymbolPath, true, plateAddition);
return doCreateSymbol(address, symbolPath, true, plateAddition);
}
// 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
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) {
Symbol symbol = null;
try {
@ -2362,25 +2355,6 @@ public class DefaultPdbApplicator implements PdbApplicator {
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) {
return name.startsWith("?");
}

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -123,6 +123,14 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier {
FieldListTypeApplier.FieldLists lists =
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.
List<AbstractEnumerateMsType> enumerates = lists.enumerates();

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,11 +15,14 @@
*/
package ghidra.app.util.pdb.pdbapplicator;
import java.util.List;
import ghidra.app.cmd.function.ApplyFunctionSignatureCmd;
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.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.AddressSet;
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.symbol.SourceType;
import ghidra.util.InvalidNameException;
import ghidra.util.Msg;
import ghidra.util.exception.*;
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
// the global symbol that provided this signature so that Demangler does not overwrite
// 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)) {
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);
applicator.predefineClass(sp);
}

View File

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