GP-6499 - Various PDB tweaks

This commit is contained in:
ghizard
2026-02-26 16:13:16 -05:00
parent 12605fa91f
commit c348f88346
10 changed files with 118 additions and 34 deletions
@@ -141,7 +141,12 @@ public abstract class ModuleInformation {
}
/**
* Returns {@link SectionContribution} of the module
* Returns {@link SectionContribution} of the module. This seems to be just one of possibly
* many SectionContributions for the module (at least of ModuleInformation600; need to check
* for older PDBs/ModuleInformation500). User should consult the debugInfo
* SectionContributionList for full list of SectionContributions, which also (at least for
* newer PDBs) has many contributions that all refer to the same module (contributions are
* relatively small)
* @return {@link SectionContribution} of the module
*/
public SectionContribution getSectionContribution() {
@@ -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.
@@ -17,6 +17,8 @@ package ghidra.app.util.bin.format.pdb2.pdbreader;
import java.io.*;
import ghidra.app.util.bin.format.pe.SectionFlags;
/**
* This class represents Section Contribution component of a PDB file. This class is only
* suitable for reading; not for writing or modifying a PDB.
@@ -62,6 +64,16 @@ public abstract class SectionContribution {
return imod;
}
/**
* Returns the characteristics. Believe these to be documented at:
* https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_section_header
* User can likely get interpretation from {@link SectionFlags#resolveFlags(int value)}
* @return the characteristics
*/
public long getCharacteristics() {
return characteristics;
}
@Override
public String toString() {
StringWriter writer = new StringWriter();
@@ -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.
@@ -104,7 +104,7 @@ public abstract class AbstractComplexMsType extends AbstractMsType {
/**
* Returns the mangled name within this complex type
* @return Mangled name
* @return Mangled name; can be null
*/
public String getMangledName() {
return mangledName;
@@ -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.
@@ -58,7 +58,11 @@ public class FunctionMsAttributes extends AbstractParsableItem {
isInstanceConstructorOfClassWithVirtualBases = ((attributes & 0x0001) == 0x0001);
}
boolean isConstructor() {
/**
* Returns {@code true} if flagged as a constructor
* @return {@code true} if is constructor
*/
public boolean isConstructor() {
return isInstanceConstructor || isInstanceConstructorOfClassWithVirtualBases;
}
@@ -72,6 +72,11 @@ public abstract class AbstractComplexTypeApplier extends MsDataTypeApplier {
*/
//return mine or my def's (and set mine)
SymbolPath getFixedSymbolPath(AbstractComplexMsType type) {
CppCompositeType compType = applicator.getClassType(type);
if (compType != null) {
// Return path if it has already been processed
return compType.getSymbolPath();
}
SymbolPath path = getSymbolPath(type);
RecordNumber mappedNumber = applicator.getMappedRecordNumber(type.getRecordNumber());
Integer num = mappedNumber.getNumber();
@@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.DataTypeNamingUtil;
import ghidra.app.util.SymbolPath;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
@@ -79,8 +80,9 @@ public abstract class AbstractFunctionTypeApplier extends MsDataTypeApplier {
/**
* Processes containing class if one exists
* @param type the PDB type being inspected
* @return symbol path of containing type; {@code null} if does not exist
*/
protected abstract void processContainingType(AbstractMsType type);
protected abstract SymbolPath processContainingType(AbstractMsType type);
/**
* Returns if known to be a constructor.
@@ -220,10 +222,12 @@ public abstract class AbstractFunctionTypeApplier extends MsDataTypeApplier {
return false;
}
FunctionDefinitionDataType functionDefinition = new FunctionDefinitionDataType(
applicator.getAnonymousFunctionsCategory(), "_func", applicator.getDataTypeManager());
SymbolPath spContainer = processContainingType(type);
CategoryPath cpFunction = getFunctionCategoryPath(spContainer);
FunctionDefinitionDataType functionDefinition = new FunctionDefinitionDataType(
cpFunction, "_func", applicator.getDataTypeManager());
processContainingType(type);
setReturnType(functionDefinition, type);
setArguments(functionDefinition, type);
Pointer thisPointer = getThisPointer(type);
@@ -238,6 +242,16 @@ public abstract class AbstractFunctionTypeApplier extends MsDataTypeApplier {
return true;
}
private CategoryPath getFunctionCategoryPath(SymbolPath spContainer) {
CategoryPath cpStandard = applicator.getAnonymousFunctionsCategory();
if (spContainer == null) {
return cpStandard;
}
CategoryPath cpContainer = applicator.getCategory(spContainer);
// Add the "standard" name to the container path
return cpContainer.extend(cpStandard.getName());
}
/**
* Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(RecordNumber)}) on all underlying
* types to ensure that the types get scheduled... and detects whether any types were not yet
@@ -2226,12 +2226,12 @@ public class DefaultPdbApplicator implements PdbApplicator {
}
//==============================================================================================
void predefineClass(SymbolPath classPath) {
if (classPath == null) {
void predefineClass(SymbolPath symbolPath) {
if (symbolPath == null) {
return;
}
isClassByNamespace.put(classPath, true);
for (SymbolPath path = classPath.getParent(); path != null; path = path.getParent()) {
isClassByNamespace.put(symbolPath, true);
for (SymbolPath path = symbolPath.getParent(); path != null; path = path.getParent()) {
if (!isClassByNamespace.containsKey(path)) {
isClassByNamespace.put(path, false); // path is simple namespace
}
@@ -25,8 +25,7 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
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;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType;
@@ -119,6 +118,9 @@ public class FunctionSymbolApplier extends AbstractBlockContextApplier
return symbolPath;
}
// For Future investigation
//String modName = getConstructorName(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.
@@ -170,6 +172,29 @@ public class FunctionSymbolApplier extends AbstractBlockContextApplier
return new SymbolPath(parts);
}
// For Future investigation
@SuppressWarnings("unused")
private String getConstructorName(SymbolPath symbolPath) {
if (isConstructor() && function != null) {
DataType ret = function.getReturnType();
if (ret != null) {
if (ret instanceof Pointer p) {
DataType u = p.getDataType();
if (u instanceof Composite c) {
String s = c.getName();
String x = symbolPath.getName();
if (!s.equals(x)) {
// Future investigation? In what cases does this hit?
// For example, triggers on x:=DName<1> and s:=DName
// (standard embedded msft demangler stuff found in most binaries)
}
}
}
}
}
return null;
}
/**
* returns true only if we set a function signature
* @return true if function signature was set
@@ -232,6 +257,22 @@ public class FunctionSymbolApplier extends AbstractBlockContextApplier
return true;
}
/**
* Returns true if we can tell that we have a constructor type; false if not or we cannot tell
* @return true if we know that we have a constructor type
*/
private boolean isConstructor() {
RecordNumber typeRecordNumber = symbol.getTypeRecordNumber();
AbstractMsType fType = applicator.getTypeRecord(typeRecordNumber);
if (fType instanceof AbstractMemberFunctionMsType memFn) {
return memFn.getFunctionAttributes().isConstructor();
}
else if (fType instanceof AbstractProcedureMsType fn) {
return fn.getFunctionAttributes().isConstructor();
}
return false;
}
//==============================================================================================
@Override
public void deferredApply(MsSymbolIterator iter) throws PdbException, CancelledException {
@@ -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.
@@ -67,7 +67,8 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier {
return null;
}
if (mType instanceof AbstractPointerMsType msPtr) {
predefineClass(msPtr.getUnderlyingRecordNumber());
SymbolPath sp = getClassSymbolPath(msPtr.getUnderlyingRecordNumber());
applicator.predefineClass(sp);
}
applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointer(mType);
DataType dt = applicator.getDataType(ptrRecord);
@@ -78,32 +79,33 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier {
}
@Override
protected void processContainingType(AbstractMsType type) {
protected SymbolPath processContainingType(AbstractMsType type) {
// TODO: evaluate whether we need to schedule this container type... guessing not
RecordNumber containerRecord =
((AbstractMemberFunctionMsType) type).getContainingClassRecordNumber();
if (containerRecord == null) {
return;
return null;
}
predefineClass(containerRecord);
SymbolPath sp = getClassSymbolPath(containerRecord);
applicator.predefineClass(sp);
AbstractMsType mType = applicator.getTypeRecord(containerRecord);
applicator.getPdbApplicatorMetrics().witnessMemberFunctionContainingType(mType);
return sp;
}
private void predefineClass(RecordNumber recordNumber) {
private SymbolPath getClassSymbolPath(RecordNumber recordNumber) {
AbstractMsType type = applicator.getTypeRecord(recordNumber);
if (!(type instanceof AbstractCompositeMsType msComposite)) {
return;
return null;
}
MsTypeApplier applier = applicator.getTypeApplier(recordNumber);
if (!(applier instanceof CompositeTypeApplier compApplier)) {
return;
return null;
}
// 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);
return compApplier.getFixedSymbolPath(msComposite);
}
@Override
@@ -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,6 +15,7 @@
*/
package ghidra.app.util.pdb.pdbapplicator;
import ghidra.app.util.SymbolPath;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
@@ -59,8 +60,8 @@ public class ProcedureTypeApplier extends AbstractFunctionTypeApplier {
}
@Override
protected void processContainingType(AbstractMsType type) {
return; // do nothing
protected SymbolPath processContainingType(AbstractMsType type) {
return null; // do nothing
}
@Override