mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-09-20 09:31:47 +00:00
GP-4773 - PDB - Standardize namespaces and improve class namespace determination; involved MDMangUtils too; re-instates GP-4595 change
This commit is contained in:
parent
cc2d53e594
commit
c26a290c14
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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("?");
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user