From a1d7ed2cb27c22e18755a7a37316204743749243 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Tue, 1 Sep 2020 10:48:01 -0400 Subject: [PATCH 01/15] GT-3112 - PDB Universal - applicator/analyzer (112 squashed commits) --- .../Base/.launch/Ghidra Code Coverage.launch | 27 + Ghidra/Features/Base/certification.manifest | 1 + .../app/util/demangler/DemangledObject.java | 16 +- .../database/data/ConflictHandlerTest.java | 116 + .../plugin/core/checksums/MyTestMemory.java | 7 +- .../DeveloperDumpAllTypesScript.java | 108 + .../DumpAllSymbolsDemangledScript.java | 101 + .../PdbDeveloperDumpScript.java | 88 + .../plugin/core/analysis/Pdb2Analyzer.java | 590 ++ .../app/plugin/core/analysis/PdbAnalyzer.java | 1 + .../format/pdb/DefaultCompositeMember.java | 4 +- .../app/util/bin/format/pdb/PdbBitField.java | 2 +- .../app/util/bin/format/pdb/PdbMember.java | 2 +- .../app/util/bin/format/pdb/PdbParser.java | 2 + .../util/bin/format/pdb/WrappedDataType.java | 2 +- .../pdb2/pdbreader/PdbReaderOptions.java | 28 +- .../bin/format/pdb2/pdbreader/TypeParser.java | 1 - ...aratedCodeFromCompilerSupportMsSymbol.java | 69 +- .../ghidra/app/util/pdb/PdbCategoryUtils.java | 211 + .../app/util/pdb/PdbLocatorSelector.java | 671 ++ .../app/util/pdb/PdbNamespaceUtils.java | 101 + .../format => }/pdb/PdbProgramAttributes.java | 27 +- .../AbstractComplexTypeApplier.java | 111 + .../AbstractFunctionTypeApplier.java | 229 + .../AbstractMsSymbolApplier.java | 75 + .../pdbapplicator/AbstractMsTypeApplier.java | 219 + .../ArgumentsListTypeApplier.java | 227 + .../pdb/pdbapplicator/ArrayTypeApplier.java | 207 + .../pdbapplicator/BaseClassTypeApplier.java | 147 + .../pdbapplicator/BitfieldTypeApplier.java | 112 + .../pdbapplicator/BlockCommentsManager.java | 134 + .../pdb/pdbapplicator/BlockSymbolApplier.java | 65 + .../ComplexTypeApplierMapper.java | 231 + .../pdbapplicator/CompositeLayoutMode.java | 52 + .../pdbapplicator/CompositeTypeApplier.java | 820 ++ .../pdb/pdbapplicator/CppCompositeType.java | 1915 ++++ .../pdb/pdbapplicator/DataSymbolApplier.java | 270 + .../pdb/pdbapplicator/Default2PdbMember.java | 108 + ...efinedSingleAddressRangeSymbolApplier.java | 75 + .../pdb/pdbapplicator/EndSymbolApplier.java | 70 + .../pdb/pdbapplicator/EnumTypeApplier.java | 321 + .../pdbapplicator/EnumerateTypeApplier.java | 93 + .../pdbapplicator/FieldListTypeApplier.java | 183 + ...eAndProcedureInformationSymbolApplier.java | 57 + .../pdbapplicator/FunctionSymbolApplier.java | 456 + .../pdb/pdbapplicator/LabelSymbolApplier.java | 73 + .../LocalOptimizedSymbolApplier.java | 77 + .../MemberFunctionTypeApplier.java | 274 + .../pdb/pdbapplicator/MemberTypeApplier.java | 97 + .../pdbapplicator/ModifierTypeApplier.java | 136 + .../pdb/pdbapplicator/NestedTypeApplier.java | 169 + .../pdb/pdbapplicator/NoSymbolApplier.java | 45 + .../util/pdb/pdbapplicator/NoTypeApplier.java | 50 + .../pdbapplicator/OoComponentLayoutMode.java | 22 + .../pdb/pdbapplicator/PdbAddressManager.java | 406 + .../util/pdb/pdbapplicator/PdbApplicator.java | 1328 +++ .../pdbapplicator/PdbApplicatorMetrics.java | 278 + .../pdbapplicator/PdbApplicatorOptions.java | 213 + .../PdbPrimitiveTypeApplicator.java | 698 ++ ...dbRegisterNameToProgramRegisterMapper.java | 63 + .../util/pdb/pdbapplicator/PdbResearch.java | 1001 ++ .../util/pdb/pdbapplicator/PdbVbtManager.java | 233 + .../PeCoffGroupSymbolApplier.java | 66 + .../PeCoffSectionSymbolApplier.java | 58 + .../pdb/pdbapplicator/PointerTypeApplier.java | 119 + .../pdbapplicator/PrimitiveTypeApplier.java | 2079 ++++ .../pdbapplicator/ProcedureTypeApplier.java | 90 + .../pdbapplicator/PublicSymbolApplier.java | 99 + .../pdbapplicator/ReferenceSymbolApplier.java | 71 + .../RegisterRelativeSymbolApplier.java | 156 + .../SeparatedCodeSymbolApplier.java | 135 + .../pdbapplicator/SymbolApplierParser.java | 659 ++ .../util/pdb/pdbapplicator/SymbolGroup.java | 236 + .../TrampolineSymbolApplier.java | 98 + .../pdb/pdbapplicator/TypeApplierParser.java | 519 + .../pdbapplicator/TypedefSymbolApplier.java | 125 + .../UdtSourceLineTypeApplier.java | 112 + .../util/pdb/pdbapplicator/VbtManager.java | 129 + ...irtualFunctionTablePointerTypeApplier.java | 104 + .../pdb/pdbapplicator/VtShapeTypeApplier.java | 110 + .../pdb/pdbapplicator/WithSymbolApplier.java | 69 + .../main/java/pdb/PdbSymbolServerPlugin.java | 1 + .../pdbapplicator/ConflictHandlerTest2.java | 180 + .../pdbapplicator/CppCompositeTypeTest.java | 8685 +++++++++++++++++ .../ghidra/app/util/SymbolPathParser.java | 4 +- 85 files changed, 27376 insertions(+), 43 deletions(-) create mode 100644 Ghidra/Features/Base/.launch/Ghidra Code Coverage.launch create mode 100644 Ghidra/Features/PDB/developer_scripts/DeveloperDumpAllTypesScript.java create mode 100644 Ghidra/Features/PDB/developer_scripts/DumpAllSymbolsDemangledScript.java create mode 100644 Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpScript.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/Pdb2Analyzer.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategoryUtils.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocatorSelector.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/{bin/format => }/pdb/PdbProgramAttributes.java (87%) create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockCommentsManager.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/Default2PdbMember.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierParser.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierParser.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VbtManager.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java create mode 100644 Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java create mode 100644 Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java diff --git a/Ghidra/Features/Base/.launch/Ghidra Code Coverage.launch b/Ghidra/Features/Base/.launch/Ghidra Code Coverage.launch new file mode 100644 index 0000000000..0b8fc4b28c --- /dev/null +++ b/Ghidra/Features/Base/.launch/Ghidra Code Coverage.launch @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index 0e12e74b48..386226b0b2 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -10,6 +10,7 @@ ##MODULE IP: Oxygen Icons - LGPL 3.0 ##MODULE IP: Tango Icons - Public Domain .gitignore||GHIDRA||||END| +.launch/Ghidra Code Coverage.launch||GHIDRA||||END| .launch/Ghidra.launch||GHIDRA||||END| Module.manifest||GHIDRA||||END| build.gradle||GHIDRA||||END| diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java index 2da0ee5232..b55dffb890 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledObject.java @@ -306,6 +306,15 @@ public abstract class DemangledObject implements Demangled { public boolean applyTo(Program program, Address address, DemanglerOptions options, TaskMonitor monitor) throws Exception { + return applyPlateCommentOnly(program, address); + } + + /** + * @param program The program for which to apply the comment + * @param address The address for the comment + * @return {@code true} if a comment was applied + */ + public boolean applyPlateCommentOnly(Program program, Address address) { if (mangled.equals(name)) { return false; } @@ -443,11 +452,8 @@ public abstract class DemangledObject implements Demangled { List symbols = symbolTable.getSymbols(namespaceName, namespace); Symbol namespaceSymbol = - symbols.stream() - .filter(s -> (s.getSymbolType() == SymbolType.NAMESPACE || - s.getSymbolType() == SymbolType.CLASS)) - .findFirst() - .orElse(null); + symbols.stream().filter(s -> (s.getSymbolType() == SymbolType.NAMESPACE || + s.getSymbolType() == SymbolType.CLASS)).findFirst().orElse(null); if (namespaceSymbol == null) { try { namespace = diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/ConflictHandlerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/ConflictHandlerTest.java index cc7669e4ba..0e94570a97 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/ConflictHandlerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/ConflictHandlerTest.java @@ -395,6 +395,122 @@ public class ConflictHandlerTest extends AbstractGhidraHeadedIntegrationTest { struct1a_pathname, struct1b_pathname); } + /** + * Tests the + * {@link DataTypeConflictHandler#REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER RESORAAH} + * conflict handler to be sure that, if all else is the same, the aligned version is chosen + * over the unaligned version. + *

+ * Success is the aligned version is chosen over the unaligned version. + */ + @Test + public void testChooseNewAlignedOverExistingUnalignedWhenAllElseIsEqualForEmptyStructures() { + // Unaligned exists first. + Structure empty1Unaligned = new StructureDataType(root, "empty1", 0, dataMgr); + Composite empty1AlignedToAdd = (Composite) empty1Unaligned.copy(dataMgr); + empty1AlignedToAdd.setInternallyAligned(true); + + String empty1UnalignedString = empty1Unaligned.toString(); + String empty1AlignedToAddString = empty1AlignedToAdd.toString(); + + Structure empty1AddResult = (Structure) dataMgr.addDataType(empty1AlignedToAdd, + DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER); + String empty1AddResultString = empty1AddResult.toString(); + assertEquals(empty1AlignedToAddString, empty1AddResultString); + assertNotEquals(empty1UnalignedString, empty1AddResultString); + } + + /** + * Tests the + * {@link DataTypeConflictHandler#REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER RESORAAH} + * conflict handler to be sure that, if all else is the same, the aligned version is chosen + * over the unaligned version. + *

+ * Success is the aligned version is chosen over the unaligned version. + */ + @Test + public void testChooseNewAlignedOverExistingUnalignedWhenAllElseIsEqualForNonEmptyStructures() { + // Unaligned exists first. + StructureDataType struct1Unaligned = createPopulated(dataMgr); + Composite struct1AlignedToAdd = (Composite) struct1Unaligned.copy(dataMgr); + struct1AlignedToAdd.setInternallyAligned(true); + + String struct1UnalignedString = struct1Unaligned.toString(); + String struct1AlignedToAddString = struct1AlignedToAdd.toString(); + + Structure struct1AddResult = (Structure) dataMgr.addDataType(struct1AlignedToAdd, + DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER); + String struct1AddResultString = struct1AddResult.toString(); + assertEquals(struct1AlignedToAddString, struct1AddResultString); + assertNotEquals(struct1UnalignedString, struct1AddResultString); + } + + /** + * Tests the + * {@link DataTypeConflictHandler#REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER RESORAAH} + * conflict handler to be sure that, if all else is the same, the new unaligned version is + * chosen over the existing unaligned version. + *

+ * Success is the new unaligned version is chosen over the existing aligned version. + */ + // TODO: consider whether we want to change the logic of the conflict handler to favor + // aligned over unaligned. + @Test + public void testChooseNewUnalignedOverExistingAlignedWhenAllElseIsEqualForEmptyStructures() { + + // Aligned exists first. + Structure empty2Aligned = new StructureDataType(root, "empty2", 0, dataMgr); + Composite empty2UnalignedToAdd = (Composite) empty2Aligned.copy(dataMgr); + // aligning only after making unaligned copy. + empty2Aligned.setInternallyAligned(true); + + String empty2AlignedString = empty2Aligned.toString(); + String empty2UnalignedToAddString = empty2UnalignedToAdd.toString(); + + Structure empty2AddResult = (Structure) dataMgr.addDataType(empty2UnalignedToAdd, + DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER); + String empty2AddResultString = empty2AddResult.toString(); + assertEquals(empty2UnalignedToAddString, empty2AddResultString); + assertNotEquals(empty2AlignedString, empty2AddResultString); + } + + /** + * Tests the + * {@link DataTypeConflictHandler#REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER RESORAAH} + * conflict handler to be sure that, if all else is the same, the new unaligned version is + * chosen over the existing aligned version. + *

+ * Success is the new unaligned version is chosen over the existing aligned version. + */ + // TODO: consider whether we want to change the logic of the conflict handler to favor + // aligned over unaligned. + @Test + public void testChooseNewUnalignedOverExistingAlignedWhenAllElseIsEqualForNonEmptyStructures() { + + // Aligned exists first. + StructureDataType struct2Aligned = createPopulated(dataMgr); + Composite struct2UnalignedToAdd = (Composite) struct2Aligned.copy(dataMgr); + // aligning only after making unaligned copy. + struct2Aligned.setInternallyAligned(true); + + String struct2AlignedString = struct2Aligned.toString(); + String struct2UnalignedToAddString = struct2UnalignedToAdd.toString(); + + Structure struct2AddResult = (Structure) dataMgr.addDataType(struct2UnalignedToAdd, + DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER); + String struct2AddResultString = struct2AddResult.toString(); + assertEquals(struct2UnalignedToAddString, struct2AddResultString); + assertNotEquals(struct2AlignedString, struct2AddResultString); + } + + /** + * Tests the + * {@link DataTypeConflictHandler#REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER RESORAAH} + * conflict handler to be sure that, if all else is the same, the aligned version is chosen + * over the unaligned version. + *

+ * Success is the aligned version is chosen over the unaligned version. + */ @Test public void testResolveDataTypeNonStructConflict() throws Exception { DataTypeManager dtm = new StandAloneDataTypeManager("Test"); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemory.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemory.java index 17d6ec8604..440ad3b166 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemory.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/checksums/MyTestMemory.java @@ -27,11 +27,11 @@ import ghidra.program.model.mem.*; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; -class MyTestMemory extends AddressSet implements Memory { +public class MyTestMemory extends AddressSet implements Memory { byte[] myMemoryBytes; MemoryBlock myMemoryBlock; - MyTestMemory(byte[] bytes) { + public MyTestMemory(byte[] bytes) { super(); this.myMemoryBytes = bytes; AddressSpace space = new GenericAddressSpace("Mem", 32, AddressSpace.TYPE_RAM, 0); @@ -108,8 +108,7 @@ class MyTestMemory extends AddressSet implements Memory { @Override public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress, - long length, ByteMappingScheme byteMappingScheme, boolean overlay) - throws LockException, + long length, ByteMappingScheme byteMappingScheme, boolean overlay) throws LockException, MemoryConflictException, AddressOverflowException, IllegalArgumentException { throw new UnsupportedOperationException(); } diff --git a/Ghidra/Features/PDB/developer_scripts/DeveloperDumpAllTypesScript.java b/Ghidra/Features/PDB/developer_scripts/DeveloperDumpAllTypesScript.java new file mode 100644 index 0000000000..a38798ef98 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/DeveloperDumpAllTypesScript.java @@ -0,0 +1,108 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Text-dump all data types from the user-specified DataTypeManager to the user-specified file. +// +//@category Data Types +import java.io.File; +import java.io.FileWriter; +import java.util.Iterator; + +import docking.widgets.OptionDialog; +import ghidra.app.script.GhidraScript; +import ghidra.app.services.DataTypeManagerService; +import ghidra.app.util.ToolTipUtils; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.data.*; +import ghidra.util.HTMLUtilities; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; + +public class DeveloperDumpAllTypesScript extends GhidraScript { + + @Override + protected void run() throws Exception, CancelledException { + + DataTypeManager manager = userChooseDataTypeManager(); + if (manager == null) { + return; + } + + File dumpFile = askFile("Choose an output file", "OK"); + if (dumpFile == null) { + Msg.info(this, "Canceled execution due to no output file"); + return; + } + if (dumpFile.exists()) { + if (!askYesNo("Confirm Overwrite", "Overwrite file: " + dumpFile.getName())) { + Msg.info(this, "Operation canceled"); + return; + } + } + FileWriter fileWriter = new FileWriter(dumpFile); + + String message = "Outputting DataTypes from: " + manager.getName(); + + Iterator allDataTypes = manager.getAllDataTypes(); + while (allDataTypes.hasNext()) { + monitor.checkCanceled(); + DataType dataType = allDataTypes.next(); + DataTypePath dataTypePath = dataType.getDataTypePath(); + String pathString = dataTypePath.toString(); + String htmlString = ToolTipUtils.getToolTipText(dataType); + String plainString = HTMLUtilities.fromHTML(htmlString); + fileWriter.append(pathString); + fileWriter.append("\n"); + fileWriter.append(plainString); + fileWriter.append("\n"); + fileWriter.append("------------------------------------------------------------\n"); + } + fileWriter.close(); + + message = "Results located in: " + dumpFile.getAbsoluteFile(); + monitor.setMessage(message); + Msg.info(this, message); + } + + private DataTypeManager userChooseDataTypeManager() { + PluginTool tool = state.getTool(); + DataTypeManagerService service = tool.getService(DataTypeManagerService.class); + DataTypeManager[] dataTypeManagers = service.getDataTypeManagers(); + String names[] = new String[dataTypeManagers.length]; + String initialDtmChoice = names[0]; + try { + initialDtmChoice = currentProgram.getDataTypeManager().getName(); + } + catch (Exception e) { + // Ignore... assuming no program or dtm. + } + for (int i = 0; i < dataTypeManagers.length; i++) { + names[i] = dataTypeManagers[i].getName(); + } + String userChoice = + OptionDialog.showInputChoiceDialog(null, "Choose a Data Type Manager or Cancel", + "Choose", names, initialDtmChoice, OptionDialog.CANCEL_OPTION); + if (userChoice == null) { + return null; + } + for (int i = 0; i < dataTypeManagers.length; i++) { + if (names[i].contentEquals(userChoice)) { + return dataTypeManagers[i]; + } + } + return null; // should not reach this line. + } + +} diff --git a/Ghidra/Features/PDB/developer_scripts/DumpAllSymbolsDemangledScript.java b/Ghidra/Features/PDB/developer_scripts/DumpAllSymbolsDemangledScript.java new file mode 100644 index 0000000000..2645ab3a3d --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/DumpAllSymbolsDemangledScript.java @@ -0,0 +1,101 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Script for ghizard developer investigating template and ICF squashing. +// +//@category PDB +import java.io.*; + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.address.Address; +import ghidra.program.model.symbol.*; +import ghidra.util.Msg; +import mdemangler.*; +import mdemangler.object.MDObjectCPP; + +public class DumpAllSymbolsDemangledScript extends GhidraScript { + + @Override + public void run() throws Exception { + File dumpFile = askFile("Choose an output file", "OK"); + if (dumpFile == null) { + Msg.info(this, "Canceled execution due to no output file"); + return; + } + if (dumpFile.exists()) { + if (!askYesNo("Confirm Overwrite", "Overwrite file: " + dumpFile.getName())) { + Msg.info(this, "Operation canceled"); + return; + } + } + FileWriter fileWriter = new FileWriter(dumpFile); + BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); + + SymbolTable st = currentProgram.getSymbolTable(); + SymbolIterator it = st.getDefinedSymbols(); + + while (it.hasNext() && !monitor.isCancelled()) { + Symbol s = it.next(); + if (s.getSource() == SourceType.DEFAULT) { + continue; + } + + Address addr = s.getAddress(); + if (addr.isExternalAddress() || Address.NO_ADDRESS.equals(addr)) { + continue; + } + + String name = s.getName(); + String demangled = getDemangledString(name); + if (demangled != null && !demangled.isBlank()) { + name = demangled; + } + + bufferedWriter.append(addr + " " + name + "\n"); + } + bufferedWriter.close(); + } + + /** + * Gets a demangled string for the indicated mangled string. + * @param mangledString the mangled string to be decoded + * @return the associated demangled string + */ + private static String getDemangledString(String mangledString) { + MDMangGhidra demangler = new MDMangGhidra(); + try { + MDParsableItem parsableItem = demangler.demangle(mangledString, true); + if (parsableItem instanceof MDObjectCPP) { + MDObjectCPP mdObject = (MDObjectCPP) parsableItem; + return mdObject.getQualifiedName().toString(); + } +// if (parsableItem instanceof MDFunctionType) { +// MDFunctionType functionType = (MDFunctionType) parsableItem; +// return functionType.getName(); +// } +// if (parsableItem instanceof MDDataType) { +// MDDataType dataType = (MDDataType) parsableItem; +// return dataType.getName(); +// } + return parsableItem.toString(); + } + catch (MDException e) { + // Couldn't demangle. + Msg.info(null, e.getMessage()); + return null; + } + } + +} diff --git a/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpScript.java b/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpScript.java new file mode 100644 index 0000000000..614c218d4a --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/PdbDeveloperDumpScript.java @@ -0,0 +1,88 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Dump PDB information from AbstractPdb for PDB developer use. +// +//@category PDB + +import java.io.*; + +import ghidra.app.script.GhidraScript; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.util.Msg; + +public class PdbDeveloperDumpScript extends GhidraScript { + + @Override + protected void run() throws Exception { + File pdbFile = askFile("Choose a PDB file", "OK"); + if (pdbFile == null) { + Msg.info(this, "Canceled execution due to no input file"); + return; + } + if (!pdbFile.exists()) { + String message = pdbFile.getAbsolutePath() + " is not a valid file."; + Msg.info(this, message); + popup(message); + return; + } + String pdbFileName = pdbFile.getAbsolutePath(); + if (!pdbFileName.endsWith(".pdb") && !pdbFileName.endsWith(".PDB")) { + String message = "Aborting: Expected input file to have extension of type .pdb (got '" + + pdbFileName + "')."; + Msg.info(this, message); + popup(message); + return; + } + + File dumpFile = askFile("Choose an output file", "OK"); + if (dumpFile == null) { + Msg.info(this, "Canceled execution due to no output file"); + return; + } + if (dumpFile.exists()) { + if (!askYesNo("Confirm Overwrite", "Overwrite file: " + dumpFile.getName())) { + Msg.info(this, "Operation canceled"); + return; + } + } + + String message = "Processing PDB Dump of: " + pdbFileName; + monitor.setMessage(message); + Msg.info(this, message); + try (AbstractPdb pdb = PdbParser.parse(pdbFileName, new PdbReaderOptions(), monitor)) { + pdb.deserialize(monitor); + FileWriter fileWriter = new FileWriter(dumpFile); + BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); + outputHeaderMessage(bufferedWriter, pdbFileName); + pdb.dumpDirectory(bufferedWriter); + pdb.dumpSubStreams(bufferedWriter); + bufferedWriter.close(); + } + catch (IOException ioe) { + Msg.info(this, ioe.getMessage()); + popup(ioe.getMessage()); + } + message = "Results located in: " + dumpFile.getAbsoluteFile(); + monitor.setMessage(message); + Msg.info(this, message); + } + + private void outputHeaderMessage(BufferedWriter bufferedWriter, String name) throws Exception { + bufferedWriter.append(getClass().getSimpleName() + " dump of: " + name + + "\nWARNING: FORMAT SUBJECT TO CHANGE WITHOUT NOTICE--DO NOT PARSE\n\n"); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/Pdb2Analyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/Pdb2Analyzer.java new file mode 100644 index 0000000000..aa633d7f5d --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/Pdb2Analyzer.java @@ -0,0 +1,590 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.analysis; + +import java.io.File; +import java.io.IOException; +import java.util.Date; + +import docking.widgets.OkDialog; +import docking.widgets.OptionDialog; +import ghidra.app.services.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.app.util.opinion.PeLoader; +import ghidra.app.util.pdb.PdbLocatorSelector; +import ghidra.app.util.pdb.PdbProgramAttributes; +import ghidra.app.util.pdb.pdbapplicator.*; +import ghidra.framework.Application; +import ghidra.framework.options.OptionType; +import ghidra.framework.options.Options; +import ghidra.framework.preferences.Preferences; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.data.CharsetInfo; +import ghidra.program.model.listing.Program; +import ghidra.util.Msg; +import ghidra.util.SystemUtilities; +import ghidra.util.bean.opteditor.OptionsVetoException; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +// TODO: Need to refactor packaging/classes/methods associated with "Features PDB" that are +// taken and used here. Need to make them available to both previous and this new analyzers +// in their own special ways. Make utility classes that are better split/organized. Some +// items are also used in other plugins/loaders (e.g, PdbException). +// For example, we do not use the XML format here. The code that was taken was strewn across +// classes and should be reorganized. For example, why is PdbParserNEW in control of the logic +// of where a PDB file might be found? + +/** + * PDB Universal Reader/Analyzer. Uses raw PDB files (not XML-converted PDBs). Attempts to + * apply the information to a program. + */ +public class Pdb2Analyzer extends AbstractAnalyzer { + + // Developer turn on/off options that are in still in development. + private static final boolean developerMode = false; + + //============================================================================================== + private static final String NAME = "PDB Universal Reader/Analyzer"; + private static final String DESCRIPTION = + "[PDB EVOLUTIONARY PROTOTYPE V1] [OPTIONS MAY CHANGE]\n" + + "Platform-indepent PDB analysis\n" + + "(No XML. Will not run with DIA-based PDB Analyzer.)"; + + private final static String PDB_STORAGE_PROPERTY = "PDB Storage Directory"; + // TODO; look into what we can do with the following (old analyzer says this is a "thing") + //public final static File SPECIAL_PDB_LOCATION = new File("C:/WINDOWS/Symbols"); + + //============================================================================================== + // Force-load a PDB file. + private static final String OPTION_NAME_DO_FORCELOAD = "Do Force-Load"; + private static final String OPTION_DESCRIPTION_DO_FORCELOAD = + "If checked, uses the 'Force Load' file without validation."; + private boolean doForceLoad = false; + + // The file to force-load. + private static final String OPTION_NAME_FORCELOAD_FILE = "Force-Load FilePath"; + private static final String OPTION_DESCRIPTION_FORCELOAD_FILE = + "This file is force-loaded if the '" + OPTION_NAME_DO_FORCELOAD + "' option is checked"; + private File forceLoadFile = null; + + // Symbol Repository Path. + private static final String OPTION_NAME_SYMBOLPATH = "Symbol Repository Path"; + private static final String OPTION_DESCRIPTION_SYMBOLPATH = + "Directory path to root of Microsoft Symbol Repository Directory"; + private File symbolsRepositoryPath = null; // value set in constructor + private File defaultSymbolsRepositoryPath = Application.getUserTempDirectory(); + + // Include the PE-Header-Specified PDB path for searching for appropriate PDB file. + private static final String OPTION_NAME_INCLUDE_PE_PDB_PATH = + "Unsafe: Include PE PDB Path in PDB Search"; + private static final String OPTION_DESCRIPTION_INCLUDE_PE_PDB_PATH = + "If checked, specifically searching for PDB in PE-Header-Specified Location."; + private boolean includePeSpecifiedPdbPath = false; + + //============================================================================================== + // Logging options + //============================================================================================== + // Perform logging of PDB information for debugging/development. + // NOTE: This logging mechanism is not intended to live the full life of this tool, but to + // aid in getting feedback from the field during its early development. + private static final String OPTION_NAME_PDB_READER_ANALYZER_LOGGING = + "[PDB Reader/Analyzer Debug Logging]"; + private static final String OPTION_DESCRIPTION_PDB_READER_ANALYZER_LOGGING = + "If checked, logs information to the pdb.analyzer.log file for debug/development."; + private boolean pdbLogging = false; + + //============================================================================================== + // PdbReader options + //============================================================================================== + // Sets the one-byte Charset to be used for PDB processing. + // NOTE: This "Option" is not intended as a permanent part of this analyzer. Should be + // replaced by target-specific Charset. + private static final String OPTION_NAME_ONE_BYTE_CHARSET_NAME = "PDB One-Byte Charset Name"; + private static final String OPTION_DESCRIPTION_ONE_BYTE_CHARSET_NAME = + "Charset used for processing of one-byte (or multi) encoded Strings: " + + PdbReaderOptions.getOneByteCharsetNames(); + private String oneByteCharsetName = CharsetInfo.UTF8; + + // Sets the wchar_t Charset to be used for PDB processing. + // NOTE: This "Option" is not intended as a permanent part of this analyzer. Should be + // replaced by target-program-specific Charset. + private static final String OPTION_NAME_WCHAR_CHARSET_NAME = "PDB Wchar_t Charset Name"; + private static final String OPTION_DESCRIPTION_WCHAR_CHARSET_NAME = + "Charset used for processing of wchar_t encoded Strings: " + + PdbReaderOptions.getTwoByteCharsetNames(); + private String wideCharCharsetName = CharsetInfo.UTF16; + + //============================================================================================== + // PdbApplicator options + //============================================================================================== + // Apply Data Types Only. + private static final String OPTION_NAME_APPLY_DATA_TYPES_ONLY = "Apply Data Types Only"; + private static final String OPTION_DESCRIPTION_APPLY_DATA_TYPES_ONLY = + "If checked, only applies data types to program."; + private boolean applyDataTypesOnly; + + // Apply Public Symbols Only. + private static final String OPTION_NAME_PUBLIC_SYMBOLS_ONLY = "Apply Public Symbols Only"; + private static final String OPTION_DESCRIPTION_PUBLIC_SYMBOLS_ONLY = + "If checked, only applies public symbols to program. Does not apply data types."; + private boolean applyPublicSymbolsOnly; + + // Apply Code Block Comments. + private static final String OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS = + "Apply Code Scope Block Comments"; + private static final String OPTION_DESCRIPTION_APPLY_CODE_SCOPE_BLOCK_COMMENTS = + "If checked, pre/post-comments will be applied when code scope blocks are specified."; + private boolean applyCodeScopeBlockComments; + + // Apply Instruction Labels information. + private static final String OPTION_NAME_APPLY_INSTRUCTION_LABELS = "Apply Instruction Labels"; + private static final String OPTION_DESCRIPTION_APPLY_INSTRUCTION_LABELS = + "If checked, labels associated with instructions will be applied."; + private boolean applyInstructionLabels; + + // Attempt to map address using existing mangled symbols. + private static final String OPTION_NAME_ADDRESS_REMAP = "Address Remap Using Existing Symbols"; + private static final String OPTION_DESCRIPTION_ADDRESS_REMAP = + "If checked, attempts to remap address to those matching existing public symbols."; + private boolean remapAddressUsingExistingPublicMangledSymbols; + + // Allow a mangled symbol to be demoted from being a primary symbol if another symbol and + // associated explicit data type will be laid down at the location. This option exists + // because we expect the PDB explicit data type will be more accurate than trying to + // have the demangler lay down the data type. + private static final String OPTION_NAME_ALLOW_DEMOTE_MANGLED_PRIMARY = + "Allow demote mangled symbol from primary"; + private static final String OPTION_DESCRIPTION_ALLOW_DEMOTE_MANGLED_PRIMARY = + "If checked, allows a mangled symbol to be demoted from primary if a possibly " + + "better data type can be laid down with a nonmangled symbol."; + private boolean allowDemotePrimaryMangledSymbol; + + // Apply Function Variables + private static final String OPTION_NAME_APPLY_FUNCTION_VARIABLES = "Apply Function Variables"; + private static final String OPTION_DESCRIPTION_APPLY_FUNCTION_VARIABLES = + "If checked, attempts to apply function parameters and local variables for program functions."; + private boolean applyFunctionVariables; + + // Sets the composite layout mode. + // Legacy + // - similar to existing DIA-based PDB Analyzer, only placing current composite direct + // members (none from parent classes. + // Warning: the remaining experimental layout modes may not be kept and are not guaranteed + // to result in data types that will be compatible with future Ghidra releases: + // Complex with Basic Fallback + // - Performs Complex layout, but if the current class has no parent classes, it will not + // encapsulate the current class's 'direct' members. + // Simple + // - Performs Complex layout, except in rare instances where , so in most cases is the same + // as 'Complex with Basic Fallback' layout. + // Complex + // - Puts all current class members and 'direct' parents' 'direct' components into an + // encapsulating 'direct' container + private static final String OPTION_NAME_COMPOSITE_LAYOUT_MODE = "Composite Layout Mode"; + private static final String OPTION_DESCRIPTION_COMPOSITE_LAYOUT_MODE = + "Legacy mode like original PDB Analyzer. Warning: other modes have no compatibility" + + " guarantee with future Ghidra releases or minor PDB Analyzer changes"; + private CompositeLayoutMode compositeLayoutMode; + + //============================================================================================== + // Additional instance data + //============================================================================================== + private AbstractPdb myPdb = null; + private PdbReaderOptions pdbReaderOptions; + private PdbApplicatorOptions pdbApplicatorOptions; + private MessageLog messageLog = null; + + //============================================================================================== + //============================================================================================== + public Pdb2Analyzer() { + super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); + setPrototype(); + // false for now; after proven... then TODO: true always + setDefaultEnablement(false); + // or... + // false for now if on Windows; after proven... then TODO: true always + // setDefaultEnablement(!onWindows); + setPriority(AnalysisPriority.FORMAT_ANALYSIS.after()); + setSupportsOneTimeAnalysis(); + + String pdbStorageLocation = Preferences.getProperty(PDB_STORAGE_PROPERTY, null, true); + if (pdbStorageLocation != null) { + symbolsRepositoryPath = new File(pdbStorageLocation); + } + else { + symbolsRepositoryPath = defaultSymbolsRepositoryPath; + } + if (!symbolsRepositoryPath.isDirectory()) { + symbolsRepositoryPath = new File(File.separator); + } + pdbStorageLocation = symbolsRepositoryPath.getAbsolutePath(); + forceLoadFile = new File(pdbStorageLocation + File.separator + "sample.pdb"); + + pdbReaderOptions = new PdbReaderOptions(); + pdbApplicatorOptions = new PdbApplicatorOptions(); + } + + @Override + public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) + throws CancelledException { + + messageLog = log; + // TODO: + // Work on use cases... + // Code for checking if the PDB is already loaded (... assumes it was analyzed as well). + // Need different logic... perhaps we could have multiple PDBs loaded already and need + // to decide if any of those is the "correct" one or even look for another one. + // Probably still need to have a loader separate from the loader/analyzer, but then have + // the ability to analyze (apply) any given already-loaded PDB to the program. A PDB + // loader should probably be able to load an optionally apply data types to its own + // category manager. Question would be if/how we "might" try to resolve any of these + // against the "main" category data types. + + if (oldPdbAnalyzerEnabled(program)) { + log.appendMsg(getName(), "Stopped: Cannot run with other PDB Analyzer enabled"); + return false; + } + + PdbProgramAttributes programAttributes = new PdbProgramAttributes(program); + if (failMissingFilename(programAttributes, log) || + failMissingAttributes(programAttributes, log)) { + return true; + } + + String pdbFilename; + if (doForceLoad) { + pdbFilename = forceLoadFile.getAbsolutePath(); + } + else { + PdbLocatorSelector locator = new PdbLocatorSelector(symbolsRepositoryPath); + pdbFilename = + locator.findPdb(program, programAttributes, !SystemUtilities.isInHeadlessMode(), + includePeSpecifiedPdbPath, monitor, log, getName()); + if (pdbFilename == null) { + return false; + } + } + Msg.info(this, "Using PDB: " + pdbFilename); + + PdbLog.message( + "================================================================================"); + PdbLog.message(new Date(System.currentTimeMillis()).toString() + "\n"); + PdbLog.message("Ghidra Version: " + Application.getApplicationVersion()); + PdbLog.message(NAME); + PdbLog.message(DESCRIPTION); + PdbLog.message("PDB Filename: " + pdbFilename + "\n"); + + try (AbstractPdb pdb = PdbParser.parse(pdbFilename, pdbReaderOptions, monitor)) { + myPdb = pdb; + monitor.setMessage("PDB: Parsing " + pdbFilename + "..."); + pdb.deserialize(monitor); + PdbApplicator applicator = new PdbApplicator(pdbFilename, myPdb); + applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(), + pdbApplicatorOptions, monitor, log); + } + catch (PdbException e) { + String message = "Issue processing PDB file: " + pdbFilename + + ". Detailed issues may follow:\n" + e.toString(); + log.appendMsg(getName(), message); + return false; + } + catch (IOException e) { + String message = "Issue processing PDB file: " + pdbFilename + + ". Detailed issues may follow:\n" + e.toString(); + log.appendMsg(getName(), message); + return false; + } + + return true; + } + + // TODO: I changed this method from what was lifted in the old code. I check for null string + // and I also check for MSCOFF_NAME (TODO: check on the validity of this!!!). Also, changed + // the comparison to a substring search from a .equals). + @Override + public boolean canAnalyze(Program program) { + String executableFormat = program.getExecutableFormat(); + return executableFormat != null && (executableFormat.indexOf(PeLoader.PE_NAME) != -1); + // TODO: Check for MSCOFF_NAME. Initial investigation shows that the .debug$T section of + // the MSCOFF (*.obj) file has type records and the .debug$S section has symbol records. + // More than that, in at least one instance, there has been a TypeServer2MsType type + // record that give the GUID, age, and name of the PDB file associated with the MSCOFF + // file. At this point in time, these two sections of the MSCOFF are read (header and + // raw data), but we do not interpret these sections any further. Suggest that we "might" + // want to parse some of these records at load time? Maybe not. We could, at analysis + // time, add the ability to process these two sections (as part of analysis (though we + // will not be aware of a PDB file yet), and upon discovery of a TypeServer2MsType (or + // perhaps other?), proceed to find the file (if possible) and also process that file. + // We posit that if a record indicates a separate PDB for the types (Note: MSFT indicates + // that only data types will be found in an MSCOFF PDB file), then that will likely be + // the only record in the .debug$T section. + // TODO: If the MSCOFF file is located in a MSCOFF ARCHIVE (*.lib), there can be a PDB + // associated with the archive. We currently do not pass on this association of the + // PDB archive to each underlying MSCOFF file. Moreover, we believe that we are not + // currently discovering the associated MSCOFF ARCHIVE PDB file when processing the + // MSCOFF ARCHIVE. Initial indication is that each MSCOFF within the archive will have + // the PDB file that it needs listed, even if redundant for each MSCOFF within the + // archive. +// return executableFormat != null && (executableFormat.indexOf(PeLoader.PE_NAME) != -1 || +// executableFormat.indexOf(MSCoffLoader.MSCOFF_NAME) != -1); + } + + @Override + public void registerOptions(Options options, Program program) { + // TODO: keeping around while still developing, but eventually delete these. +// options.removeOption(OPTION_NAME_DO_FORCELOAD); +// options.removeOption(OPTION_NAME_FORCELOAD_FILE); +// options.removeOption(OPTION_NAME_INCLUDE_PE_PDB_PATH); +// options.removeOption(OPTION_NAME_PDB_READER_ANALYZER_LOGGING); +// options.removeOption(OPTION_NAME_APPLY_INSTRUCTION_LABELS); +// options.removeOption(OPTION_NAME_SYMBOLPATH); +// options.removeOption(OPTION_NAME_ONE_BYTE_CHARSET_NAME); +// options.removeOption(OPTION_NAME_WCHAR_CHARSET_NAME); +// options.removeOption("Analyzers.PDB Universal Reader/Analyzer.Symbol Repository Path"); + + // PDB file location information + options.registerOption(OPTION_NAME_DO_FORCELOAD, doForceLoad, null, + OPTION_DESCRIPTION_DO_FORCELOAD); + options.registerOption(OPTION_NAME_FORCELOAD_FILE, OptionType.FILE_TYPE, forceLoadFile, + null, OPTION_DESCRIPTION_FORCELOAD_FILE); + options.registerOption(OPTION_NAME_SYMBOLPATH, OptionType.FILE_TYPE, symbolsRepositoryPath, + null, OPTION_DESCRIPTION_SYMBOLPATH); + options.registerOption(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath, null, + OPTION_DESCRIPTION_INCLUDE_PE_PDB_PATH); + + // PdbReaderOptions + getPdbReaderOptions(); + options.registerOption(OPTION_NAME_PDB_READER_ANALYZER_LOGGING, pdbLogging, null, + OPTION_DESCRIPTION_PDB_READER_ANALYZER_LOGGING); + options.registerOption(OPTION_NAME_ONE_BYTE_CHARSET_NAME, oneByteCharsetName, null, + OPTION_DESCRIPTION_ONE_BYTE_CHARSET_NAME); + options.registerOption(OPTION_NAME_WCHAR_CHARSET_NAME, wideCharCharsetName, null, + OPTION_DESCRIPTION_WCHAR_CHARSET_NAME); + + // PdbApplicatorOptions + getPdbApplicatorOptions(); + options.registerOption(OPTION_NAME_APPLY_DATA_TYPES_ONLY, applyDataTypesOnly, null, + OPTION_DESCRIPTION_APPLY_DATA_TYPES_ONLY); + options.registerOption(OPTION_NAME_PUBLIC_SYMBOLS_ONLY, applyPublicSymbolsOnly, null, + OPTION_DESCRIPTION_PUBLIC_SYMBOLS_ONLY); + options.registerOption(OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, + applyCodeScopeBlockComments, null, OPTION_DESCRIPTION_APPLY_CODE_SCOPE_BLOCK_COMMENTS); + if (developerMode) { + // Mechanism to apply instruction labels is not yet implemented-> does nothing + options.registerOption(OPTION_NAME_APPLY_INSTRUCTION_LABELS, applyInstructionLabels, + null, OPTION_DESCRIPTION_APPLY_INSTRUCTION_LABELS); + options.registerOption(OPTION_NAME_ADDRESS_REMAP, + remapAddressUsingExistingPublicMangledSymbols, null, + OPTION_DESCRIPTION_ADDRESS_REMAP); + options.registerOption(OPTION_NAME_ALLOW_DEMOTE_MANGLED_PRIMARY, + allowDemotePrimaryMangledSymbol, null, + OPTION_DESCRIPTION_ALLOW_DEMOTE_MANGLED_PRIMARY); + options.registerOption(OPTION_NAME_APPLY_FUNCTION_VARIABLES, applyFunctionVariables, + null, OPTION_DESCRIPTION_APPLY_FUNCTION_VARIABLES); + options.registerOption(OPTION_NAME_COMPOSITE_LAYOUT_MODE, compositeLayoutMode, null, + OPTION_DESCRIPTION_COMPOSITE_LAYOUT_MODE); + } + } + + @Override + public void optionsChanged(Options options, Program program) { + + // This test can go away once this new analyzer completely replaces the old analyzer. + if (!SystemUtilities.isInHeadlessMode() && oldPdbAnalyzerEnabled(program) && + thisPdbAnalyzerEnabled(program)) { + OkDialog.show("Warning", + "Cannot use PDB Universal Analyzer and DIA-based PDB Analyzer at the same time"); + } + + doForceLoad = options.getBoolean(OPTION_NAME_DO_FORCELOAD, doForceLoad); + + File pdbFile = options.getFile(OPTION_NAME_FORCELOAD_FILE, forceLoadFile); + if (doForceLoad) { + if (pdbFile == null) { + throw new OptionsVetoException("Force-load file field is missing"); + } + else if (!confirmFile(pdbFile)) { + throw new OptionsVetoException(pdbFile + " force-load file does not exist"); + } + } + forceLoadFile = pdbFile; + + File path = options.getFile(OPTION_NAME_SYMBOLPATH, symbolsRepositoryPath); + if (path == null) { + throw new OptionsVetoException("Symbol Path field is missing"); + } + else if (!confirmDirectory(path)) { + throw new OptionsVetoException(path + " is not a valid directory"); + } + symbolsRepositoryPath = path; + + includePeSpecifiedPdbPath = + options.getBoolean(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath); + + pdbLogging = options.getBoolean(OPTION_NAME_PDB_READER_ANALYZER_LOGGING, pdbLogging); + setPdbLogging(); + + // PdbReaderOptions + oneByteCharsetName = + options.getString(OPTION_NAME_ONE_BYTE_CHARSET_NAME, oneByteCharsetName); + wideCharCharsetName = + options.getString(OPTION_NAME_WCHAR_CHARSET_NAME, wideCharCharsetName); + setPdbReaderOptions(); + + // PdbApplicatorOptions + applyDataTypesOnly = + options.getBoolean(OPTION_NAME_APPLY_DATA_TYPES_ONLY, applyDataTypesOnly); + applyPublicSymbolsOnly = + options.getBoolean(OPTION_NAME_PUBLIC_SYMBOLS_ONLY, applyPublicSymbolsOnly); + applyCodeScopeBlockComments = options.getBoolean( + OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, applyCodeScopeBlockComments); + if (developerMode) { + // Mechanism to apply instruction labels is not yet implemented-> does nothing + applyInstructionLabels = + options.getBoolean(OPTION_NAME_APPLY_INSTRUCTION_LABELS, applyInstructionLabels); + remapAddressUsingExistingPublicMangledSymbols = options.getBoolean( + OPTION_NAME_ADDRESS_REMAP, remapAddressUsingExistingPublicMangledSymbols); + allowDemotePrimaryMangledSymbol = options.getBoolean( + OPTION_NAME_ALLOW_DEMOTE_MANGLED_PRIMARY, allowDemotePrimaryMangledSymbol); + applyFunctionVariables = + options.getBoolean(OPTION_NAME_APPLY_FUNCTION_VARIABLES, applyFunctionVariables); + compositeLayoutMode = + options.getEnum(OPTION_NAME_COMPOSITE_LAYOUT_MODE, compositeLayoutMode); + } + setPdbApplicatorOptions(); + } + + //============================================================================================== + private boolean oldPdbAnalyzerEnabled(Program program) { + String oldPdbNAME = "PDB"; + // This assert is just to catch us if we change the new NAME to what the old name is + // without first eliminating the call to this method and this method altogether. + assert !NAME.contentEquals(oldPdbNAME); + Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES); + // Don't have access to ghidra.app.plugin.core.analysis.PdbAnalyzer.NAME so using string. + boolean isPdbEnabled = analysisOptions.getBoolean(oldPdbNAME, false); + return isPdbEnabled; + } + + private boolean thisPdbAnalyzerEnabled(Program program) { + Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES); + // Don't have access to ghidra.app.plugin.core.analysis.PdbAnalyzer.NAME so using string. + boolean isPdbEnabled = analysisOptions.getBoolean(NAME, false); + return isPdbEnabled; + } + + private boolean failMissingFilename(PdbProgramAttributes attributes, MessageLog log) { + if (attributes.getPdbFile() == null || attributes.getPdbFile().isEmpty()) { + String message = "No PdbFile specified in program... Skipping PDB processing."; + log.appendMsg(getName(), message); + log.setStatus(message); + return true; + } + return false; + } + + private boolean failMissingAttributes(PdbProgramAttributes attributes, MessageLog log) { + // RSDS version should only have GUID; non-RSDS version should only have Signature. + String warning; + if ("RSDS".equals(attributes.getPdbVersion())) { + if (attributes.getPdbGuid() != null) { + return false; // Don't fail. + } + warning = "No Program GUID to match with PDB."; + } + else { + if (attributes.getPdbSignature() != null) { + return false; // Don't fail. + } + warning = "No Program Signature to match with PDB."; + } + String message; + if (!SystemUtilities.isInHeadlessMode()) { + int option = OptionDialog.showYesNoDialog(null, "Continue Loading PDB?", + warning + "\n " + "\nContinue anyway?" + "\n " + + "\nPlease note: Invalid disassembly may be produced!"); + if (option == OptionDialog.OPTION_ONE) { + message = warning + ".. Continuing PDB processing."; + log.appendMsg(getName(), message); + log.setStatus(message); + return false; + } + } + message = warning + ".. Skipping PDB processing."; + log.appendMsg(getName(), message); + log.setStatus(message); + return true; + } + + private void setPdbLogging() { + try { + PdbLog.setEnabled(pdbLogging); + } + catch (IOException e) { + // Probably could not open the file. + if (messageLog != null) { + messageLog.appendException(e); + } + } + } + + private void getPdbReaderOptions() { + oneByteCharsetName = pdbReaderOptions.getOneByteCharsetName(); + wideCharCharsetName = pdbReaderOptions.getTwoByteCharsetName(); + } + + private void setPdbReaderOptions() { + pdbReaderOptions.setOneByteCharsetForName(oneByteCharsetName); + pdbReaderOptions.setWideCharCharsetForName(wideCharCharsetName); + } + + private void getPdbApplicatorOptions() { + applyCodeScopeBlockComments = pdbApplicatorOptions.applyCodeScopeBlockComments(); + applyDataTypesOnly = pdbApplicatorOptions.applyDataTypesOnly(); + applyPublicSymbolsOnly = pdbApplicatorOptions.applyPublicSymbolsOnly(); + + applyInstructionLabels = pdbApplicatorOptions.applyInstructionLabels(); + remapAddressUsingExistingPublicMangledSymbols = + pdbApplicatorOptions.remapAddressUsingExistingPublicMangledSymbols(); + allowDemotePrimaryMangledSymbol = pdbApplicatorOptions.allowDemotePrimaryMangledSymbol(); + applyFunctionVariables = pdbApplicatorOptions.applyFunctionVariables(); + compositeLayoutMode = pdbApplicatorOptions.getCompositeLayoutMode(); + } + + private void setPdbApplicatorOptions() { + pdbApplicatorOptions.setApplyDataTypesOnly(applyDataTypesOnly); + pdbApplicatorOptions.setApplyPublicSymbolsOnly(applyPublicSymbolsOnly); + + pdbApplicatorOptions.setApplyCodeScopeBlockComments(applyCodeScopeBlockComments); + pdbApplicatorOptions.setApplyInstructionLabels(applyInstructionLabels); + pdbApplicatorOptions.setRemapAddressUsingExistingPublicMangledSymbols( + remapAddressUsingExistingPublicMangledSymbols); + pdbApplicatorOptions.setAllowDemotePrimaryMangledSymbol(allowDemotePrimaryMangledSymbol); + pdbApplicatorOptions.setApplyFunctionVariables(applyFunctionVariables); + pdbApplicatorOptions.setCompositeLayoutMode(compositeLayoutMode); + } + + private boolean confirmDirectory(File path) { + return path.isDirectory(); + } + + private boolean confirmFile(File path) { + return path.isFile(); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java index 5f6eb0c558..c16df3987d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java @@ -75,6 +75,7 @@ public class PdbAnalyzer extends AbstractAnalyzer { if (pdb == null) { return false; } + Msg.info(this, "Using PDB: " + pdb.getAbsolutePath()); AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program); return parsePdb(pdb, program, mgr, monitor, log); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java index d140f989e9..138bbe65e1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/DefaultCompositeMember.java @@ -35,7 +35,7 @@ import ghidra.util.task.TaskMonitor; * Container members are characterized by a null data-type name, zero length, and will be * identified as either a structure or union. */ -class DefaultCompositeMember extends CompositeMember { +public class DefaultCompositeMember extends CompositeMember { private static int MAX_CONSTRUCTION_DEPTH = 20; @@ -1150,7 +1150,7 @@ class DefaultCompositeMember extends CompositeMember { * @return true if members successfully added to composite * @throws CancelledException if monitor is cancelled */ - static boolean applyDataTypeMembers(Composite composite, boolean isClass, + public static boolean applyDataTypeMembers(Composite composite, boolean isClass, int preferredCompositeSize, List members, Consumer errorConsumer, TaskMonitor monitor) throws CancelledException { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbBitField.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbBitField.java index 4ef5a5a559..96e4283250 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbBitField.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbBitField.java @@ -22,7 +22,7 @@ import ghidra.util.exception.AssertException; * PdbBitField provides ability to hang onto bitfield as a datatype. * This will be transformed to a normal BitFieldDataType when cloned. */ -class PdbBitField extends BitFieldDataType { +public class PdbBitField extends BitFieldDataType { private int bitOffsetWithinBaseType; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbMember.java index 30463ad076..3d5a8d4386 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbMember.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbMember.java @@ -21,7 +21,7 @@ import ghidra.util.exception.CancelledException; * PdbMember convey PDB member information used for datatype * reconstruction. */ -abstract class PdbMember { +public abstract class PdbMember { final String memberName; final String memberDataTypeName; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbParser.java index 495c603dcf..4253c005e8 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbParser.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbParser.java @@ -28,6 +28,7 @@ import ghidra.app.util.NamespaceUtils; import ghidra.app.util.SymbolPath; import ghidra.app.util.importer.LibrarySearchPathManager; import ghidra.app.util.importer.MessageLog; +import ghidra.app.util.pdb.PdbProgramAttributes; import ghidra.framework.*; import ghidra.framework.options.Options; import ghidra.program.model.address.Address; @@ -739,6 +740,7 @@ public class PdbParser { EnumDataType createEnum(String name, int length) { SymbolPath path = new SymbolPath(name); + // Ghidra does not like size of zero. length = Integer.max(length, 1); return new EnumDataType(getCategory(path.getParent(), true), path.getName(), length, dataMgr); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/WrappedDataType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/WrappedDataType.java index 31ce7ffcda..db5fd63789 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/WrappedDataType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/WrappedDataType.java @@ -40,7 +40,7 @@ public class WrappedDataType { * @param isNoType if true wrapped type corresponds to NoType as * used by PDB forced to have a size of 1-byte. */ - protected WrappedDataType(DataType dataType, boolean isZeroLengthArray, boolean isNoType) { + public WrappedDataType(DataType dataType, boolean isZeroLengthArray, boolean isNoType) { this.dataType = dataType; this.isZeroLengthArray = isZeroLengthArray; this.isNoType = isNoType; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbReaderOptions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbReaderOptions.java index 564bc87d92..62ce050892 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbReaderOptions.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbReaderOptions.java @@ -41,8 +41,6 @@ public class PdbReaderOptions extends Exception { private Charset oneByteCharset; private Charset twoByteCharset; - private boolean debug; - /** * Constructor. */ @@ -113,6 +111,14 @@ public class PdbReaderOptions extends Exception { return twoByteCharsetName; } + /** + * Returns the name of the Wchar Charset in use for PDB processing. + * @return the name of the Wchar Charset. + */ + public String getWideCharCharsetName() { + return twoByteCharsetName; + } + /** * Returns the one-byte Charset in use for PDB processing. * @return the Charset. @@ -130,21 +136,11 @@ public class PdbReaderOptions extends Exception { } /** - * Enable/disable developmental debug. - * @param debug {@code true} to turn debug on; default is {@code false}. - * @return this, so options can be daisy-chained. + * Returns the Wchar Charset in use for PDB processing. + * @return the Wchar Charset. */ - public PdbReaderOptions setDebug(boolean debug) { - this.debug = debug; - return this; - } - - /** - * Returns true if debug is "on." - * @return {@code true} if debug is "on." - */ - public boolean isDebug() { - return debug; + public Charset getWideCharCharset() { + return twoByteCharset; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeParser.java index 9587b509b7..2464139f43 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeParser.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/TypeParser.java @@ -18,7 +18,6 @@ package ghidra.app.util.bin.format.pdb2.pdbreader; import java.util.Objects; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; -import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; /** diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SeparatedCodeFromCompilerSupportMsSymbol.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SeparatedCodeFromCompilerSupportMsSymbol.java index 19e8e602b3..f2f4109d65 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SeparatedCodeFromCompilerSupportMsSymbol.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SeparatedCodeFromCompilerSupportMsSymbol.java @@ -23,7 +23,8 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.*; * Note: we do not necessarily understand each of these symbol type classes. Refer to the * base class for more information. */ -public class SeparatedCodeFromCompilerSupportMsSymbol extends AbstractMsSymbol { +public class SeparatedCodeFromCompilerSupportMsSymbol extends AbstractMsSymbol + implements AddressMsSymbol { public static final int PDB_ID = 0x1132; @@ -78,6 +79,72 @@ public class SeparatedCodeFromCompilerSupportMsSymbol extends AbstractMsSymbol { return "SEPCODE"; } + /** + * Returns the parent pointer. + * @return Parent pointer. + */ + public long getParentPointer() { + return parentPointer; + } + + /** + * Returns the end pointer. + * @return End pointer. + */ + public long getEndPointer() { + return endPointer; + } + + /** + * Returns the block length. + * @return Block length. + */ + public long getBlockLength() { + return blockLength; + } + + /** + * Returns the indication of if is lexical scope. + * @return {@code true} if is lexical scope. + */ + public boolean isLexicalScope() { + return isLexicalScope; + } + + /** + * Returns the indication of if returns to parent. + * @return {@code true} if returns to parent. + */ + public boolean returnsToParent() { + return returnsToParent; + } + + @Override + public long getOffset() { + return offset; + } + + /** + * Returns the parent offset. + * @return Parent offset. + */ + public long getOffsetParent() { + return offsetParent; + } + + @Override + public int getSegment() { + return section; + } + + /** + * Returns the parent segment. + * @return Parent segment. + */ + public long getSegmentParent() { + return sectionParent; + } + /** * Internal method that breaks out the flag values from the aggregate integral type. * @param flagsIn {@code long} containing unsigned int value. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategoryUtils.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategoryUtils.java new file mode 100644 index 0000000000..346d3717dd --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategoryUtils.java @@ -0,0 +1,211 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb; + +import java.util.*; + +import ghidra.app.util.SymbolPath; +import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractDatabaseInterface; +import ghidra.program.model.data.Category; +import ghidra.program.model.data.CategoryPath; + +/** + * Sets up PDB base {@link CategoryPath} information for the PDB file and provides + * {@link CategoryPath CategoryPaths} based on {@link SymbolPath SymbolPaths}, name lists, and + * qualified namespace strings. Also maintains the state of the active Module {@link CategoryPath} + * while parsing a PDB and the count (state) of anonymous functions for their creation within + * the particular PDB's {@link Category}. + */ +public class PdbCategoryUtils { + + private CategoryPath pdbRootCategory; + private CategoryPath pdbUncategorizedCategory; + private CategoryPath anonymousFunctionsCategory; + private CategoryPath anonymousTypesCategory; + private CategoryPath baseModuleTypedefsCategory; + private List typedefCategories = new ArrayList<>(); + + private int anonymousFunctionCount; + + //============================================================================================== + // NOTE: a TODO could be to add optional GUID and AGE values. This could be as sub-categories + // or combined with the file name. This could be helpful when allowing multiple PDBs to be + // loaded (at least their data types). + /** + * Constructor + * @param pdbCategoryName pathname of the PDB file that this category represents. + * @param moduleNames module names + */ + public PdbCategoryUtils(String pdbCategoryName, List moduleNames) { + Objects.requireNonNull(pdbCategoryName, "pdbCategoryName cannot be null"); + + pdbRootCategory = new CategoryPath(CategoryPath.ROOT, pdbCategoryName); + + pdbUncategorizedCategory = new CategoryPath(pdbRootCategory, "_UNCATEGORIZED_"); + + setTypedefCategoryPaths(moduleNames); + + anonymousFunctionsCategory = new CategoryPath(pdbRootCategory, "!_anon_funcs_"); + anonymousFunctionCount = 0; + + anonymousTypesCategory = new CategoryPath(pdbRootCategory, "!_anon_types_"); + } + + /** + * Get root CategoryPath for the PDB. + * @return the root CategoryPath. + */ + public CategoryPath getRootCategoryPath() { + return pdbRootCategory; + } + + /** + * Get uncategorized CategoryPath for the PDB. + * @return the uncategorized CategoryPath. + */ + public CategoryPath getUnCategorizedCategoryPath() { + return pdbUncategorizedCategory; + } + + private void setTypedefCategoryPaths(List moduleNames) { + baseModuleTypedefsCategory = new CategoryPath(pdbRootCategory, "!_module_typedefs_"); + // non-module typedefs go with all other global types, not in + // baseModuleTypedefsCategory. + typedefCategories.add(pdbRootCategory); + for (String name : moduleNames) { + CategoryPath categoryPath = (name == null) ? baseModuleTypedefsCategory + : new CategoryPath(baseModuleTypedefsCategory, name); + typedefCategories.add(categoryPath); + } + } + +// /** +// * Get the name with any namespace stripped. +// * @param name Name with optional namespace prefix. +// * @return Name without namespace prefix. +// */ +// public String stripNamespace(String name) { +// int index = name.lastIndexOf(Namespace.DELIMITER); +// if (index <= 0) { +// return name; +// } +// return name.substring(index + Namespace.DELIMITER.length()); +// } +// +// /** +// * Get the name with any namespace stripped. +// * @param name Name with optional namespace prefix. +// * @return Name without namespace prefix. +// */ +// public String stripNamespaceBetter(String name) { +// List names = SymbolPathParser.parse(name); +// return names.get(names.size() - 1); +// } +// + /** + * Get the {@link CategoryPath} associated with the {@link SymbolPath} specified, rooting + * it either at the PDB Category. + * @param symbolPath Symbol path to be used to create the CategoryPath. Null represents global + * namespace. + * @return {@link CategoryPath} created for the input. + */ + public CategoryPath getCategory(SymbolPath symbolPath) { + + CategoryPath category = pdbRootCategory; + + if (symbolPath == null) { // global namespace + return category; + } + return recurseGetCategoryPath(category, symbolPath); + } + + /** + * Returns the {@link CategoryPath} for a typedef with the give {@link SymbolPath} and + * module number; 1 <= moduleNumber <= {@link AbstractDatabaseInterface#getNumModules()}, + * except that modeleNumber of 0 represents publics/globals. + * @param moduleNumber module number + * @param symbolPath SymbolPath of the symbol + * @return the CategoryPath + */ + public CategoryPath getTypedefsCategory(int moduleNumber, SymbolPath symbolPath) { + CategoryPath category = null; + if (moduleNumber >= 0 && moduleNumber < typedefCategories.size()) { + category = typedefCategories.get(moduleNumber); + } + if (category == null) { + // non-module typedefs go with all other global types, not in + // baseModuleTypedefsCategory. + category = pdbRootCategory; + } + + if (symbolPath == null) { // global namespace + return category; + } + + return recurseGetCategoryPath(category, symbolPath); + } + + /** + * Recursion method used by {@link #getCategory(SymbolPath)} and + * {@link #getTypedefsCategory(int, SymbolPath)}. Returns a + * new {@link CategoryPath} for the + * @param category the {@ink CategoryPath} on which to build + * @param symbolPath the current {@link SymbolPath} from which the current name is pulled. + * @return the new {@link CategoryPath} for the recursion level + */ + private CategoryPath recurseGetCategoryPath(CategoryPath category, SymbolPath symbolPath) { + SymbolPath parent = symbolPath.getParent(); + if (parent != null) { + category = recurseGetCategoryPath(category, parent); + } + return new CategoryPath(category, symbolPath.getName()); + } + + /** + * Returns the {@link CategoryPath} for Anonymous Functions Category for the PDB. + * @return the {@link CategoryPath} + */ + public CategoryPath getAnonymousFunctionsCategory() { + return anonymousFunctionsCategory; + } + + /** + * Returns the {@link CategoryPath} for Anonymous Types Category for the PDB. + * @return the {@link CategoryPath} + */ + public CategoryPath getAnonymousTypesCategory() { + return anonymousTypesCategory; + } + + /** + * Returns the name of what should be the next Anonymous Function (based on the count of + * the number of anonymous functions) so that there is a unique name for the function. + * @return the name for the next anonymous function. + */ + public String getNextAnonymousFunctionName() { + return String.format("_func_%08X", anonymousFunctionCount); + } + + /** + * Updates the count of the anonymous functions. This is a separate call from + * {@link #getNextAnonymousFunctionName()} because the count should only be updated after + * the previous anonymous function has been successfully created/stored. + */ + public void incrementNextAnonymousFunctionName() { + anonymousFunctionCount++; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocatorSelector.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocatorSelector.java new file mode 100644 index 0000000000..45f50682bb --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocatorSelector.java @@ -0,0 +1,671 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.*; + +import docking.widgets.OptionDialog; +import ghidra.app.util.bin.format.pdb.PdbParserConstants; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.datatype.microsoft.GUID; +import ghidra.app.util.importer.LibrarySearchPathManager; +import ghidra.app.util.importer.MessageLog; +import ghidra.framework.OperatingSystem; +import ghidra.framework.Platform; +import ghidra.program.model.listing.Program; +import ghidra.util.Msg; +import ghidra.util.SystemUtilities; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Searches for and presents PDB path information if order specified by + * + * Symbol Paths. + *

+ * Gist is: TODO. + *

+ * Our design:
+ *   Looking for files with extension .pdb or .PDB using an ordered set of paths and resources. 
+ *   
+ *   TODO:
+ *   Option to look exclusively for the above, exclusively for something else, or inclusive of
+ *    other extensions with a preference order.  So if we want to inclusively look for .pdb
+ *    and .pdb.xml with a preference of .pdb, and if we have a path search order of path A,
+ *    then path B, the question is whether we would choose a .pdb file in path B before a .pdb.xml
+ *    in path A.  Same question for other extensions such as .dbg.
+ *    
+ *   Could do similar to SymSetSearchPath() with semicolon-separated paths.
+ *   
+ *   Could have an configuration list that gives the search order for all resources to be searched.
+ *    For instance: path of the loaded executable, path specified in header of loaded executable,
+ *    local symbol paths, symbol servers at specified URLs.
+ *    -> Could allow any of these to not be active; could require optional user interaction ("are
+ *       you sure") for the path specified in the header of the loaded executable, option of read
+ *       and/or write to local symbol cache.
+ *   
+ *   Depending on whether is or used to be supported by MSFT, allow (with option?) the 2-tier
+ *    symbol server directory structure.
+ *    
+ *   Should we allow different or use different structures for local paths vs. symbol server paths?
+ *    For instance, the extension-tier (if *.dll, search an appropriate set of paths that have a
+ *    "dll" component). 
+ *   
+ * 
+ */ +public class PdbLocatorSelector { + + public static final File SPECIAL_PDB_LOCATION = new File("C:/WINDOWS/Symbols"); + public static final boolean onWindows = + (Platform.CURRENT_PLATFORM.getOperatingSystem() == OperatingSystem.WINDOWS); + + private File symbolsRepositoryPath; + /** + * Only holds identifies in PDBs up until a matching one was found--nothing beyond that. + */ + private Map identifiersByFilePath = new HashMap<>(); + + public PdbLocatorSelector(File symbolsRepositoryPath) { + this.symbolsRepositoryPath = symbolsRepositoryPath; + } + + //============================================================================================== + // TODO: Ideas for future. +// public SymbolPathSearcher(String message) { +// } + + // Search order preference: + // EXTENSION_PREFERENCE_ORDER(pdb, pdb.xml, dbg)--at least one; no duplicates + // e.g., {PDB, PDB_XML, DBG} means *.pdb before *.pdb.xml before *.dbg + // PATH_BEFORE_EXTENSION or EXTENSION_BEFORE_PATH + // e.g., + // PATH_BEFORE_EXTENSION means: (assuming EXTENION_PREFERENCE_ORDER is {PDB, PDB_XML}), + // at first path in list look for *.pdb, then *.pdb.xml, then if failed to + // find at the first path, try the same tWO ordered searches at the second path in + // the path list, etc. + // EXTENSION_BEFORE_PATH means: (assuming EXTENION_PREFERENCE_ORDER is {PDB, PDB_XML}), + // at first path in list look for *.pdb, then search for *.pdb at the second path, etc. + // If after the last path a *.pdb is not found, then repeat with list of paths, now + // looking for *.pdb.xml + + // Use a list of enums to specify search order? + // queryUser true if can interact with user (non-headless) + + // need paths for symbol server vs. paths for local cache? + + // specify filetype (pdb, pdb.xml, dbg, other?) + + // upper/lower case conversion + +// public void find(boolean includePeSpecifiedPdbPath, boolean queryUser) { +// } + + //============================================================================================== + /* + * TODO 20190403: Need to consider documentation at + * + * Symbol Paths. + *

+ * Says order: + *

  • C:\MySymbols + *
  • C:\MySymbols\ext, where ext is extension of binary (e.g., dll, exe, sys) + *
  • C:\MySymbols\symbols\ext + *

    + */ + // 20190321 Thoughts for fixing this up: + // Processing logic: + // + // Tenet: Program may or may not specify the following about an associated PDB: + // - filename of PDB + // - version (magic: RSDS) + // - signature + // - age + // - GUID (probably only in later versions) + // + // Tenet: PDB files may or may not specify the following about themselves: + // - version (date field indicating PDB version; also versioning dates of subcomponents) + // - signature + // - age + // - GUID (only in later versions) + // + // Tenet: Can be headed (GUI) or headless processing + // + // Logic Basics: + // - Need at least the filename. + // - No user interaction if headless. + // + // Use cases: + // - Given Program PDB info, search/find matching PDB, and apply all possible; else fail + // - Given Program PDB info, if matching PDB not found, but similar exist, present + // all possibles to user for choice or cancel. Choice would include the filename + // location along with the basic information pieces indicated above. Option to + // apply data types only (to a DataTypeManager) or to additionally apply symbols. + // (Could dig into each PDB for possible compile information, but requires full + // parsing.) Future may allow for a way to bring in symbol information into a + // temporary space that could allow the user to selectively choose symbols to apply + // to Program locations. + // - Given Program PDB info, if headless and exact match not found, option flag to fail + // with no information or to fail with the filenames and associated basic info. + // - Regardless of PDB info, if headless use "force" option with a single filename, + // which will force parsing and application of PDB file. (No option to force + // partially apply any parts of the PDB--think on this more.) + // Additional use cases: + // - Any PDB file can be loaded for general perusing (maybe). + // - Multiple PDB files can be loaded at any given time. + // - Multiple PDB files can have been loaded and had their data type processed and put + // into data type Categories labeled with the PDB information (might need GUID + // and other attributes used to help uniquely identify each (perhaps part of the + // Category name)). Perhaps the symbols for each PDB are available--perhaps just + // have each PDB available for further symbol/data type application. + // + // Today's Logic: + public String findPdb(Program program, PdbProgramAttributes programAttributes, + boolean userInteractive, boolean includePeSpecifiedPdbPath, TaskMonitor monitor, + MessageLog log, String messagePrefix) throws CancelledException { + + List orderedListOfExistingFileNames = + lookForPdb(program, includePeSpecifiedPdbPath, log, messagePrefix); + if (orderedListOfExistingFileNames.isEmpty()) { + String message = "Cannot find candidate PDB files."; + log.appendMsg(messagePrefix, message); + return null; + } + + String pdbFilename = null; + try { + pdbFilename = choosePdb(orderedListOfExistingFileNames, programAttributes, monitor, log, + messagePrefix); + } + catch (PdbException e) { + String message = "Could not find appropriate PDB file. Detailed issues may follow:\n" + + e.toString(); + log.appendMsg(messagePrefix, message); + return null; + } + + return pdbFilename; + } + + //============================================================================================== + /** + * @param program Program under analysis. + * @param includePeSpecifiedPdbPath {@code true} if looking for PDB in PE-Header-Specified + * path location, which may be unsafe security-wise. + * @param log MessageLog to report to. + * @param messagePrefix prefix string for any error message written to the log + * @return Ordered List of potential filenames + */ + private List lookForPdb(Program program, boolean includePeSpecifiedPdbPath, + MessageLog log, String messagePrefix) { + String message = ""; + try { + + List orderedListOfExistingFileNames = findPDB(new PdbProgramAttributes(program), + includePeSpecifiedPdbPath, symbolsRepositoryPath.getAbsolutePath()); + if (orderedListOfExistingFileNames.isEmpty()) { + + String pdbName = program.getOptions(Program.PROGRAM_INFO).getString( + PdbParserConstants.PDB_FILE, (String) null); + if (pdbName == null) { + message = "Program has no associated PDB file."; + } + else { + message = "Unable to locate PDB file \"" + pdbName + "\" with matching GUID."; + } + if (SystemUtilities.isInHeadlessMode()) { + message += "\n Use a script to set the PDB Symbol Location. I.e.,\n" + + " setAnalysisOption(currentProgram, \"PDB.Symbol Repository Path\", " + + "\"/path/to/pdb/folder\");\n" + + " This must be done using a pre-script (prior to analysis)."; + } + else { + message += + "\n You can manually load PDBs using the \"File->Load PDB File...\" action."; + if (pdbName != null) { + message += "\n Alternatively, you may set the PDB Symbol Repository Path" + + "\n using \"Edit->Options for [program]\" prior to analysis."; + } + } + } + return orderedListOfExistingFileNames; + } + catch (PdbException pe) { + message += pe.getMessage(); + } + finally { + if (message.length() > 0) { + log.appendMsg(messagePrefix, message); + log.setStatus(message); + } + } + + return null; + } + + //============================================================================================== + private String choosePdb(List orderedListOfExistingFileNames, + PdbProgramAttributes programAttributes, TaskMonitor monitor, MessageLog log, + String messagePrefix) throws PdbException, CancelledException { + String choice = findMatchingPdb(orderedListOfExistingFileNames, programAttributes, monitor); + if (choice == null) { + //choice = userSelectPdb(programAttributes, messagePrefix, log, monitor); + String message = getNoMatchMessage(programAttributes, monitor); + log.appendMsg(message); + } + return choice; + } + + //============================================================================================== + private String findMatchingPdb(List orderedListOfExistingFileNames, + PdbProgramAttributes programAttributes, TaskMonitor monitor) + throws PdbException, CancelledException { + + String message = ""; + + for (String filepath : orderedListOfExistingFileNames) { + monitor.checkCanceled(); + monitor.setMessage("Attempting to find/process PDB file " + filepath + "..."); + try (AbstractPdb tryPdb = PdbParser.parse(filepath, new PdbReaderOptions(), monitor)) { + PdbIdentifiers identifiers = tryPdb.getIdentifiers(); + identifiersByFilePath.put(filepath, identifiers); + if (verifyPdbSignature(programAttributes, identifiers)) { + monitor.setMessage("Parsing validated PDB file " + filepath + "."); + return filepath; + } + } + catch (Exception e) { + // Ignore FileNotFoundException. + if (!e.getClass().equals(FileNotFoundException.class)) { + // Noting any exceptions. Will only report if we have not successfully + // found a matching PDB without an exception being thrown for it. + message += "Exception for attempted PDB " + filepath + ": " + e.toString(); + } + } + } + if (!message.isEmpty()) { + throw new PdbException(message); + } + return null; + } + + //============================================================================================== + @SuppressWarnings("unused") // for method not being called. + private String userSelectPdb(PdbProgramAttributes programAttributes, String messagePrefix, + MessageLog log, TaskMonitor monitor) throws CancelledException { + + String[] fileNames = new String[identifiersByFilePath.size()]; + String[] fileIdents = new String[identifiersByFilePath.size()]; + int i = 0; + for (Map.Entry entry : identifiersByFilePath.entrySet()) { + monitor.checkCanceled(); + fileNames[i] = entry.getKey(); + fileIdents[i++] = formatPdbIdentifiers(entry.getKey(), entry.getValue()).toString(); + } + + String message = "Could not match program with PDB.\n"; + if (identifiersByFilePath.size() != 0) { + message += "PDB File Options (Name Signature Age GUID):\n"; + for (String fileIdent : fileIdents) { + message += fileIdent + "\n"; + } + } + + if (SystemUtilities.isInHeadlessMode()) { + message = "In Headless mode... skipping PDB processing.\n"; + log.appendMsg(messagePrefix, message); + log.setStatus(message); + return null; + } + String header = + "Choose PDB or Cancel (for: " + formatPdbIdentifiers(programAttributes) + ")"; + String userChoice = OptionDialog.showInputChoiceDialog(null, header, "Choose", fileIdents, + fileIdents[0], OptionDialog.CANCEL_OPTION); + if (userChoice == null) { + return null; + } + for (i = 0; i < fileIdents.length; i++) { + if (userChoice.contentEquals(fileIdents[i])) { + message = "User PDB Choice: " + userChoice; + Msg.info(this, message); // Info for console. + return fileNames[i]; + } + } + return null; + } + + //============================================================================================== + private String getNoMatchMessage(PdbProgramAttributes programAttributes, TaskMonitor monitor) + throws CancelledException { + StringBuilder builder = new StringBuilder(); + builder.append("ERROR: Could not run PDB Analyzer because a matched PDB was not found.\n"); + builder.append("PDB specification from PE header:\n"); + builder.append(formatPdbIdentifiers(programAttributes)); + + builder.append("Discovered non-matches:\n"); + for (Map.Entry entry : identifiersByFilePath.entrySet()) { + monitor.checkCanceled(); + builder.append(formatPdbIdentifiers(entry.getKey(), entry.getValue())); + } + return builder.toString(); + } + + private StringBuilder formatPdbIdentifiers(PdbProgramAttributes attributes) { + Integer signature = (attributes.getPdbSignature() == null) ? null + : Integer.valueOf(attributes.getPdbSignature()); + return formatPdbIdentifiers(attributes.getPdbFile(), signature, + Integer.valueOf(attributes.getPdbAge()), attributes.getPdbGuid()); + } + + private StringBuilder formatPdbIdentifiers(String file, PdbIdentifiers identifiers) { + return formatPdbIdentifiers(file, identifiers.getSignature(), identifiers.getAge(), + identifiers.getGuid().toString()); + } + + private StringBuilder formatPdbIdentifiers(String file, Integer signature, int age, + String guidString) { + StringBuilder builder = new StringBuilder(); + builder.append(" Location: ").append(file); + if (signature != null) { + builder.append(String.format("; Signature: 0X%08X", signature)); + } + builder.append("; Age: "); + builder.append(age); + if (guidString != null) { + builder.append("; GUID: "); + builder.append(guidString); + } + builder.append('\n'); + return builder; + } + + //============================================================================================== + /** + * Find a matching PDB file using attributes associated with the program. User can specify the + * type of file to search from (.pdb or .pdb.xml). + * + * @param pdbAttributes PDB attributes associated with the program. + * @param includePeSpecifiedPdbPath {@code true} if looking for PDB in PE-Header-Specified + * path location, which may be unsafe security-wise. + * @param symbolsRepositoryPathIn Location of the local symbols repository (can be null). + * @return matching PDB file (or null, if not found). + * @throws PdbException if there was a problem with the PDB attributes. + */ + private List findPDB(PdbProgramAttributes pdbAttributes, + boolean includePeSpecifiedPdbPath, String symbolsRepositoryPathIn) throws PdbException { + + // Store potential names of PDB files and potential locations of those files, + // so that all possible combinations can be searched. + // LinkedHashSet is used when we need to preserve order + Set guidSubdirPaths = new HashSet<>(); + + String guidAgeString = pdbAttributes.getGuidAgeCombo(); + if (guidAgeString == null) { + throw new PdbException( + "Incomplete PDB information (GUID/Signature and/or age) associated with this program.\n" + + "Either the program is not a PE, or it was not compiled with debug information."); + } + + List potentialPdbNames = pdbAttributes.getPotentialPdbFilenames(); + for (String potentialName : potentialPdbNames) { + guidSubdirPaths.add(File.separator + potentialName + File.separator + guidAgeString); + } + + return checkPathsForPdb(symbolsRepositoryPathIn, guidSubdirPaths, potentialPdbNames, + pdbAttributes, includePeSpecifiedPdbPath); + } + + //============================================================================================== + /** + * Check potential paths in a specific order. If the symbolsRepositoryPath parameter is + * supplied and the directory exists, that directory will be searched first for the + * matching PDB file. + * + * If the file type is supplied, then only that file type will be searched for. Otherwise, + * the search process depends on the current operating system that Ghidra is running from: + * + * - Windows: look in the symbolsRepositoryPath for a matching .pdb file. If one does not + * exist, look for a .pdb.xml file in symbolsRepositoryPath. If not found, then + * search for a matching .pdb file, then .pdb.xml file, in other directories. + * - non-Windows: look in the symbolsRepositoryPath for a matching .pdb.xml file. If one does + * not exist, look for a .pdb file. If a .pdb file is found, return an error saying + * that it was found, but could not be processed. If no matches found in + * symbolsRepositoryPath, then look for .pdb.xml file, then .pdb.xml file in other + * directories. + * + * @param symbolsRepositoryPath location of the local symbols repository (can be null) + * @param guidSubdirPaths subdirectory paths (that include the PDB's GUID) that may contain + * a matching PDB + * @param potentialPdbNames all potential filenames for the PDB file(s) that match the program + * @param pdbAttributes PDB attributes associated with the program + * @return matching PDB file, if found (else null) + */ + private static List checkPathsForPdb(String symbolsRepositoryPath, + Set guidSubdirPaths, List potentialPdbNames, + PdbProgramAttributes pdbAttributes, boolean includePeSpecifiedPdbPath) { + + Set symbolsRepoPaths = + getSymbolsRepositoryPaths(symbolsRepositoryPath, guidSubdirPaths); + Set predefinedPaths = + getPredefinedPaths(guidSubdirPaths, pdbAttributes, includePeSpecifiedPdbPath); + + // Start by searching in symbolsRepositoryPath, if available. + + List orderedListOfExistingFileNames = new ArrayList<>(); + if (symbolsRepositoryPath != null) { + orderedListOfExistingFileNames.addAll( + checkSpecificPathsForPdb(symbolsRepoPaths, potentialPdbNames)); + } + + orderedListOfExistingFileNames.addAll( + checkSpecificPathsForPdb(predefinedPaths, potentialPdbNames)); + + return orderedListOfExistingFileNames; + + } + + //============================================================================================== + private static List checkSpecificPathsForPdb(Set paths, + List potentialPdbNames) { + + List orderedListOfExistingFileNames = checkForPDBorXML(paths, potentialPdbNames); + + return orderedListOfExistingFileNames; + } + + //============================================================================================== + private static Set getSymbolsRepositoryPaths(String symbolsRepositoryPath, + Set guidSubdirPaths) { + + Set symbolsRepoPaths = new LinkedHashSet<>(); + + // Collect sub-directories of the symbol repository that exist + File symRepoFile; + + if (symbolsRepositoryPath != null && + (symRepoFile = new File(symbolsRepositoryPath)).isDirectory()) { + + for (String guidSubdir : guidSubdirPaths) { + File testDir = new File(symRepoFile, guidSubdir); + if (testDir.isDirectory()) { + symbolsRepoPaths.add(testDir); + } + } + + // Check outer folder last + symbolsRepoPaths.add(symRepoFile); + } + + return symbolsRepoPaths; + } + + //============================================================================================== + // Get list of "paths we know about" to search for PDBs + private static Set getPredefinedPaths(Set guidSubdirPaths, + PdbProgramAttributes pdbAttributes, boolean includePeSpecifiedPdbPath) { + + Set predefinedPaths = new LinkedHashSet<>(); + + getPathsFromAttributes(pdbAttributes, includePeSpecifiedPdbPath, predefinedPaths); + getWindowsPaths(guidSubdirPaths, predefinedPaths); + getLibraryPaths(guidSubdirPaths, predefinedPaths); + + return predefinedPaths; + } + + //============================================================================================== + private static void getLibraryPaths(Set guidSubdirPaths, Set predefinedPaths) { + String[] libraryPaths = LibrarySearchPathManager.getLibraryPaths(); + + File libFile, subDir; + + for (String path : libraryPaths) { + + if ((libFile = new File(path)).isDirectory()) { + predefinedPaths.add(libFile); + + // Check alternate locations + for (String guidSubdir : guidSubdirPaths) { + if ((subDir = new File(path, guidSubdir)).isDirectory()) { + predefinedPaths.add(subDir); + } + } + } + } + } + + //============================================================================================== + /** + * TODO 20190403: Need to consider documentation at + * + * Symbol Paths. + *

    + * Says order: + *

  • C:\MySymbols + *
  • C:\MySymbols\ext, where ext is extension of binary (e.g., dll, exe, sys) + *
  • C:\MySymbols\symbols\ext + *

    + */ + private static void getWindowsPaths(Set guidSubdirPaths, Set predefinedPaths) { + // Don't have to call .exists(), since .isDirectory() does that already + if (onWindows && SPECIAL_PDB_LOCATION.isDirectory()) { + predefinedPaths.add(SPECIAL_PDB_LOCATION); + + // Check alternate locations + String specialPdbPath = SPECIAL_PDB_LOCATION.getAbsolutePath(); + + for (String guidSubdir : guidSubdirPaths) { + File testDir = new File(specialPdbPath + guidSubdir); + if (testDir.isDirectory()) { + predefinedPaths.add(testDir); + } + } + } + } + + //============================================================================================== + private static void getPathsFromAttributes(PdbProgramAttributes pdbAttributes, + boolean includePeSpecifiedPdbPath, Set predefinedPaths) { + if (pdbAttributes != null) { + + String currentPath = pdbAttributes.getPdbFile(); + + if (currentPath != null && includePeSpecifiedPdbPath) { + File parentDir = new File(currentPath).getParentFile(); + + if (parentDir != null && parentDir.exists()) { + predefinedPaths.add(parentDir); + } + } + + currentPath = pdbAttributes.getExecutablePath(); + + if (currentPath != null && !currentPath.equals("unknown")) { + File parentDir = new File(currentPath).getParentFile(); + + if (parentDir != null && parentDir.exists()) { + predefinedPaths.add(parentDir); + } + } + } + } + + //============================================================================================== + /** + * Returns the first PDB-type file found. Assumes list of potentialPdbDirs is in the order + * in which the directories should be searched. + * + * @param potentialPdbDirs List of paths + * @param potentialPdbNames List of file names + * @return Ordered List of potential filenames + */ + private static List checkForPDBorXML(Set potentialPdbDirs, + List potentialPdbNames) { + + List orderedListOfExistingFileNames = new ArrayList<>(); + File file; + + for (File pdbPath : potentialPdbDirs) { + + for (String filename : potentialPdbNames) { + + file = new File(pdbPath, filename); + + // Note: isFile() also checks for existence + if (file.isFile()) { + orderedListOfExistingFileNames.add(file.getAbsolutePath()); + } + } + } + + return orderedListOfExistingFileNames; + } + + //============================================================================================== + private boolean verifyPdbSignature(PdbProgramAttributes programAttributes, + PdbIdentifiers identifiers) throws PdbException { + + String attributesGuidString = programAttributes.getPdbGuid(); + if (attributesGuidString == null) { + // TODO: note that PdbProgramAttributes does not seem to be getting this value from + // the program--getting it as a default value (e.g., from options or elsewhere). + // Should see if it is available in the program somewhere? + String attributesSignatureString = programAttributes.getPdbSignature(); + if (attributesSignatureString == null) { + throw new PdbException("No PDB GUID or Signature in file.\n Cannot match."); + } + int attributesSignature = Integer.parseInt(attributesSignatureString); + if (attributesSignature != identifiers.getSignature()) { + return false; // no match + } + } + else { + GUID pdbGuid = identifiers.getGuid(); + if (!attributesGuidString.equals(pdbGuid.toString())) { + return false; // no match + } + } + + int attributesAge = Integer.parseInt(programAttributes.getPdbAge(), 16); + if (attributesAge != identifiers.getAge()) { + return false; + } + + return true; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java new file mode 100644 index 0000000000..e195d4f77e --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java @@ -0,0 +1,101 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb; + +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.SymbolPath; +import ghidra.program.model.symbol.SymbolUtilities; + +public class PdbNamespaceUtils { + + /** + * Fixes {@link SymbolPath} name, eliminating invalid characters and making the terminal + * name of the namespace unique by the index number when necessary. For example, + * anonymous and unnamed components such as {@code } and {@code } + * are fixed up. Example: + *

    +	 *   {@code _SYSTEM_INFO::}
    +	 * 
    + * @param symbolPath the source {@link SymbolPath} + * @param index the index number used be used as part of a unique tag name. + * @return the resulting ({@link SymbolPath} + */ + public static SymbolPath getFixUpSymbolPathNameOnly(SymbolPath symbolPath, int index) { + symbolPath = symbolPath.replaceInvalidChars(); + return new SymbolPath(symbolPath.getParent(), fixUnnamed(symbolPath.getName(), index)); + } + + /** + * Fixes {@link SymbolPath} name, eliminating invalid characters + * @param symbolPath the source {@link SymbolPath} + * @return the resulting ({@link SymbolPath} + */ + public static SymbolPath getFixUpSymbolPathNameOnly(SymbolPath symbolPath) { + symbolPath = symbolPath.replaceInvalidChars(); + return symbolPath; + } + + /** + * Fixes {@code } and {@code } components of a namespace. + *

    + * NOTE: This could be an issue when there are multiple unnamed items, such as in, for example: + *

    +	 *   {@code _SYSTEM_INFO::::}
    +	 * 
    + * @param symbolPath the source {@link SymbolPath} + * @param index the index number used be used as part of a unique tag name. + * @return the resulting ({@link SymbolPath} + */ + public static SymbolPath getFixUpSymbolPath(SymbolPath symbolPath, int index) { + symbolPath = symbolPath.replaceInvalidChars(); + List modList = new ArrayList<>(); + for (String str : symbolPath.asList()) { + modList.add(SymbolUtilities.replaceInvalidChars(fixUnnamed(str, index), true)); + } + return new SymbolPath(modList); +// return getFixUpSymbolPathRecurse(symbolPath, index); + } + +// private static SymbolPath getFixUpSymbolPathRecurse(SymbolPath symbolPath, int index) { +// SymbolPath parent = symbolPath.getParent(); +// if (parent != null) { +// parent = getFixUpSymbolPathRecurse(parent, index); +// } +// return new SymbolPath(parent, fixName(symbolPath.getName(), index)); +// } +// + /** + * Fixes-up {@code } or {@code } component of a name. + * @param name original name. + * @param index the index number used be used as part of a unique tag name. + * @return the resulting name. + */ + public static String fixUnnamed(String name, int index) { + if ("".equals(name)) { + return String.format("", index); + } + if ("".equals(name)) { + return String.format("", index); + } + if ("".equals(name)) { + return String.format("", index); + } + return name; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbProgramAttributes.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbProgramAttributes.java similarity index 87% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbProgramAttributes.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbProgramAttributes.java index 25d1de26c6..97c75c4778 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb/PdbProgramAttributes.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbProgramAttributes.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package ghidra.app.util.bin.format.pdb; +package ghidra.app.util.pdb; import java.util.*; -import ghidra.app.util.bin.format.pdb.PdbParser.PdbFileType; +import ghidra.app.util.bin.format.pdb.PdbParserConstants; import ghidra.framework.options.Options; import ghidra.program.model.listing.Program; @@ -37,6 +37,7 @@ public class PdbProgramAttributes { private String guidAgeCombo; private String pdbFile; + private String pdbVersion; private boolean pdbLoaded; private boolean programAnalyzed; private String executablePath; @@ -53,6 +54,7 @@ public class PdbProgramAttributes { programAnalyzed = propList.getBoolean(Program.ANALYZED, false); pdbSignature = propList.getString(PdbParserConstants.PDB_SIGNATURE, (String) null); pdbFile = propList.getString(PdbParserConstants.PDB_FILE, (String) null); + pdbVersion = propList.getString(PdbParserConstants.PDB_VERSION, (String) null); executablePath = program.getExecutablePath(); @@ -68,6 +70,7 @@ public class PdbProgramAttributes { programAnalyzed = analyzed; pdbSignature = signature; pdbFile = file; + pdbVersion = "RSDS"; // TODO: possibly receive this as argument. executablePath = execPath; createGuidAgeString(); @@ -89,6 +92,10 @@ public class PdbProgramAttributes { return pdbFile; } + public String getPdbVersion() { + return pdbVersion; + } + public boolean isPdbLoaded() { return pdbLoaded; } @@ -110,21 +117,22 @@ public class PdbProgramAttributes { if (potentialPdbFilenames == null) { // Want to preserve add order while only keeping unique entries - Set setOfPotentialFilenames = new LinkedHashSet(); + Set setOfPotentialFilenames = new LinkedHashSet<>(); if (pdbFile != null) { setOfPotentialFilenames.add(getFilename(pdbFile).toLowerCase()); + setOfPotentialFilenames.add(getFilename(pdbFile)); setOfPotentialFilenames.add(pdbFile); } // getExecutablePath can return "unknown" if (!executablePath.equals("unknown")) { String executableFilename = getFilename(executablePath); - setOfPotentialFilenames.add(getBinaryBasename(executableFilename).toLowerCase() + - PdbFileType.PDB.toString()); + setOfPotentialFilenames.add( + getBinaryBasename(executableFilename).toLowerCase() + ".pdb"); } - potentialPdbFilenames = new ArrayList(setOfPotentialFilenames); + potentialPdbFilenames = new ArrayList<>(setOfPotentialFilenames); } return potentialPdbFilenames; @@ -179,7 +187,7 @@ public class PdbProgramAttributes { * @param fullPath from which to extract the filename * @return the name of the file specified by the fullPath */ - private static String getFilename(String fullPath) { + private String getFilename(String fullPath) { // Remove any trailing slashes String editedPath = fullPath; editedPath = editedPath.replaceAll("[\\/]$", ""); @@ -191,9 +199,8 @@ public class PdbProgramAttributes { return editedPath; } - int indexToUse = - (lastIndexForwardSlash > lastIndexBackSlash) ? lastIndexForwardSlash - : lastIndexBackSlash; + int indexToUse = (lastIndexForwardSlash > lastIndexBackSlash) ? lastIndexForwardSlash + : lastIndexBackSlash; return editedPath.substring(indexToUse + 1); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java new file mode 100644 index 0000000000..3f73c1f4e4 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java @@ -0,0 +1,111 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.SymbolPath; +import ghidra.app.util.SymbolPathParser; +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.*; +import ghidra.app.util.pdb.PdbNamespaceUtils; +import ghidra.program.model.data.DataType; + +public abstract class AbstractComplexTypeApplier extends AbstractMsTypeApplier { + + protected SymbolPath symbolPath; + protected SymbolPath fixedSymbolPath; + + protected AbstractComplexTypeApplier definitionApplier = null; + protected AbstractComplexTypeApplier fwdRefApplier = null; + + public static AbstractComplexTypeApplier getComplexApplier(PdbApplicator applicator, + RecordNumber recordNumber) throws PdbException { + return (AbstractComplexTypeApplier) applicator.getApplierSpec(recordNumber, + AbstractComplexTypeApplier.class); + } + + /** + * Constructor for complex type applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractEnumMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public AbstractComplexTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, msType); + String fullPathName = msType.getName(); + symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName)); + } + + public SymbolPath getSymbolPath() { + return symbolPath; + } + + public boolean isForwardReference() { + return ((AbstractComplexMsType) msType).getMsProperty().isForwardReference(); + } + + public boolean isFinal() { + return ((AbstractComplexMsType) msType).getMsProperty().isSealed(); + } + + public void setFwdRefApplier(AbstractComplexTypeApplier fwdRefApplier) { + this.fwdRefApplier = fwdRefApplier; + } + + T getFwdRefApplier(Class typeClass) { + if (!typeClass.isInstance(fwdRefApplier)) { + return null; + } + return typeClass.cast(fwdRefApplier); + } + + public void setDefinitionApplier(AbstractComplexTypeApplier definitionApplier) { + this.definitionApplier = definitionApplier; + } + + T getDefinitionApplier(Class typeClass) { + if (!typeClass.isInstance(definitionApplier)) { + return null; + } + return typeClass.cast(definitionApplier); + } + + protected SymbolPath getFixedSymbolPath() { //return mine or my def's (and set mine) + if (fixedSymbolPath != null) { + return fixedSymbolPath; + } + + if (definitionApplier != null && definitionApplier.getFixedSymbolPath() != null) { + fixedSymbolPath = definitionApplier.getFixedSymbolPath(); + return fixedSymbolPath; + } + + SymbolPath fixed = PdbNamespaceUtils.getFixUpSymbolPathNameOnly(symbolPath, index); + if (symbolPath.equals(fixed)) { + fixedSymbolPath = symbolPath; + } + else { + fixedSymbolPath = fixed; + } + return fixedSymbolPath; + } + + DataType getDataTypeInternal() { + return dataType; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java new file mode 100644 index 0000000000..25ffaa4ff1 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java @@ -0,0 +1,229 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +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.AbstractMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention; +import ghidra.program.model.data.*; +import ghidra.util.exception.CancelledException; + +/** + * Applier for certain function types. + */ +public abstract class AbstractFunctionTypeApplier extends AbstractMsTypeApplier { + + private boolean isDeferred = false; + + private FunctionDefinitionDataType functionDefinition; + + private AbstractMsTypeApplier returnApplier; + ArgumentsListTypeApplier argsListApplier; + CallingConvention callingConvention; + boolean hasThisPointer; + + /** + * Constructor for the applicator that applies a "function" type, transforming it into a + * Ghidra DataType. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractMsType} to processes + * @throws IllegalArgumentException Upon invalid arguments. + */ + public AbstractFunctionTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, msType); + String funcName = applicator.getNextAnonymousFunctionName(); + functionDefinition = new FunctionDefinitionDataType( + applicator.getAnonymousFunctionsCategory(), funcName, applicator.getDataTypeManager()); + // Updating before trying to apply... if applyFunction fails, then this name will go + // unused for the most part, but we also will not get a conflict on the name. + applicator.incrementNextAnonymousFunctionName(); + dataType = functionDefinition; + } + + //============================================================================================== + public void setDeferred() { + isDeferred = true; + } + + @Override + public boolean isDeferred() { + return isDeferred; + } + + @Override + void deferredApply() throws PdbException, CancelledException { + if (isDeferred()) { + applyInternal(); + } + } + + //============================================================================================== + /** + * Returns the function definition being created by this applier. + * @return the function definition. + */ + public FunctionDefinitionDataType getFunctionDefinition() { + return functionDefinition; + } + + @Override + DataType getCycleBreakType() { + if (dataType != null) { + return dataType; + } + return functionDefinition; + } + + AbstractMsTypeApplier getReturnTypeApplier() { + return applicator.getTypeApplier(getReturnRecordNumber()); + } + + ArgumentsListTypeApplier getArgsListApplier() { + AbstractMsTypeApplier argsApplier = applicator.getTypeApplier(getArgListRecordNumber()); + if (argsApplier instanceof ArgumentsListTypeApplier) { + return (ArgumentsListTypeApplier) applicator.getTypeApplier(getArgListRecordNumber()); + } + return null; + } + + protected abstract CallingConvention getCallingConvention(); + + protected abstract boolean hasThisPointer() throws CancelledException, PdbException; + + protected abstract RecordNumber getReturnRecordNumber(); + + protected abstract RecordNumber getArgListRecordNumber(); + + /** + * Method to create the {@link DataType} based upon the type indices of the calling + * convention, return type, and arguments list. + * @param callingConventionParam Identification of the {@link AbstractMsType} record of the + * {@link CallingConvention}. + * @param hasThisPointerParam true if has a this pointer + * @return {@link DataType} created or null upon issue. + * @throws PdbException when unexpected function internals are found. + * @throws CancelledException Upon user cancellation + */ + protected DataType applyFunction(CallingConvention callingConventionParam, + boolean hasThisPointerParam) throws PdbException, CancelledException { +// String funcName = applicator.getCategoryUtils().getNextAnonymousFunctionName(); +// FunctionDefinitionDataType functionDefinition = new FunctionDefinitionDataType( +// applicator.getCategoryUtils().getAnonymousFunctionsCategory(), funcName, +// applicator.getDataTypeManager()); + + this.callingConvention = callingConventionParam; + this.hasThisPointer = hasThisPointerParam; + returnApplier = getReturnTypeApplier(); + argsListApplier = getArgsListApplier(); + + applyOrDeferForDependencies(); +// applyInternal(); + + // 20190725 remove for second pass in applicator +// // TODO: what handler should we really use? +// DataType resolvedFunctionDefinition = applicator.resolve(functionDefinition); +// +// if (resolvedFunctionDefinition == null) { +// applicator.getLog().appendMsg("Function definition type not resolved for " + functionDefinition.getName()); +// return null; +// } +// if (!(resolvedFunctionDefinition instanceof FunctionDefinition)) { +// // Error... can this happen? +// // Remove what was just created? +// applicator.getLog().appendMsg("Non-function resolved for " + functionDefinition.getName()); +// return null; +// } + +// // Only update if successful. +// applicator.getCategoryUtils().incrementNextAnonymousFunctionName(); +// return resolvedFunctionDefinition; + return functionDefinition; + } + + private void applyOrDeferForDependencies() throws CancelledException { + if (returnApplier.isDeferred()) { + applicator.addApplierDependency(this, returnApplier); + setDeferred(); + } + if (argsListApplier != null) { + argsListApplier.checkForDependencies(this); + } + + if (!isDeferred()) { + applyInternal(); + } + } + + public void applyInternal() throws CancelledException { + if (isApplied()) { + return; + } + if (!setReturnType()) { + return; + } + if (argsListApplier != null) { + argsListApplier.applyTo(this); + } + setCallingConvention(applicator, callingConvention, hasThisPointer); + setApplied(); + } + + private boolean setReturnType() { + + DataType returnDataType = returnApplier.getDataType(); + if (returnDataType == null) { + applicator.appendLogMsg("Return type is null in " + functionDefinition.getName()); + return false; + } + functionDefinition.setReturnType(returnDataType); + return true; + } + + private void setCallingConvention(PdbApplicator applicator, CallingConvention callingConvention, + boolean hasThisPointer) { + GenericCallingConvention convention; + if (hasThisPointer) { + convention = GenericCallingConvention.thiscall; + } + else { + // Since we are a member function, we will always assume a _thiscall... + // but how do we know it is not a atatic member function (no "this")? + switch (callingConvention) { + // TODO: figure all of these out. + case THISCALL: // "this" passed in register (we have not yet seen this) + convention = GenericCallingConvention.thiscall; // Is this correct if in reg? + break; + case NEAR_C: // we have seen this one + convention = GenericCallingConvention.cdecl; + break; + case NEAR_VECTOR: // we have seen this one + convention = GenericCallingConvention.vectorcall; + break; + default: +// applicator.getLog().appendMsg( +// "TODO: calling convention not implemented for value " + callingConventionVal + +// " in " + funcName); + //convention = GenericCallingConvention.cdecl; + convention = GenericCallingConvention.cdecl; + break; + } + } + functionDefinition.setGenericCallingConvention(convention); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsSymbolApplier.java new file mode 100644 index 0000000000..22040424ac --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsSymbolApplier.java @@ -0,0 +1,75 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.Objects; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.util.exception.CancelledException; + +public abstract class AbstractMsSymbolApplier { + protected PdbApplicator applicator; + protected AbstractMsSymbolIterator iter; + protected long currentOffset; + + public AbstractMsSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + Objects.requireNonNull(applicator, "applicator cannot be null"); + Objects.requireNonNull(iter, "symbolGroup cannot be null"); + this.applicator = applicator; + this.iter = iter; + currentOffset = iter.getCurrentOffset(); + } + + /** + * Sets the offset of the {@link SymbolGroup} back to the state when this applicator was + * created. + */ + protected void resetOffset() { + iter.initGetByOffset(currentOffset); + } + + /** + * Apply the next and any desired subsequent {@link AbstractMsSymbol AbstractMsSymbols} from + * the {@link SymbolGroup} to a program. + * @throws PdbException if there was a problem processing the data. + * @throws CancelledException upon user cancellation + */ + public abstract void apply() throws PdbException, CancelledException; + + /** + * Applies logic of this class to another {@link AbstractMsSymbolApplier} instead of to + * "the program." + * @param applyToApplier the applier to which the logic of this class is applied. + * @throws PdbException if there was a problem processing the data. + * @throws CancelledException upon user cancellation. + */ + public abstract void applyTo(AbstractMsSymbolApplier applyToApplier) + throws PdbException, CancelledException; + + /** + * Manages block nesting for symbols/appliers that represent the beginning or end of blocks. + * The default is to do nothing. Otherwise the appliers should implement the appropriate + * logic. + * @param applierParam the applier which is managing blocks, which is typically + * {@link FunctionSymbolApplier}. + */ + public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + // Do nothing by default. + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsTypeApplier.java new file mode 100644 index 0000000000..4af118ed9a --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsTypeApplier.java @@ -0,0 +1,219 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; +import java.util.*; + +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.AbstractMsType; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.CancelledException; + +/** + * Abstract class representing the applier/wrapper for a specific {@link AbstractMsType}. The + * {link {@link #apply()} method creates an associated {@link DataType}, if + * applicable. Methods associated with the {@link AbstractMsTypeApplier} or derived class will + * make fields available to the user, first by trying to get them from the {@link DataType}, + * otherwise getting them from the {@link AbstractMsType}. + */ +public abstract class AbstractMsTypeApplier implements Comparable { + + protected PdbApplicator applicator; + protected AbstractMsType msType; + protected int index; + protected DataType dataType; + // separate copy for now. Might eventually just replace dataType (above)--would have to + // change getDataType(). + protected DataType resolvedDataType; + protected boolean resolved = false; + protected boolean applied = false; + + protected Set waitSet = new HashSet<>(); + + /** + * Constructor. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractMsType} to apply. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public AbstractMsTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + if (msType == null) { + throw new IllegalArgumentException("PDB Type Applying null AbstractMsType"); + } + this.applicator = applicator; + this.msType = msType; + RecordNumber recordNumber = msType.getRecordNumber(); + if (recordNumber != null) { + index = recordNumber.getNumber(); + } + else { + index = -1; + } + dataType = null; + } + + public boolean isApplied() { + return applied; + } + + public void setApplied() { + applied = true; + } + + boolean isDeferred() { + return false; + } + + void deferredApply() throws PdbException, CancelledException { + // default is to do nothing, as most appliers are not deferrable (or should not be). + } + + public AbstractMsTypeApplier getDependencyApplier() { + return this; + } + + /** + * Resolves the type through the DataTypeManager and makes the resolved type primary. + */ + public void resolve() { + if (resolved) { + return; + } + if (dataType != null) { + resolvedDataType = applicator.resolve(dataType); + } + resolved = true; + } + + /** + * Returns the {@link AbstractMsType} associated with this applier/wrapper. + * @return {@link AbstractMsType} associated with this applier/wrapper. + */ + public AbstractMsType getMsType() { + return msType; + } + + /** + * Returns the {@link DataType} associated with this applier/wrapper. + * @return {@link DataType} associated with this applier/wrapper. + */ + public DataType getDataType() { + if (resolved) { + return resolvedDataType; + } + return dataType; + } + + /** + * Returns either a DataTypeDB or an type (IMPL that might be an empty container) that + * suffices to break cyclical dependencies in data type generation. + * @return the data type. + */ + DataType getCycleBreakType() { + return getDataType(); + } + + /** + * Apply the {@link AbstractMsType} in an attempt to create a Ghidra type. + * @throws PdbException if there was a problem processing the data. + * @throws CancelledException upon user cancellation + */ + public abstract void apply() throws PdbException, CancelledException; + + /** + * Returns the size of the type or 0 if unknown. + * @return the size; zero if unknown. + */ + public abstract BigInteger getSize(); + + /** + * Returns the (long) size of the type or 0 if unknown. Or Long.MAX_VALUE if too large. + * @return the size; zero if unknown. + */ + public long getSizeLong() { + return PdbApplicator.bigIntegerToLong(applicator, getSize()); + } + + /** + * Returns the (int) size of the type or 0 if unknown. Or Integer.MAX_VALUE if too large. + * @return the size; zero if unknown. + */ + public int getSizeInt() { + return PdbApplicator.bigIntegerToInt(applicator, getSize()); + } + + @Override + public String toString() { + return msType.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + index; + result = prime * result + msType.getClass().getSimpleName().hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AbstractMsTypeApplier other = (AbstractMsTypeApplier) obj; + if (index != other.index) { + return false; + } + if (!msType.getClass().getSimpleName().equals(other.msType.getClass().getSimpleName())) { + return false; + } + return true; + } + + @Override + public int compareTo(AbstractMsTypeApplier o) { + int val = hashCode() - o.hashCode(); + return val; + } + + protected void waitSetPut(AbstractMsTypeApplier applier) { + waitSet.add(applier); + } + + protected boolean waitSetRemove(AbstractMsTypeApplier applier) { + return waitSet.remove(applier); + } + + protected boolean waitSetIsEmpty() { + return waitSet.isEmpty(); + } + + protected AbstractMsTypeApplier waitSetGetNext() { + List list = new ArrayList<>(waitSet); + return list.get(0); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java new file mode 100644 index 0000000000..6286837ca6 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java @@ -0,0 +1,227 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +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.AbstractArgumentsListMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.program.model.data.*; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractArgumentsListMsType} types. + */ +public class ArgumentsListTypeApplier extends AbstractMsTypeApplier { + + private boolean isDeferred = false; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractArgumentsListMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + ArgumentsListTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for the applicator that applies a arguments list. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractArgumentsListMsType} to processes. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public ArgumentsListTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + //============================================================================================== + public void setDeferred() { + isDeferred = true; + } + + @Override + public boolean isDeferred() { + return isDeferred; + } + + @Override + void deferredApply() throws PdbException, CancelledException { + // Do nothing... Just need dependency tie of each argument to function. + } + + //============================================================================================== + // TODO: would be nice if we did not have to implement this method. Want the applyTo() below. + @Override + public void apply() throws PdbException, CancelledException { +// addMyDependenciesOnly(); +// // Silently do nothing. + } + + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + +// private void addMyDependenciesOnly() throws CancelledException, PdbException { +// AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType; +// List list = argsList.getArgTypeIndexList(); +// for (AbstractTypeIndex element : list) { +// applicator.checkCanceled(); +// AbstractMsTypeApplier argApplier = applicator.getTypeApplier(element.get()); +// +// if (argApplier instanceof PrimitiveTypeApplier && +// ((PrimitiveTypeApplier) argApplier).isNoType()) { +// // Arguments list is empty. (There better not have been any arguments up until +// // now.) +// break; +// } +// +// if (argApplier instanceof AbstractDeferrableMsTypeApplier && +// ((AbstractDeferrableMsTypeApplier) argApplier).isDeferred()) { +// applicator.addApplierDependency(this, argApplier); +// setDeferred(); +// } +// } +// } +// + public void checkForDependencies(AbstractFunctionTypeApplier functionApplier) + throws CancelledException { + AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType; + List args = argsList.getArgRecordNumbers(); + for (RecordNumber arg : args) { + applicator.checkCanceled(); + AbstractMsTypeApplier argApplier = applicator.getTypeApplier(arg); + + if (argApplier instanceof PrimitiveTypeApplier && + ((PrimitiveTypeApplier) argApplier).isNoType()) { + // Arguments list is empty. (There better not have been any arguments up until + // now.) + break; + } + +// if (argApplier instanceof AbstractDeferrableMsTypeApplier && +// ((AbstractDeferrableMsTypeApplier) argApplier).isDeferred()) { +// applicator.addApplierDependency(functionApplier, argApplier); +// functionApplier.setDeferred(); +// } + if (argApplier.isDeferred()) { + applicator.addApplierDependency(functionApplier, argApplier); + functionApplier.setDeferred(); + } + } + } + + /** + * Apply this to function ({@link AbstractFunctionTypeApplier}). + * @param functionApplier the {@link AbstractFunctionTypeApplier} to which to apply the + * arguments. + * @throws CancelledException Upon user cancellation + */ + public void applyTo(AbstractFunctionTypeApplier functionApplier) throws CancelledException { + FunctionDefinitionDataType functionDefinition = functionApplier.getFunctionDefinition(); + + AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType; + List args = argsList.getArgRecordNumbers(); + List parameterDefinitionList = new ArrayList<>(); + int parameterCount = 0; + for (RecordNumber arg : args) { + applicator.checkCanceled(); + AbstractMsTypeApplier argApplier = applicator.getTypeApplier(arg); + + if (argApplier instanceof PrimitiveTypeApplier && + ((PrimitiveTypeApplier) argApplier).isNoType()) { + // Arguments list is empty. (There better not have been any arguments up until + // now.) + break; + } + + DataType argDataType = argApplier.getDataType(); + if (argDataType == null) { + String message = + "PDB Warning: No type conversion for " + argApplier.getMsType().toString() + + " for parameter " + parameterCount + " of " + functionDefinition.getName(); + applicator.appendLogMsg(message); + } + else { + ParameterDefinition parameterDefinition = + new ParameterDefinitionImpl(null, argDataType, ""); + parameterDefinitionList.add(parameterDefinition); + parameterCount++; + } + } + functionDefinition.setArguments(parameterDefinitionList.toArray( + new ParameterDefinition[parameterDefinitionList.size()])); + } + +// /** +// * Apply this to function ({@link AbstractFunctionTypeApplier}). +// * @param functionApplier the {@link AbstractFunctionTypeApplier} to which to apply the +// * arguments. +// * @throws PdbException when unexpected function internals are found. +// * @throws CancelledException Upon user cancellation +// */ +// public void applyTo(AbstractFunctionTypeApplier functionApplier) +// throws CancelledException, PdbException { +// FunctionDefinitionDataType functionDefinition = functionApplier.getFunctionDefinition(); +// +// AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType; +// List list = argsList.getArgTypeIndexList(); +// List parameterDefinitionList = new ArrayList<>(); +// int parameterCount = 0; +// for (AbstractTypeIndex element : list) { +// applicator.getMonitor().checkCanceled(); +// AbstractMsTypeApplier argApplier = applicator.getTypeApplier(element.get()); +// +// if (argApplier instanceof PrimitiveTypeApplier && +// ((PrimitiveTypeApplier) argApplier).isNoType()) { +// // Arguments list is empty. (There better not have been any arguments up until +// // now.) +// break; +// } +// +// if (argApplier instanceof AbstractDeferrableMsTypeApplier && +// ((AbstractDeferrableMsTypeApplier) argApplier).isDeferred()) { +// applicator.addApplierDependency(functionApplier, argApplier); +// functionApplier.setDeferred(); +// } +// +//// applicator.addApplierDependency(functionApplier, argApplier); +// DataType argDataType = argApplier.getDataType(); +// if (argDataType == null) { +// String message = +// "PDB Warning: No type conversion for " + argApplier.getMsType().toString() + +// " for parameter " + parameterCount + " of " + functionDefinition.getName(); +// applicator.getLog().appendMsg(message); +// } +// else { +// ParameterDefinition parameterDefinition = +// new ParameterDefinitionImpl(null, argDataType, ""); +// parameterDefinitionList.add(parameterDefinition); +// parameterCount++; +// } +// } +// functionDefinition.setArguments(parameterDefinitionList.toArray( +// new ParameterDefinition[parameterDefinitionList.size()])); +// } +// +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java new file mode 100644 index 0000000000..9755a28393 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java @@ -0,0 +1,207 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractArrayMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.program.model.data.*; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractArrayMsType} types. + */ +public class ArrayTypeApplier extends AbstractMsTypeApplier { + + private boolean isDeferred = false; + + private AbstractMsTypeApplier underlyingTypeApplier = null; + private boolean isFlexibleArray = false; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractArrayMsType)) { + throw new IllegalArgumentException("PDB Incorrectly applying " + + type.getClass().getSimpleName() + " to " + ArrayTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for the applicator that applies a "array" type, transforming it into a + * Ghidra DataType. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractArrayMsType} to processes. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public ArrayTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + //============================================================================================== + public void setDeferred() { + isDeferred = true; + } + + @Override + public boolean isDeferred() { + return isDeferred; + } + + public boolean isFlexibleArray() { + return isFlexibleArray; + } + + @Override + void deferredApply() throws PdbException, CancelledException { + // No work done here. Just deferring resolve. + } + + //============================================================================================== + @Override + public BigInteger getSize() { + return ((AbstractArrayMsType) msType).getSize(); + } + + @Override + public void apply() throws PdbException, CancelledException { + applyOrDeferForDependencies(); + } + + private void applyOrDeferForDependencies() { + AbstractArrayMsType type = (AbstractArrayMsType) msType; + underlyingTypeApplier = applicator.getTypeApplier(type.getElementTypeRecordNumber()); + if (underlyingTypeApplier instanceof ModifierTypeApplier) { + underlyingTypeApplier = + ((ModifierTypeApplier) underlyingTypeApplier).getModifiedTypeApplier(); + } + underlyingTypeApplier = underlyingTypeApplier.getDependencyApplier(); + applyType(type); // applying now, but resolve() might get deferred. + } + +// private void recurseAddDependency(AbstractMsTypeApplier dependee) +// throws CancelledException, PdbException { +// if (dependee instanceof ModifierTypeApplier) { +// ModifierTypeApplier modifierApplier = (ModifierTypeApplier) dependee; +// recurseAddDependency(modifierApplier.getModifiedTypeApplier()); +// } +// else if (dependee instanceof CompositeTypeApplier) { +// CompositeTypeApplier defApplier = +// ((CompositeTypeApplier) dependee).getDefinitionApplier(); +// if (defApplier != null) { +// applicator.addApplierDependency(this, defApplier); +// } +// else { +// applicator.addApplierDependency(this, dependee); +// } +// setDeferred(); +// } +// else if (dependee instanceof ArrayTypeApplier) { +// applicator.addApplierDependency(this, dependee); +// setDeferred(); +// } +// else if (dependee instanceof BitfieldTypeApplier) { +// int x = +// ((AbstractBitfieldMsType) ((BitfieldTypeApplier) dependee).getMsType()).getElementTypeIndex(); +// AbstractMsTypeApplier underlyingApplier = applicator.getTypeApplier(x); +// if (underlyingApplier instanceof EnumTypeApplier) { +// applicator.addApplierDependency(this, underlyingApplier); +// setDeferred(); +// } +// } +// //We are assuming that bitfields on typedefs will not be defined. +// } +// + + private void applyType(AbstractArrayMsType type) { + applyArrayMsType((AbstractArrayMsType) msType); + } + + private void applyArrayMsType(AbstractArrayMsType type) { + if (isApplied()) { + return; + } + + long longUnderlyingSize = + PdbApplicator.bigIntegerToLong(applicator, underlyingTypeApplier.getSize()); + DataType underlyingDataType = underlyingTypeApplier.getDataType(); + + if (longUnderlyingSize > Integer.MAX_VALUE) { + String msg = "PDB " + type.getClass().getSimpleName() + ": Underlying type too large " + + underlyingDataType.getName(); + Msg.warn(this, msg); + underlyingDataType = Undefined1DataType.dataType; + longUnderlyingSize = 1L; + } + else if (longUnderlyingSize == 0L) { + String msg = "PDB " + type.getClass().getSimpleName() + + ": Zero-sized underlying type " + underlyingDataType.getName(); + Msg.warn(this, msg); + underlyingDataType = Undefined1DataType.dataType; + longUnderlyingSize = 1L; + } + + long longArraySize = getSizeLong(); + long longNumElements = longArraySize / longUnderlyingSize; + + if (longNumElements > Integer.MAX_VALUE) { + String msg = "PDB " + type.getClass().getSimpleName() + + ": Array num elements too large: " + longUnderlyingSize; + Msg.warn(this, msg); + longNumElements = 1L; + } + else if (longArraySize == 0) { + //flexible array + longNumElements = 0L; + } + else if (longArraySize % longUnderlyingSize != 0L) { + String msg = "PDB " + type.getClass().getSimpleName() + + ": Array num elements calculation error underlying type " + longArraySize + " % " + + longUnderlyingSize; + Msg.warn(this, msg); + // bad calculation. Underlying type does not evenly fit into array total size. + underlyingDataType = Undefined1DataType.dataType; + longUnderlyingSize = 1L; + longNumElements = longArraySize; + } + + int numElements = (int) longNumElements; + + ArrayDataType arrayDataType; + + // TODO: Need to find way to pass errorComment on to encompassing composite or other + if (numElements == 0) { + // flexible array + arrayDataType = new ArrayDataType(underlyingDataType, 1, underlyingDataType.getLength(), + applicator.getDataTypeManager()); + isFlexibleArray = true; + } + else { + arrayDataType = new ArrayDataType(underlyingDataType, numElements, -1, + applicator.getDataTypeManager()); + isFlexibleArray = false; + } + + setApplied(); + + dataType = arrayDataType; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java new file mode 100644 index 0000000000..236a1e48b1 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java @@ -0,0 +1,147 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +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.*; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, and + * {@link AbstractIndirectVirtualBaseClassMsType} types. + */ +public class BaseClassTypeApplier extends AbstractMsTypeApplier { + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractBaseClassMsType) && + !(type instanceof AbstractVirtualBaseClassMsType) && + !(type instanceof AbstractIndirectVirtualBaseClassMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + BaseClassTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for base class applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, or + * {@link AbstractIndirectVirtualBaseClassMsType} to processes. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public BaseClassTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + // The MsTypes for which we are working do not have a size in and of themselves, but the + // classes/structures to which they refer have a size, even if zero. + // For here, we are only reporting what "we" have, not what the underlying sizes are. + // ...and a value of zero is our "don't know" and "not represented" value. + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + + /** + * Returns the offset of the Base Class within the inheriting class. + * @return the offset. + * @throws PdbException if field is not available. + */ + public BigInteger getOffset() throws PdbException { + if (msType instanceof AbstractBaseClassMsType) { + return ((AbstractBaseClassMsType) msType).getOffset(); + } + throw new PdbException("Offset is not a valid field"); + } + + /** + * Returns the offset of the base base pointer within the class. + * @return the offset. + * @throws PdbException if field is not available. + */ + public BigInteger getBasePointerOffset() throws PdbException { + if (msType instanceof AbstractBaseClassMsType) { + throw new PdbException("Base Pointer Offset is not valid field"); + } + else if (msType instanceof AbstractVirtualBaseClassMsType) { + return ((AbstractVirtualBaseClassMsType) msType).getBasePointerOffset(); + } + return ((AbstractIndirectVirtualBaseClassMsType) msType).getBasePointerOffset(); + } + + /** + * Returns the attributes of the base class within the inheriting class. + * @return the attributes; + */ + public ClassFieldMsAttributes getAttributes() { + if (msType instanceof AbstractBaseClassMsType) { + return ((AbstractBaseClassMsType) msType).getAttributes(); + } + else if (msType instanceof AbstractVirtualBaseClassMsType) { + return ((AbstractVirtualBaseClassMsType) msType).getAttributes(); + } + return ((AbstractIndirectVirtualBaseClassMsType) msType).getAttributes(); + } + + /** + * Returns the record number of the base class. + * @return the record number; + */ + public RecordNumber getBaseClassRecordNumber() { + if (msType instanceof AbstractBaseClassMsType) { + return ((AbstractBaseClassMsType) msType).getBaseClassRecordNumber(); + } + else if (msType instanceof AbstractVirtualBaseClassMsType) { + return ((AbstractVirtualBaseClassMsType) msType).getBaseClassRecordNumber(); + } + return ((AbstractIndirectVirtualBaseClassMsType) msType).getBaseClassRecordNumber(); + } + + /** + * Returns whether there is a Virtual Base Pointer type index available. + * @return {@code true} if available. + */ + public boolean hasVirtualBasePointerTypeIndex() { + return (!(msType instanceof AbstractBaseClassMsType)); + } + + /** + * Returns the record number of the virtual base pointer. + * @return the record number; + * @throws PdbException if not a virtual base class. + */ + public RecordNumber getVirtualBasePointerRecordNumber() throws PdbException { + if (msType instanceof AbstractVirtualBaseClassMsType) { + return ((AbstractVirtualBaseClassMsType) msType).getVirtualBasePointerRecordNumber(); + } + else if (msType instanceof AbstractIndirectVirtualBaseClassMsType) { + return ((AbstractIndirectVirtualBaseClassMsType) msType).getVirtualBasePointerRecordNumber(); + } + throw new PdbException("Not a virtual base class"); + } + + @Override + public void apply() throws PdbException, CancelledException { + // do nothing at the moment. + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java new file mode 100644 index 0000000000..895257c2b4 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java @@ -0,0 +1,112 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +import ghidra.app.util.bin.format.pdb.PdbBitField; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractBitfieldMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.InvalidDataTypeException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractBitfieldMsType} types. + */ +public class BitfieldTypeApplier extends AbstractMsTypeApplier { + private AbstractMsTypeApplier elementTypeApplier = null; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractBitfieldMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + BitfieldTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for bitfield applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractBitfieldMsType} to processes + * @throws IllegalArgumentException Upon invalid arguments. + */ + public BitfieldTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + if (elementTypeApplier == null) { + return BigInteger.ZERO; + } + return elementTypeApplier.getSize(); + } + + @Override + public void apply() throws PdbException, CancelledException { + // The bitfield does not get resolved/commited to the DataTypeManager. + dataType = applyBitfieldMsType((AbstractBitfieldMsType) msType); + } + + private DataType applyBitfieldMsType(AbstractBitfieldMsType type) { + elementTypeApplier = applicator.getTypeApplier(type.getElementRecordNumber()); + if (elementTypeApplier instanceof ModifierTypeApplier) { + elementTypeApplier = + ((ModifierTypeApplier) elementTypeApplier).getModifiedTypeApplier(); + } + if (!(elementTypeApplier instanceof PrimitiveTypeApplier || + (elementTypeApplier instanceof EnumTypeApplier))) { + applicator.appendLogMsg( + "Unable to process underlying type for Bitfield: " + type.getName()); + return null; + } + DataType baseDataType = elementTypeApplier.getDataType(); + + DataType bitFieldDataType = null; + try { + bitFieldDataType = new Pdb2BitField(baseDataType.clone(applicator.getDataTypeManager()), + type.getBitLength(), type.getBitPosition()); + } + catch (InvalidDataTypeException e) { + applicator.appendLogMsg( + "Problem creating PdbBitField for " + type.getName() + ", error: " + e.toString()); + return null; + } + return bitFieldDataType; + } + + @Override + public void resolve() { + // Do not resolve Bitfield Types... will be resolved with composite!!! + } + + /** + * Pdb2BitField provides ability to hang onto bitfield as a datatype. + * This will be transformed to a normal BitFieldDataType when cloned. + */ + private class Pdb2BitField extends PdbBitField { + private Pdb2BitField(DataType baseDataType, int bitSize, int bitOffsetWithinBaseType) + throws InvalidDataTypeException { + super(baseDataType, bitSize, bitOffsetWithinBaseType); + } + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockCommentsManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockCommentsManager.java new file mode 100644 index 0000000000..e6a6f01aef --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockCommentsManager.java @@ -0,0 +1,134 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.HashMap; +import java.util.Map; + +import ghidra.app.cmd.comments.SetCommentCmd; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.CodeUnit; +import ghidra.program.model.listing.Program; + +public class BlockCommentsManager { + + private static final String BLOCK_INDENT = " "; + +// private int symbolBlockNestingLevel; + private Map blockPreComments; + private Map blockPostComments; + + BlockCommentsManager() { +// symbolBlockNestingLevel = 0; + blockPreComments = new HashMap<>(); + blockPostComments = new HashMap<>(); + } + + void applyTo(Program program) { + applyTo(program, 0L); + } + + void applyTo(Program program, long addressDelta) { + finalizeBlockComments(program, addressDelta); + } + +// int beginBlock(Address startAddress, String name, long length) { +// ++symbolBlockNestingLevel; +// addBlockComment(startAddress, name, length, symbolBlockNestingLevel); +// return symbolBlockNestingLevel; +// } +// +// int endBlock() throws PdbException { +// if (--symbolBlockNestingLevel < 0) { +// // TODO: eliminate exception and handle another way. +// throw new PdbException("Block Nesting went negative"); +// } +// if (symbolBlockNestingLevel == 0) { +// //currentFunctionSymbolApplier = null; +// } +// return symbolBlockNestingLevel; +// } +// +// int getBlockNestingLevel() { +// return symbolBlockNestingLevel; +// } +// + void addPreComment(Address address, String preComment) { + String existingPreComment = blockPreComments.get(address); + preComment = + (existingPreComment == null) ? preComment : existingPreComment + "\n" + preComment; + blockPreComments.put(address, preComment); + } + + void addPostComment(Address address, String postComment) { + String existingPostComment = blockPostComments.get(address); + postComment = + (existingPostComment == null) ? postComment : postComment + "\n" + existingPostComment; + blockPostComments.put(address, postComment); + } + + void addBlockComment(Address startAddress, String name, long length, int nestingLevel) { + String indent = ""; + for (int i = 1; i < nestingLevel; i++) { + indent += BLOCK_INDENT; + } + + String baseComment = "level " + nestingLevel + ", length " + length; + String preComment = indent + "PDB: Block Beg, " + baseComment; + if (!name.isEmpty()) { + preComment += " (" + name + ")"; + } + String postComment = indent + "PDB: Block End, " + baseComment; + + addPreComment(startAddress, preComment); +// String existingPreComment = blockPreComments.get(startAddress); +// preComment = +// (existingPreComment == null) ? preComment : existingPreComment + "\n" + preComment; +// blockPreComments.put(startAddress, preComment); + + Address endAddress = startAddress.add(((length <= 0) ? 0 : length - 1)); + addPostComment(endAddress, postComment); +// Address endCodeUnitAddress = +// program.getListing().getCodeUnitContaining(endAddress).getAddress(); +// +// processPostComment(endCodeUnitAddress, postComment); +// String existingPostComment = blockPostComments.get(endCodeUnitAddress); +// postComment = +// (existingPostComment == null) ? postComment : postComment + "\n" + existingPostComment; +// blockPostComments.put(endCodeUnitAddress, postComment); + } + + private void finalizeBlockComments(Program program, long addressDelta) { + for (Map.Entry entry : blockPreComments.entrySet()) { + appendBlockComment(program, entry.getKey().add(addressDelta), entry.getValue(), + CodeUnit.PRE_COMMENT); + } + for (Map.Entry entry : blockPostComments.entrySet()) { + Address endCodeUnitAddress = program.getListing().getCodeUnitContaining( + entry.getKey().add(addressDelta)).getAddress(); + appendBlockComment(program, endCodeUnitAddress, entry.getValue(), + CodeUnit.POST_COMMENT); + } + } + + private void appendBlockComment(Program program, Address address, String text, + int commentType) { + String comment = program.getListing().getComment(commentType, address); + comment = (comment == null) ? text : comment + "\n" + text; + SetCommentCmd.createComment(program, address, comment, commentType); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java new file mode 100644 index 0000000000..7ad4e8900b --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java @@ -0,0 +1,65 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +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.symbol.AbstractBlockMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractBlockMsSymbol} symbols. + */ +public class BlockSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractBlockMsSymbol symbol; + + public BlockSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractBlockMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractBlockMsSymbol) abstractSymbol; + } + + @Override + public void apply() throws PdbException, CancelledException { + String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; + Msg.info(this, message); + PdbLog.message(message); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing + } + + @Override + public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + if (applierParam instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; + Address address = applicator.reladdr(symbol); + functionSymbolApplier.beginBlock(address, symbol.getName(), symbol.getLength()); + } + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java new file mode 100644 index 0000000000..bf28bbf429 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java @@ -0,0 +1,231 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.*; + +import ghidra.app.util.SymbolPath; +import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Two-way Maps forward references with corresponding definitions for composites and enums. + * Uses the fwdref and definition members of the AbstractComplexTypeApplier. + */ +// We have probably tried 5 or more ways of doing this, all with mixed results. The current +// implementation seems to yield the best results at the moment. Keeping some of the old code +// around until we are solid on our algorithm and until we document some of the various algorithms +// tried. +public class ComplexTypeApplierMapper { + + private PdbApplicator applicator; + +// private Map complexTypeAppliersBySymbolPath; + private Map> compositeAppliersQueueBySymbolPath; + private Map> enumAppliersQueueBySymbolPath; + + //============================================================================================== + public ComplexTypeApplierMapper(PdbApplicator applicator) { + Objects.requireNonNull(applicator, "applicator cannot be null"); + this.applicator = applicator; +// complexTypeAppliersBySymbolPath = new HashMap<>(); + compositeAppliersQueueBySymbolPath = new HashMap<>(); + enumAppliersQueueBySymbolPath = new HashMap<>(); + } + + //============================================================================================== + //============================================================================================== + void mapAppliers(TaskMonitor monitor) throws CancelledException { + int indexLimit = applicator.getPdb().getTypeProgramInterface().getTypeIndexMaxExclusive(); + int indexNumber = applicator.getPdb().getTypeProgramInterface().getTypeIndexMin(); + monitor.initialize(indexLimit - indexNumber); + applicator.setMonitorMessage("PDB: Mapping Composites..."); + while (indexNumber < indexLimit) { + monitor.checkCanceled(); + PdbResearch.checkBreak(indexNumber); + AbstractMsTypeApplier applier = + applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber++)); + // From real data, we know that an enum and a composite both had the same SymbolPath, + // so enums and composites must be maintained separately so they do not get matched + // with each other. + if (applier instanceof CompositeTypeApplier) { +// mapComplexApplierBySymbolPath(compositeAppliersFwdRefQueueBySymbolPath, +// (AbstractComplexTypeApplier) applier); + mapComplexApplierTwoWayBySymbolPath(compositeAppliersQueueBySymbolPath, + (AbstractComplexTypeApplier) applier); + } + else if (applier instanceof EnumTypeApplier) { +// mapComplexApplierBySymbolPath(enumAppliersFwdRefQueueBySymbolPath, +// (AbstractComplexTypeApplier) applier); + mapComplexApplierTwoWayBySymbolPath(enumAppliersQueueBySymbolPath, + (AbstractComplexTypeApplier) applier); + } +// if (applier instanceof AbstractComplexTypeApplier) { +// mapComplexApplierByQueue((AbstractComplexTypeApplier) applier); +// //mapComplexApplierForwardOnly((AbstractComplexTypeApplier) applier); +// //mapComplexApplier((AbstractComplexTypeApplier) applier); +// } + monitor.incrementProgress(1); + } + } + + private void mapComplexApplierTwoWayBySymbolPath( + Map> applierQueueBySymbolPath, + AbstractComplexTypeApplier complexApplier) { + SymbolPath symbolPath = complexApplier.getSymbolPath(); + Objects.requireNonNull(symbolPath, "SymbolPath may not be null"); + + LinkedList appliers = applierQueueBySymbolPath.get(symbolPath); + if (appliers == null) { + appliers = new LinkedList<>(); + applierQueueBySymbolPath.put(symbolPath, appliers); + // Putting fwdref or def (doesn't matter which it is) + if (!appliers.add(complexApplier)) { + // Error + } + } + else if (appliers.peekFirst().isForwardReference() == complexApplier.isForwardReference()) { + // Only need to look at first on list, as all on list are the same fwdref or def. + // If same as what is on list, add to the list. + if (!appliers.add(complexApplier)) { + // Error + } + } + else { + if (complexApplier.isForwardReference()) { + AbstractComplexTypeApplier defApplier = appliers.removeFirst(); + defApplier.setFwdRefApplier(complexApplier); + complexApplier.setDefinitionApplier(defApplier); + } + else { + AbstractComplexTypeApplier fwdApplier = appliers.removeFirst(); + fwdApplier.setDefinitionApplier(complexApplier); + complexApplier.setFwdRefApplier(fwdApplier); + } + if (appliers.isEmpty()) { + // Do not need to keep all of these around. + applierQueueBySymbolPath.remove(symbolPath); + } + } + } + +// private void mapComplexApplier(AbstractComplexTypeApplier complexApplier) { +// SymbolPath symbolPath = complexApplier.getSymbolPath(); +// +// AbstractComplexTypeApplier cachedComplexApplier = +// getComplexTypeApplierBySymbolPath(symbolPath, complexApplier.getClass()); +// if (cachedComplexApplier == null) { +// // Setting cache if not already set or setting to definition. +// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier); +// } +// else if (cachedComplexApplier.isForwardReference()) { +// if (!complexApplier.isForwardReference()) { +// cachedComplexApplier.setDefinitionApplier(complexApplier); +// complexApplier.setFwdRefApplier(cachedComplexApplier); +// } +// // Setting cache to new applier, whether fwd ref or definition. +// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier); +// } +// else { // cached is definition +// if (!complexApplier.isForwardReference()) { // we are definition +// // Setting cache if not already set or setting to definition. +// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier); +// } +// else { // we are forward ref +// AbstractComplexTypeApplier fwdRef = +// cachedComplexApplier.getFwdRefApplier(complexApplier.getClass()); +// if (fwdRef == null) { +// // cached definition did not have a forward ref but we are one, so hook it up? +// // problem is if a definition follows... ugh. Not sure want to do this. +// complexApplier.setDefinitionApplier(cachedComplexApplier); +// cachedComplexApplier.setFwdRefApplier(complexApplier); +// // would like to cache a forward ref, but are are tying it to a previous +// // definition, so not. +// } +// else { +// // Setting cache if not already set or setting to definition. +// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier); +// } +// } +// } +// } +// +// // Only caching forward ref and then mapping only following def to fwdref. +// // Clearing cache after that def so next def does not map. +// private void mapComplexApplierForwardOnly(AbstractComplexTypeApplier complexApplier) { +// SymbolPath symbolPath = complexApplier.getSymbolPath(); +// +// if (complexApplier.isForwardReference()) { +// putComplexTypeApplierBySymbolPath(symbolPath, complexApplier); +// } +// else { +// AbstractComplexTypeApplier cachedComplexApplier = +// getComplexTypeApplierBySymbolPath(symbolPath, complexApplier.getClass()); +// if (cachedComplexApplier != null) { +// cachedComplexApplier.setDefinitionApplier(complexApplier); +// complexApplier.setFwdRefApplier(cachedComplexApplier); +// // set cache back to null +// complexTypeAppliersBySymbolPath.remove(symbolPath); +// } +// } +// } +// +// private void putComplexTypeApplierBySymbolPath(SymbolPath symbolPath, +// AbstractComplexTypeApplier applier) { +// Objects.requireNonNull(symbolPath, "SymbolPath may not be null"); +// Objects.requireNonNull(applier, "CompositeTypeApplier may not be null"); +// complexTypeAppliersBySymbolPath.put(symbolPath, applier); +// } +// +// private T getComplexTypeApplierBySymbolPath( +// SymbolPath symbolPath, Class typeClass) { +// Objects.requireNonNull(symbolPath, "SymbolPath may not be null"); +// Objects.requireNonNull(typeClass, "typeClass may not be null"); +// AbstractComplexTypeApplier applier = complexTypeAppliersBySymbolPath.get(symbolPath); +// if (!typeClass.isInstance(applier)) { +// return null; +// } +// return typeClass.cast(applier); +// } +// +// //============================================================================================== +// private void mapComplexApplierBySymbolPath( +// Map> applierQueueBySymbolPath, +// AbstractComplexTypeApplier complexApplier) { +// SymbolPath symbolPath = complexApplier.getSymbolPath(); +// Objects.requireNonNull(symbolPath, "SymbolPath may not be null"); +// +// LinkedList fwdList = applierQueueBySymbolPath.get(symbolPath); +// if (fwdList == null) { +// fwdList = new LinkedList<>(); +// applierQueueBySymbolPath.put(symbolPath, fwdList); +// } +// +// if (complexApplier.isForwardReference()) { +// if (!fwdList.add(complexApplier)) { +// // Error +// } +// } +// else if (!fwdList.isEmpty()) { +// AbstractComplexTypeApplier fwdApplier = fwdList.removeFirst(); +// fwdApplier.setDefinitionApplier(complexApplier); +// complexApplier.setFwdRefApplier(fwdApplier); +// } +// } +// + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java new file mode 100644 index 0000000000..13f15adbe1 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java @@ -0,0 +1,52 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.HashMap; +import java.util.Map; + +public enum CompositeLayoutMode { + MEMBERS_ONLY("Legacy", 0, OoComponentLayoutMode.MEMBERS_ONLY), + BASIC_SIMPLE_COMPLEX("Complex with Basic Fallback", 1, OoComponentLayoutMode.BASIC), + SIMPLE_COMPLEX("Complex with Simple Fallback", 2, OoComponentLayoutMode.SIMPLE), + COMPLEX("Complex Always", 3, OoComponentLayoutMode.COMPLEX); + + private static final Map BY_VALUE = new HashMap<>(); + static { + for (CompositeLayoutMode val : values()) { + BY_VALUE.put(val.value, val); + } + } + + public final String label; + private final int value; + private OoComponentLayoutMode layoutMode; + + @Override + public String toString() { + return label; + } + + private CompositeLayoutMode(String label, int value, OoComponentLayoutMode layoutMode) { + this.label = label; + this.value = value; + this.layoutMode = layoutMode; + } + + public OoComponentLayoutMode getLayoutMode() { + return layoutMode; + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java new file mode 100644 index 0000000000..16acd28ffc --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java @@ -0,0 +1,820 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; +import java.util.*; + +import ghidra.app.util.SymbolPath; +import ghidra.app.util.SymbolPathParser; +import ghidra.app.util.bin.format.pdb.DefaultCompositeMember; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.program.model.data.*; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/* + * Non java-doc: + * Some truths: + * For AbstractMsCompositeType: do not count on "count" to be zero when MsProperty is fwdref + * (we have seen example of count==0 and not fwdref, though the majority of the time the + * two go hand-in-hand. When these did not equate, it might have been when there was no + * need for a fwdref and possibly only one definition--this would require a closer look). + */ +/** + * Applier for {@link AbstractCompositeMsType} types. + */ +public class CompositeTypeApplier extends AbstractComplexTypeApplier { + + // DO NOT DELETE. Might eliminate one path or might make an analyzer option. + private static boolean applyBaseClasses = true; + //private static boolean applyBaseClasses = false; + + private boolean isDeferred = false; + private CppCompositeType classType; + +// private final static DataType NO_TYPE_DATATYPE = +// new TypedefDataType("", Undefined1DataType.dataType); +// + private Map componentComments; + + private List members; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractCompositeMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + CompositeTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for composite type applier, for transforming a composite into a + * Ghidra DataType. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractCompositeMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public CompositeTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + String fullPathName = ((AbstractCompositeMsType) msType).getName(); + symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName)); + } + + public CppCompositeType getClassType() { + if (definitionApplier != null) { + return ((CompositeTypeApplier) definitionApplier).getClassTypeInternal(); + } + return classType; + } + + CppCompositeType getClassTypeInternal() { + return classType; + } + + List getMembers() { + return members; + } + + // Mapping of fwdRef/def must be done prior to this call. + private void getOrCreateComposite() { + if (dataType != null) { + return; + } + if (isForwardReference()) { + if (definitionApplier != null) { + dataType = definitionApplier.getDataTypeInternal(); + classType = ((CompositeTypeApplier) definitionApplier).getClassTypeInternal(); + if (dataType != null) { + return; + } + } + } + else { + if (fwdRefApplier != null) { + dataType = fwdRefApplier.getDataTypeInternal(); + classType = ((CompositeTypeApplier) fwdRefApplier).getClassTypeInternal(); + if (dataType != null) { + return; + } + } + } + dataType = createEmptyComposite((AbstractCompositeMsType) msType); + String mangledName = ((AbstractCompositeMsType) msType).getMangledName(); + classType = new CppCompositeType((Composite) dataType, mangledName); + classType.setName(getName()); + classType.setSize(PdbApplicator.bigIntegerToInt(applicator, getSize())); + if (msType instanceof AbstractClassMsType) { + classType.setClass(); + } + else if (msType instanceof AbstractStructureMsType) { + classType.setStruct(); + } + else if (msType instanceof AbstractUnionMsType) { + classType.setUnion(); + } + classType.setFinal(isFinal()); + + } + + @Override + public void apply() throws PdbException, CancelledException { + + getOrCreateComposite(); + + Composite composite = (Composite) dataType; + + AbstractCompositeMsType type = (AbstractCompositeMsType) msType; + MsProperty property = type.getMsProperty(); + if (property.isForwardReference() && definitionApplier != null) { + return; + } + if (!(composite instanceof CompositeDataTypeImpl)) { + return; // A resolved version exists (multiple definitions). + } + applyOrDeferForDependencies(); + } + + @Override + public void resolve() { + if (!isForwardReference()) { + super.resolve(); + } + } + + private void applyOrDeferForDependencies() throws PdbException, CancelledException { + AbstractCompositeMsType type = (AbstractCompositeMsType) msType; + MsProperty property = type.getMsProperty(); + if (property.isForwardReference() && definitionApplier != null) { + return; + } + + // Add self + applicator.addApplierDependency(this); + + // Add any dependees: base classes and members + FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( + applicator, type.getFieldDescriptorListRecordNumber()); + + // Currently do not need this dependency, as we currently do not need any contents + // of the base class for filling in this class + for (AbstractMsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) { + if (baseApplierIterated instanceof BaseClassTypeApplier) { + BaseClassTypeApplier baseTypeApplier = (BaseClassTypeApplier) baseApplierIterated; + AbstractMsTypeApplier applier = + applicator.getTypeApplier(baseTypeApplier.getBaseClassRecordNumber()); + if (applier instanceof CompositeTypeApplier) { + CompositeTypeApplier dependencyApplier = + ((CompositeTypeApplier) applier).getDependencyApplier(); + applicator.addApplierDependency(this, dependencyApplier); +// CompositeTypeApplier defApplier = +// ((CompositeTypeApplier) applier).getDefinitionApplier(); +// if (defApplier != null) { +// applicator.addApplierDependency(this, defApplier); +// } +// else { +// applicator.addApplierDependency(this, applier); +// } + setDeferred(); + } + } + } + for (AbstractMsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) { + applicator.checkCanceled(); + if (memberTypeApplierIterated instanceof MemberTypeApplier) { + MemberTypeApplier memberTypeApplier = (MemberTypeApplier) memberTypeApplierIterated; + AbstractMsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier(); + recurseAddDependency(fieldApplier); + } +// if (memberTypeApplierIterated instanceof NestedTypeApplier) { +// recurseAddDependency(memberTypeApplierIterated); +// } + else if (memberTypeApplierIterated instanceof VirtualFunctionTablePointerTypeApplier) { + applicator.addApplierDependency(this, memberTypeApplierIterated); + } + } + if (!isDeferred()) { + applyInternal(); + } + } + + private void recurseAddDependency(AbstractMsTypeApplier dependee) + throws CancelledException, PdbException { + if (dependee instanceof ModifierTypeApplier) { + ModifierTypeApplier modifierApplier = (ModifierTypeApplier) dependee; + recurseAddDependency(modifierApplier.getModifiedTypeApplier()); + } + else if (dependee instanceof CompositeTypeApplier) { + CompositeTypeApplier defApplier = + ((CompositeTypeApplier) dependee).getDefinitionApplier(CompositeTypeApplier.class); + if (defApplier != null) { + applicator.addApplierDependency(this, defApplier); + } + else { + applicator.addApplierDependency(this, dependee); + } + setDeferred(); + } + else if (dependee instanceof ArrayTypeApplier) { + applicator.addApplierDependency(this, dependee); + setDeferred(); + } +// else if (dependee instanceof NestedTypeApplier) { +// NestedTypeApplier nestedTypeApplier = (NestedTypeApplier) dependee; +// AbstractMsTypeApplier nestedDefinitionApplier = +// nestedTypeApplier.getNestedTypeDefinitionApplier(); +// // Need to make sure that "this" class id dependent on all elements composing the +// // nested definition, but we need to create the nested definition during the +// // creation of this class. (NestedTypeApplier and NestedTypeMsType do not really +// // have their own RecordNumber). +// applicator.addApplierDependency(this, nestedDefinitionApplier); +// setDeferred(); +// } + else if (dependee instanceof BitfieldTypeApplier) { + RecordNumber recNum = + ((AbstractBitfieldMsType) ((BitfieldTypeApplier) dependee).getMsType()).getElementRecordNumber(); + AbstractMsTypeApplier underlyingApplier = applicator.getTypeApplier(recNum); + if (underlyingApplier instanceof EnumTypeApplier) { + applicator.addApplierDependency(this, underlyingApplier); + setDeferred(); + } + } + //We are assuming that bitfields on typedefs will not be defined. + } + + public void applyInternal() throws CancelledException, PdbException { + + if (isApplied()) { + return; + } + Composite composite = (Composite) dataType; + + AbstractCompositeMsType type = (AbstractCompositeMsType) msType; + + boolean applyCpp = applyBaseClasses; + if (type instanceof AbstractUnionMsType) { + applyCpp = false; + if (hasBaseClasses()) { + String msg = "Unexpected base classes for union type: " + type.getName(); + PdbLog.message(msg); + Msg.info(this, msg); + } + } + if (applyCpp) { + applyCpp(composite, type); + } + else { + applyBasic(composite, type); + } + setApplied(); + } + + //============================================================================================== + void applyBasic(Composite composite, AbstractCompositeMsType type) + throws CancelledException, PdbException { + + //boolean isClass = (type instanceof AbstractClassMsType || actsLikeClass(applicator, type)); + boolean isClass = (type instanceof AbstractClassMsType); + + int size = getSizeInt(); + + // Fill in composite definition details. + FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( + applicator, type.getFieldDescriptorListRecordNumber()); + + clearComponents(composite); + members = new ArrayList<>(); + componentComments = new HashMap<>(); + + addMembers(composite, fieldListApplier); + + if (!DefaultCompositeMember.applyDataTypeMembers(composite, isClass, size, members, + msg -> reconstructionWarn(msg), applicator.getCancelOnlyWrappingMonitor())) { + clearComponents(composite); + } + + setComponentComments(composite); + } + + private void setComponentComments(Composite composite) { + if (composite instanceof Structure) { + Structure structure = (Structure) composite; + for (Map.Entry entry : componentComments.entrySet()) { + DataTypeComponent component = structure.getComponentAt(entry.getKey()); + if (component == null) { + String message = "Could not set comment for 'missing' componenent " + + entry.getKey() + " for: " + structure.getName(); + PdbLog.message(message); + Msg.info(this, message); + return; + } + component.setComment(entry.getValue()); + } + } + } + + //============================================================================================== + void applyCpp(Composite composite, AbstractCompositeMsType type) + throws PdbException, CancelledException { + // Fill in composite definition details. + FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( + applicator, type.getFieldDescriptorListRecordNumber()); + clearComponents(composite); + members = new ArrayList<>(); // TODO: temporary for old "basic" mechanism + componentComments = new HashMap<>(); // TODO: temporary for old "basic" mechanism + + addClassTypeBaseClasses(composite, fieldListApplier); + addMembers(composite, fieldListApplier); + + if (!classType.validate()) { + // TODO: Investigate. We should do this check for some classes somewhere. Should + // we do it here. Set breakpoint here to investigate. + } + classType.createLayout(applicator.getPdbApplicatorOptions().getCompositeLayoutMode(), + applicator.getVbtManager(), applicator.getCancelOnlyWrappingMonitor()); + } + + //============================================================================================== + private void reconstructionWarn(String msg) { + //TODO: if statement/contents temporary + if (msg.contains("failed to align") && hasHiddenComponents()) { + msg = msg.replaceFirst("PDB", "PDB CLASS"); + } + Msg.warn(this, msg); + } + + //============================================================================================== + public void setDeferred() { + isDeferred = true; + } + + @Override + public boolean isDeferred() { + return isDeferred; + } + + @Override + void deferredApply() throws PdbException, CancelledException { + if (isDeferred()) { + applyInternal(); + } + } + + //============================================================================================== + //============================================================================================== + @Override + public CompositeTypeApplier getDependencyApplier() { + if (definitionApplier != null && definitionApplier instanceof CompositeTypeApplier) { + return (CompositeTypeApplier) definitionApplier; + } + return this; + } + + public String getName() { + return getMsType().getName(); + } + + @Override + public DataType getDataType() { + if (resolved) { + return resolvedDataType; + } + getOrCreateComposite(); + return dataType; + } + + @Override + DataType getCycleBreakType() { + if (isForwardReference() && definitionApplier != null && definitionApplier.isApplied()) { + return definitionApplier.getDataType(); + } + return dataType; + } + + public boolean hasUniqueName() { + return ((AbstractCompositeMsType) msType).getMsProperty().hasUniqueName(); + } + + @Override + public BigInteger getSize() { + return ((AbstractCompositeMsType) getDependencyApplier().getMsType()).getSize(); + } + + // TODO: + // Taken from PdbUtil without change. Would have had to change access on class PdbUtil and + // this ensureSize method to public to make it accessible. Can revert to using PdbUtil + // once we move this new module from Contrib to Features/PDB. + final static void clearComponents(Composite composite) { + if (composite instanceof Structure) { + ((Structure) composite).deleteAll(); + } + else { + while (composite.getNumComponents() > 0) { + composite.delete(0); + } + } + } + + private Composite createEmptyComposite(AbstractCompositeMsType type) { + + SymbolPath fixedPath = getFixedSymbolPath(); + CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent()); + + Composite composite; + if (type instanceof AbstractClassMsType) { + applicator.predefineClass(fixedPath); + composite = new StructureDataType(categoryPath, fixedPath.getName(), 0, + applicator.getDataTypeManager()); + } + else if (type instanceof AbstractStructureMsType) { + composite = new StructureDataType(categoryPath, fixedPath.getName(), 0, + applicator.getDataTypeManager()); + } + else if (type instanceof AbstractUnionMsType) { + composite = new UnionDataType(categoryPath, fixedPath.getName(), + applicator.getDataTypeManager()); + } + else { // InterfaceMsType + String message = "Unsupported datatype (" + type.getClass().getSimpleName() + "): " + + fixedPath.getPath(); + applicator.appendLogMsg(message); + return null; + } + return composite; + } + + private boolean hasBaseClasses() { + AbstractCompositeMsType defType; + if (definitionApplier == null) { + if (isForwardReference()) { + return false; + } + defType = (AbstractCompositeMsType) msType; + } + else { + defType = (AbstractCompositeMsType) definitionApplier.getMsType(); + } + AbstractMsTypeApplier applier = + applicator.getTypeApplier(defType.getFieldDescriptorListRecordNumber()); + if (!(applier instanceof FieldListTypeApplier)) { + return false; + } + FieldListTypeApplier fieldListApplier = (FieldListTypeApplier) applier; + AbstractFieldListMsType fieldListType = + ((AbstractFieldListMsType) fieldListApplier.getMsType()); + if (fieldListType.getBaseClassList().size() != 0) { + return true; + } + return (fieldListType.getBaseClassList().size() != 0); + } + + private boolean hasHiddenComponents() { + AbstractCompositeMsType defType; + if (definitionApplier == null) { + if (isForwardReference()) { + return false; + } + defType = (AbstractCompositeMsType) msType; + } + else { + defType = (AbstractCompositeMsType) definitionApplier.getMsType(); + } + + // Note: if a "class" only has structure fields--does not have member functions, base + // class, virtual inheritance, etc., then it acts like a structure, meaning that there + // should be no extra fields for pvft, pvbt, base and virtual class components. + // So... it might not be good to return "true" for just checking if the type is an + // instanceof AbstractClassMsType. + + AbstractMsTypeApplier applier = + applicator.getTypeApplier(defType.getFieldDescriptorListRecordNumber()); + if (!(applier instanceof FieldListTypeApplier)) { + return false; + } + FieldListTypeApplier fieldListApplier = (FieldListTypeApplier) applier; + AbstractFieldListMsType fieldListType = + ((AbstractFieldListMsType) fieldListApplier.getMsType()); + + return (fieldListType.getMethodList().size() != 0 || + fieldListType.getBaseClassList().size() != 0); + } + + private void addClassTypeBaseClasses(Composite composite, FieldListTypeApplier fieldListApplier) + throws PdbException { + + AbstractCompositeMsType type = (AbstractCompositeMsType) msType; + + for (AbstractMsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) { + if (!(baseApplierIterated instanceof BaseClassTypeApplier)) { + applicator.appendLogMsg(baseApplierIterated.getClass().getSimpleName() + + " seen where BaseClassTypeApplier expected for " + type.getName()); + continue; + } + BaseClassTypeApplier baseTypeApplier = (BaseClassTypeApplier) baseApplierIterated; + AbstractMsTypeApplier baseClassTypeApplier = + applicator.getTypeApplier(baseTypeApplier.getBaseClassRecordNumber()); + if (!(baseClassTypeApplier instanceof CompositeTypeApplier)) { + applicator.appendLogMsg(baseApplierIterated.getClass().getSimpleName() + + " seen where CompositeTypeApplier expected for " + type.getName()); + continue; + } + + AbstractMsType baseClassMsType = baseTypeApplier.getMsType(); + if (baseClassMsType instanceof AbstractBaseClassMsType) { + applyDirectBaseClass((AbstractBaseClassMsType) baseClassMsType); + } + else if (baseClassMsType instanceof AbstractVirtualBaseClassMsType) { + applyDirectVirtualBaseClass((AbstractVirtualBaseClassMsType) baseClassMsType); + } + else if (baseClassMsType instanceof AbstractIndirectVirtualBaseClassMsType) { + applyIndirectVirtualBaseClass( + (AbstractIndirectVirtualBaseClassMsType) baseClassMsType); + } + else { + throw new AssertException( + "Unknown base class type: " + baseClassMsType.getClass().getSimpleName()); + } + } + } + + private void applyDirectBaseClass(AbstractBaseClassMsType base) throws PdbException { + CppCompositeType underlyingClassType = + getUnderlyingClassType(base.getBaseClassRecordNumber()); + if (underlyingClassType == null) { + return; + } + ClassFieldMsAttributes atts = base.getAttributes(); + int offset = PdbApplicator.bigIntegerToInt(applicator, base.getOffset()); + classType.addDirectBaseClass(underlyingClassType, convertAttributes(atts), offset); + } + + private void applyDirectVirtualBaseClass(AbstractVirtualBaseClassMsType base) + throws PdbException { + CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber()); + if (underlyingCt == null) { + return; + } + DataType vbtptr = + getVirtualBaseTablePointerDataType(base.getVirtualBasePointerRecordNumber()); + ClassFieldMsAttributes atts = base.getAttributes(); + int basePointerOffset = + PdbApplicator.bigIntegerToInt(applicator, base.getBasePointerOffset()); + int offsetFromVbt = PdbApplicator.bigIntegerToInt(applicator, base.getBaseOffsetFromVbt()); + classType.addDirectVirtualBaseClass(underlyingCt, convertAttributes(atts), + basePointerOffset, vbtptr, offsetFromVbt); + } + + private void applyIndirectVirtualBaseClass(AbstractIndirectVirtualBaseClassMsType base) + throws PdbException { + CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber()); + if (underlyingCt == null) { + return; + } + DataType vbtptr = + getVirtualBaseTablePointerDataType(base.getVirtualBasePointerRecordNumber()); + ClassFieldMsAttributes atts = base.getAttributes(); + int basePointerOffset = + PdbApplicator.bigIntegerToInt(applicator, base.getBasePointerOffset()); + int offsetFromVbt = PdbApplicator.bigIntegerToInt(applicator, base.getBaseOffsetFromVbt()); + classType.addIndirectVirtualBaseClass(underlyingCt, convertAttributes(atts), + basePointerOffset, vbtptr, offsetFromVbt); + } + + private CppCompositeType getUnderlyingClassType(RecordNumber recordNumber) { + AbstractMsTypeApplier baseUnderlyingApplier = applicator.getTypeApplier(recordNumber); + if (!(baseUnderlyingApplier instanceof CompositeTypeApplier)) { + applicator.appendLogMsg(baseUnderlyingApplier.getClass().getSimpleName() + + " seen where CompositeTypeApplier expected for base class."); + return null; + } + CompositeTypeApplier baseApplier = (CompositeTypeApplier) baseUnderlyingApplier; + CppCompositeType underlyingClassType = baseApplier.getClassType(); + if (underlyingClassType == null) { + applicator.appendLogMsg("Underlying base class type is null."); + } + return underlyingClassType; + } + + private DataType getVirtualBaseTablePointerDataType(RecordNumber recordNumber) { + AbstractMsTypeApplier vbptrApplier = applicator.getTypeApplier(recordNumber); + if (vbptrApplier != null) { + if (vbptrApplier instanceof PointerTypeApplier) { + return vbptrApplier.getDataType(); + } + } + applicator.appendLogMsg("Generating a generic Virtual Base Table Pointer."); + return new PointerDataType(); + } + + private static CppCompositeType.ClassFieldAttributes convertAttributes( + ClassFieldMsAttributes atts) { + CppCompositeType.Access myAccess; + switch (atts.getAccess()) { + case PUBLIC: + myAccess = CppCompositeType.Access.PUBLIC; + break; + case PROTECTED: + myAccess = CppCompositeType.Access.PROTECTED; + break; + case PRIVATE: + myAccess = CppCompositeType.Access.PRIVATE; + break; + default: + myAccess = CppCompositeType.Access.BLANK; + break; + } + CppCompositeType.Property myProperty; + switch (atts.getProperty()) { + case VIRTUAL: + myProperty = CppCompositeType.Property.VIRTUAL; + break; + case STATIC: + myProperty = CppCompositeType.Property.STATIC; + break; + case FRIEND: + myProperty = CppCompositeType.Property.FRIEND; + break; + default: + myProperty = CppCompositeType.Property.BLANK; + break; + } + return new CppCompositeType.ClassFieldAttributes(myAccess, myProperty); + } + + private void addMembers(Composite composite, FieldListTypeApplier fieldListApplier) { + + AbstractCompositeMsType type = (AbstractCompositeMsType) msType; + + for (AbstractMsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) { + boolean handled = true; + if (memberTypeApplierIterated instanceof MemberTypeApplier) { + MemberTypeApplier memberTypeApplier = (MemberTypeApplier) memberTypeApplierIterated; + String memberName = memberTypeApplier.getName(); + + int offset = + PdbApplicator.bigIntegerToInt(applicator, memberTypeApplier.getOffset()); + ClassFieldMsAttributes memberAttributes = memberTypeApplier.getAttribute(); + memberAttributes.getAccess(); // TODO: do something with this and other attributes + AbstractMsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier(); + + if (fieldApplier instanceof CompositeTypeApplier) { + CompositeTypeApplier defApplier = + ((CompositeTypeApplier) fieldApplier).getDefinitionApplier( + CompositeTypeApplier.class); + if (defApplier != null) { + fieldApplier = defApplier; + } + } + DataType fieldDataType = fieldApplier.getDataType(); + boolean isFlexibleArray; + if (fieldApplier instanceof ArrayTypeApplier) { + isFlexibleArray = ((ArrayTypeApplier) fieldApplier).isFlexibleArray(); + } + else { + isFlexibleArray = false; + } + if (fieldDataType == null) { + if (fieldApplier instanceof PrimitiveTypeApplier && + ((PrimitiveTypeApplier) fieldApplier).isNoType()) { + Default2PdbMember member = + new Default2PdbMember(applicator, memberName, fieldApplier, offset); + members.add(member); + componentComments.put(offset, "NO_TYPE"); + } + else { + applicator.appendLogMsg("PDB Warning: No conversion for " + memberName + + " " + fieldApplier.getMsType().getClass().getSimpleName() + + " in composite " + composite.getName()); + } + } + else { + Default2PdbMember member = + new Default2PdbMember(applicator, memberName, fieldApplier, offset); + members.add(member); + classType.addMember(memberName, fieldDataType, isFlexibleArray, + convertAttributes(memberAttributes), offset); + } + } + else if (memberTypeApplierIterated instanceof EnumerateTypeApplier) { + EnumerateTypeApplier enumerateTypeApplier = + (EnumerateTypeApplier) memberTypeApplierIterated; + String fieldName = enumerateTypeApplier.getName(); + Numeric numeric = enumerateTypeApplier.getNumeric(); + // TODO: some work + PdbLog.message("Don't know how to apply EnumerateTypeApplier fieldName " + + fieldName + " and value " + numeric + " within " + msType.getName()); + } + else if (memberTypeApplierIterated instanceof VirtualFunctionTablePointerTypeApplier) { + VirtualFunctionTablePointerTypeApplier vtPtrApplier = + (VirtualFunctionTablePointerTypeApplier) memberTypeApplierIterated; + String vftPtrMemberName = vtPtrApplier.getMemberName(); + int offset = vtPtrApplier.getOffset(); + Default2PdbMember member = + new Default2PdbMember(applicator, vftPtrMemberName, vtPtrApplier, offset); + members.add(member); + //classType.addMember(vftPtrMemberName, vtPtrApplier.getDataType(), false, offset); + classType.addVirtualFunctionTablePointer(vftPtrMemberName, + vtPtrApplier.getDataType(), offset); + } + else if (memberTypeApplierIterated instanceof NestedTypeApplier) { + // Need to make sure that "this" class id dependent on all elements composing the + // nested definition, but we need to create the nested definition during the + // creation of this class. (NestedTypeApplier and NestedTypeMsType do not really + // have their own RecordNumber). + // 20200114: think this is a nested typedef. + NestedTypeApplier nestedTypeApplier = (NestedTypeApplier) memberTypeApplierIterated; + String memberTypeName = nestedTypeApplier.getTypeName(); + String memberName = nestedTypeApplier.getMemberName(); // use this + // TODO: we are assuming that the offset is zero (0) for the call. Need to dig + // more to confirm this. Is ever anything but just one nested type? The pdb.exe + // generates these all at offset 0. + // TODO: Nested types are currently an issue for + // DefaultCompositeMember.applyDataTypeMembers(). + // Need to investigate what to do here. It could be just when the specific + // composite is a member of itself. + if (type.getName().equals(memberTypeName)) { + // We are skipping because we've had issues and do not know what is going on + // at the moment. (I think they were dependency issues... been a while.) + // See not above the "if" condition. +// PdbLog.message("Skipping Composite Nested type member: " + memberName + +// " within " + type.getName()); + // TODO: Investigate. What does it mean when the internally defined type + // conficts with the name of the outer type. + continue; + } + // TODO: believe the thing to do is to show that these are types that are + // defined within the namespace of this containing type. This might be + // the place to do it... that is if we don't identify them separately + // falling under the namespace of this composite. + +// AbstractMsTypeApplier nestedDefinitionApplier = +// nestedTypeApplier.getNestedTypeDefinitionApplier().getDependencyApplier(); +// +// DataType ndt = nestedDefinitionApplier.getDataType(); //use this +// int ndtl = ndt.getLength(); //use this +// +// AbstractMsType ndms = nestedTypeApplier.getMsType(); +// +// BigInteger val = nestedTypeApplier.getSize(); +// int offset = 0; // ???? TODO.., +// DataType nt = nestedTypeApplier.getDataType(); +// ClassFieldMsAttributes a = nestedTypeApplier.getAttributes(); +// +// // TODO: hoping this is right... 20200521... how/where do we get offset? +// Default2PdbMember member = +// new Default2PdbMember(applicator, memberName, nestedDefinitionApplier, offset); +// members.add(member); + } + else if (memberTypeApplierIterated instanceof NoTypeApplier) { + AbstractMsType msNoType = memberTypeApplierIterated.getMsType(); + if (msNoType instanceof AbstractStaticMemberMsType) { + // TODO: Investigate anything that hits here (set break point), see if we + // see dot apply the information. If so, probably should create an applier + // for the contained MS type. + } + else { + handled = false; + } + } + else { + handled = false; + } + if (!handled) { + applicator.appendLogMsg( + memberTypeApplierIterated.getClass().getSimpleName() + " with contained " + + memberTypeApplierIterated.getMsType().getClass().getSimpleName() + + " unexpected for " + msType.getName()); + } + } + } + +// /** +// * NoType provides ability to hang NoType into a composite type by faking +// * it with a zero-length bitfield. This is a bit of a kludge +// * This will be transformed to a normal BitFieldDataType when cloned. +// */ +// private class NoType extends PdbBitField { +// private NoType(PdbApplicator applicator) throws InvalidDataTypeException { +// super(new CharDataType(applicator.getDataTypeManager()), 0, 0); +// } +// } +// +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java new file mode 100644 index 0000000000..e3d286a6db --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java @@ -0,0 +1,1915 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.*; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; + +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; +import ghidra.app.util.pdb.pdbapplicator.PdbVbtManager.PdbVirtualBaseTable; +import ghidra.program.model.data.*; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Notional C++ Class Type. + */ +public class CppCompositeType { + + // Order matters for both base classes and members for class layout. Members get offsets, + // which helps for those, but layout algorithms usually utilize order. + private List syntacticBaseClasses; + private List layoutBaseClasses; + private List myMembers; + private List layoutMembers; + private List layoutVftPtrMembers; + private boolean isFinal; + private Type type; + private String className; // String for now. + private String mangledName; + private int size; + private Composite composite; + private CategoryPath categoryPath; + + private OoComponentLayoutMode layoutMode = OoComponentLayoutMode.UNKNOWN; + + private List memberData; + + private boolean hasDirect; + + static String createDirectClassName(Composite composite) { + return composite.getName() + "_direct"; + } + + static CategoryPath createDirectCategoryPath(CppCompositeType cppType) { + return cppType.getBaseCategoryName( + CppCompositeType.createDirectClassName(cppType.getComposite())); + } + + /* + * Not certain, but think there should only be one Virtual Base Table for a given + * class (not counting those for its parents). However, since VirtualBaseClass and + * IndirectVirtualBase class records both have an "offset" for (seemingly) where the + * virtual base table point can be located, then there is a chance that different + * records for a class could have different values. This HashMap will is keyed by this + * offset, in case we see more than one. Want to log the fact if more than one value is seen + * for a particular hierarchy level. + */ + private Map placeholderVirtualBaseTables; + + //---------------------------------------------------------------------------------------------- + public CppCompositeType(Composite composite, String mangledName) { + Objects.requireNonNull(composite, "composite may not be null"); + syntacticBaseClasses = new ArrayList<>(); + layoutBaseClasses = new ArrayList<>(); + myMembers = new ArrayList<>(); + layoutMembers = new ArrayList<>(); + + memberData = new ArrayList<>(); + layoutVftPtrMembers = new ArrayList<>(); + + isFinal = false; + type = Type.UNKNOWN; + 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(Composite composite, String name, + String mangledName, int size) { + CppClassType cppType = new CppClassType(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(Composite composite, String name, + String mangledName, int size) { + CppStructType cppType = new CppStructType(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); + setClass(); + } + } + + private static class CppStructType extends CppCompositeType { + private CppStructType(Composite composite, String mangledName) { + super(composite, mangledName); + setStruct(); + } + } + + static boolean validateMangledCompositeName(String mangledCompositeTypeName, Type type) { + if (mangledCompositeTypeName == null) { + return false; + } + if (!mangledCompositeTypeName.startsWith(".?")) { + return false; + } + if (mangledCompositeTypeName.length() < 7) { + return false; + } + if (mangledCompositeTypeName.charAt(2) != 'A') { + PdbLog.message("Mangled composite type name not plain 'A'"); + } + switch (mangledCompositeTypeName.charAt(3)) { + case 'T': + if ((type.compareTo(Type.UNION) != 0) && (type.compareTo(Type.UNKNOWN) != 0)) { + PdbLog.message("Warning: Mismatched complex type 'T' for " + type); + } + break; + case 'U': + if ((type.compareTo(Type.STRUCT) != 0) && (type.compareTo(Type.UNKNOWN) != 0)) { + PdbLog.message("Warning: Mismatched complex type 'U' for " + type); + } + break; + case 'V': + if ((type.compareTo(Type.CLASS) != 0) && (type.compareTo(Type.UNKNOWN) != 0)) { + PdbLog.message("Warning: Mismatched complex type 'V' for " + type); + } + break; + default: + PdbLog.message("Not composite"); + return false; + } + return true; + + } + + public boolean validate() { + // C++ rules: + // If final, can have an empty name. I believe this means "name" can be empty, but + // can still have parent namespace. TODO: check this if we change to something more + // than String. + if (StringUtils.isEmpty(className) && !isFinal) { + return false; + } + return true; + } + + private List getLayoutBaseClasses() { + return layoutBaseClasses; + } + + Composite getComposite() { + return composite; + } + + private CategoryPath getCategoryPath() { + return categoryPath; + } + + public void setFinal(boolean isFinal) { + this.isFinal = isFinal; + } + + public boolean isFinal() { + return isFinal; + } + + public void setClass() { + type = Type.CLASS; + } + + public void setStruct() { + type = Type.STRUCT; + } + + public void setUnion() { + type = Type.UNION; + } + + // not sure if user can see Type when returned. + public Type getType() { + return type; + } + + public void setName(String className) { + this.className = className; + } + + public String getName() { + return className; + } + + public void setMangledName(String mangledName) { + this.mangledName = mangledName; + } + + public String getMangledName() { + return mangledName; + } + + public void setSize(int size) { + this.size = size; + } + + public int getSize() { + return size; + } + + public int getNumMembers() { + return myMembers.size(); + } + + public int getNumLayoutMembers() { + return layoutMembers.size(); + } + + public void addVirtualFunctionTablePointer(String name, DataType dataType, int offset) { + Member newMember = new Member(name, dataType, false, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset); + layoutVftPtrMembers.add(newMember); + } + + private void insertVirtualFunctionTablePointers(List pdbMembers) { + for (Member vftPtrMember : layoutVftPtrMembers) { + ClassPdbMember vftPtrPdbMember = new ClassPdbMember(vftPtrMember.getName(), + vftPtrMember.getDataType(), vftPtrMember.isFlexibleArray(), + vftPtrMember.getOffset(), vftPtrMember.getComment()); + int index = 0; + for (ClassPdbMember member : pdbMembers) { + if (member.getOffset() > vftPtrMember.getOffset()) { + break; + } + index++; + } + pdbMembers.add(index, vftPtrPdbMember); + } + } + + public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, int offset, + String comment) { + addMember(memberName, dataType, isFlexibleArray, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, comment); + } + + public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, + int offset) { + addMember(memberName, dataType, isFlexibleArray, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, null); + } + + public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, + ClassFieldAttributes attributes, int offset) { + Member newMember = new Member(memberName, dataType, isFlexibleArray, attributes, offset); + myMembers.add(newMember); + addMember(layoutMembers, newMember); + } + + public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, + ClassFieldAttributes attributes, int offset, String comment) { + Member newMember = + new Member(memberName, dataType, isFlexibleArray, attributes, offset, comment); + myMembers.add(newMember); + addMember(layoutMembers, newMember); + } + + private void addMember(List members, Member newMember) { + members.add(newMember); + } + + //============================================================================================== + /* + * These "insert" methods should be used judiciously. You need to know what/why you are doing + * this. Changing the order of "normal" members can mess up the layout algorithms from + * {@link DefaultCompositeMember}. The only place we currently think we can use these is + * when trying to place vbptr members. Not all of these methods are used too. + * @param isFlexibleArray TODO + */ + public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, + int offset, String comment) { + insertMember(memberName, dataType, isFlexibleArray, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, comment); + } + + public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, + int offset) { + insertMember(memberName, dataType, isFlexibleArray, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, null); + } + + public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, + ClassFieldAttributes attributes, int offset) { + Member newMember = new Member(memberName, dataType, isFlexibleArray, attributes, offset); + myMembers.add(newMember); + insertMember(layoutMembers, newMember); + } + + public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, + ClassFieldAttributes attributes, int offset, String comment) { + Member newMember = + new Member(memberName, dataType, isFlexibleArray, attributes, offset, comment); + myMembers.add(newMember); + insertMember(layoutMembers, newMember); + } + + private void insertMember(List members, Member newMember) { + int index = 0; + for (Member member : members) { + if (member.getOffset() > newMember.getOffset()) { + break; + } + index++; + } + members.add(index, newMember); + } + + public void addStaticMember(String memberName, DataType dataType) { + addStaticMember(memberName, dataType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN)); + } + + public void addStaticMember(String memberName, DataType dataType, + ClassFieldAttributes attributes) { + myMembers.add(new StaticMember(memberName, dataType, attributes)); + } + + public int getNumLayoutBaseClasses() { + return layoutBaseClasses.size(); + } + + public int getNumLayoutVirtualBaseClasses() { + int num = 0; + for (LayoutBaseClass base : layoutBaseClasses) { + if (base instanceof DirectLayoutBaseClass) { + num++; + } + } + return layoutBaseClasses.size() - num; + } + + public int getNumSyntacticBaseClasses() { + return syntacticBaseClasses.size(); + } + + public void addSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { + addSyntacticBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN)); + } + + public void addSyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes) throws PdbException { + validateBaseClass(baseClassType); + syntacticBaseClasses.add(new SyntacticBaseClass(baseClassType, attributes)); + } + + public void addDirectSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { + addDirectSyntacticBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN)); + } + + public void addDirectSyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes) throws PdbException { + validateBaseClass(baseClassType); + syntacticBaseClasses.add(new DirectSyntacticBaseClass(baseClassType, attributes)); + } + + public void addVirtualSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { + addVirtualSyntacticBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN)); + } + + public void addVirtualSyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes) throws PdbException { + validateBaseClass(baseClassType); + syntacticBaseClasses.add(new VirtualSyntacticBaseClass(baseClassType, attributes)); + } + + public void insertSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) + throws PdbException { + insertSyntacticBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal); + } + + public void insertSyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes, int ordinal) throws PdbException { + validateBaseClass(baseClassType); + if (ordinal < 0 || ordinal > getNumSyntacticBaseClasses()) { + // TODO: Change this to some new Exception type; e.g., ClassTypeException. + throw new PdbException("Invalid base class insertion index."); + } + syntacticBaseClasses.add(ordinal, new SyntacticBaseClass(baseClassType, attributes)); + } + + public void insertDirectSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) + throws PdbException { + insertDirectSyntacticBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal); + } + + public void insertDirectSyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes, int ordinal) throws PdbException { + validateBaseClass(baseClassType); + if (ordinal < 0 || ordinal > getNumSyntacticBaseClasses()) { + // TODO: Change this to some new Exception type; e.g., ClassTypeException. + throw new PdbException("Invalid base class insertion index."); + } + syntacticBaseClasses.add(ordinal, new DirectSyntacticBaseClass(baseClassType, attributes)); + } + + public void insertVirtualSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) + throws PdbException { + insertVirtualSyntacticBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal); + } + + public void insertVirtualSyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes, int ordinal) throws PdbException { + validateBaseClass(baseClassType); + if (ordinal < 0 || ordinal > getNumSyntacticBaseClasses()) { + // TODO: Change this to some new Exception type; e.g., ClassTypeException. + throw new PdbException("Invalid base class insertion index."); + } + syntacticBaseClasses.add(ordinal, new VirtualSyntacticBaseClass(baseClassType, attributes)); + } + + //============================================================================================== + public void addDirectBaseClass(CppCompositeType baseClassType, int offset) throws PdbException { + addDirectBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset); + } + + public void addDirectBaseClass(CppCompositeType baseClassType, ClassFieldAttributes attributes, + int offset) throws PdbException { + validateBaseClass(baseClassType); + layoutBaseClasses.add(new DirectLayoutBaseClass(baseClassType, attributes, offset)); + } + +// // Index is order in list, not physical offset of class elements. +// public void insertDirectBaseClass(CppCompositeType baseClassType, int index) +// throws PdbException { +// insertDirectBaseClass(baseClassType, +// new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), index); +// } +// +// // Index is order in list, not physical offset of class elements. +// public void insertDirectBaseClass(CppCompositeType baseClassType, +// ClassFieldAttributes attributes, int index) throws PdbException { +// validateBaseClass(baseClassType); +// if (index < 0 || index > getNumBaseClasses()) { +// // TODO: Change this to some new Exception type; e.g., ClassTypeException. +// throw new PdbException("Invalid base class insertion index."); +// } +// layoutBaseClasses.add(index, new DirectBaseClass(baseClassType, attributes)); +// } +// + public void addDirectVirtualBaseClass(CppCompositeType baseClassType, int basePointerOffset, + DataType vbptr, int offsetFromVbt) throws PdbException { + addDirectVirtualBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), basePointerOffset, vbptr, + offsetFromVbt); + } + + public void addDirectVirtualBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, + int offsetFromVbt) throws PdbException { + validateBaseClass(baseClassType); + layoutBaseClasses.add(new DirectVirtualLayoutBaseClass(baseClassType, attributes, + basePointerOffset, vbptr, offsetFromVbt)); + } + +// // Index is order in list, not physical offset of class elements. +// public void insertDirectVirtualBaseClass(CppCompositeType baseClassType, int index) +// throws PdbException { +// insertDirectVirtualBaseClass(baseClassType, +// new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), index); +// } +// +// // Index is order in list, not physical offset of class elements. +// public void insertDirectVirtualBaseClass(CppCompositeType baseClassType, +// ClassFieldAttributes attributes, int index) throws PdbException { +// validateBaseClass(baseClassType); +// if (index < 0 || index > getNumBaseClasses()) { +// // TODO: Change this to some new Exception type; e.g., ClassTypeException. +// throw new PdbException("Invalid base class insertion index."); +// } +// layoutBaseClasses.add(index, new DirectVirtualBaseClass(baseClassType, attributes)); +// } +// + public void addIndirectVirtualBaseClass(CppCompositeType baseClassType, int basePointerOffset, + DataType vbptr, int offsetFromVbt) throws PdbException { + addIndirectVirtualBaseClass(baseClassType, + new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), basePointerOffset, vbptr, + offsetFromVbt); + } + + public void addIndirectVirtualBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, + int offsetFromVbt) throws PdbException { + validateBaseClass(baseClassType); + layoutBaseClasses.add(new IndirectVirtualLayoutBaseClass(baseClassType, attributes, + basePointerOffset, vbptr, offsetFromVbt)); + } + +// // Index is order in list, not physical offset of class elements. +// public void insertIndirectVirtualBaseClass(CppCompositeType baseClassType, int index) +// throws PdbException { +// insertIndirectVirtualBaseClass(baseClassType, +// new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), index); +// } +// +// // Index is order in list, not physical offset of class elements. +// public void insertIndirectVirtualBaseClass(CppCompositeType baseClassType, +// ClassFieldAttributes attributes, int index) throws PdbException { +// validateBaseClass(baseClassType); +// if (index < 0 || index > getNumBaseClasses()) { +// // TODO: Change this to some new Exception type; e.g., ClassTypeException. +// throw new PdbException("Invalid base class insertion index."); +// } +// layoutBaseClasses.add(index, new IndirectVirtualBaseClass(baseClassType, attributes)); +// } +// + private static void validateBaseClass(CppCompositeType baseClassType) throws PdbException { + if (baseClassType.isFinal) { + throw new PdbException("Cannot inherit base class marked final."); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(type); + builder.append(className); + if (isFinal) { + builder.append(" final"); + } + StringBuilder baseBuilder = new StringBuilder(); + for (BaseClass base : syntacticBaseClasses) { + if (baseBuilder.length() == 0) { + baseBuilder.append(" : "); + } + else { + baseBuilder.append(", "); + } + baseBuilder.append(base); + } + builder.append(baseBuilder); + return builder.toString(); + } + + public OoComponentLayoutMode getLayoutMode(CompositeLayoutMode layoutOptions) { + if (layoutMode == OoComponentLayoutMode.UNKNOWN) { + layoutMode = determineLayoutMode(layoutOptions); + } + return layoutMode; + } + + private OoComponentLayoutMode determineLayoutMode(CompositeLayoutMode layoutOptions) { + OoComponentLayoutMode initialModeDetermination; + if (layoutOptions.getLayoutMode() == OoComponentLayoutMode.MEMBERS_ONLY) { + return OoComponentLayoutMode.MEMBERS_ONLY; + } + else if (getNumLayoutBaseClasses() == 0) { + initialModeDetermination = OoComponentLayoutMode.BASIC; + } + else if (getNumLayoutVirtualBaseClasses() == 0) { + initialModeDetermination = OoComponentLayoutMode.SIMPLE; + } + else { + initialModeDetermination = OoComponentLayoutMode.COMPLEX; + } + OoComponentLayoutMode optionsMode = layoutOptions.getLayoutMode(); + return optionsMode.compareTo(initialModeDetermination) >= 0 ? optionsMode + : initialModeDetermination; + } + + boolean isZeroSize() { + return memberData.size() == 0; + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + public void createLayoutFromSyntacticDescription(VbtManager vbtManager, TaskMonitor monitor) { + for (SyntacticBaseClass base : syntacticBaseClasses) { + if (base instanceof DirectSyntacticBaseClass) { + + } + else { // VirtualSyntacticBaseClass + + } + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + public void createLayout(CompositeLayoutMode layoutOptions, VbtManager vbtManager, + TaskMonitor monitor) throws PdbException, CancelledException { + if (vbtManager instanceof PdbVbtManager) { // Information from PDB/program symbols + // TODO: both same for now + //doSpeculativeLayout(vbtManager, monitor); + createVbtBasedLayout(layoutOptions, vbtManager, monitor); + } + else { + createSpeculativeLayout(layoutOptions, vbtManager, monitor); + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + public void createVbtBasedLayout(CompositeLayoutMode layoutOptions, VbtManager vbtManager, + TaskMonitor monitor) throws PdbException, CancelledException { + CategoryPath cn; + hasDirect = false; + switch (getLayoutMode(layoutOptions)) { + case MEMBERS_ONLY: + addLayoutPdbMembers(memberData, layoutMembers); + break; + case BASIC: + addLayoutPdbMembers(memberData, layoutMembers); + insertVirtualFunctionTablePointers(memberData); + break; + // TODO: evaluate... not really getting difference I thought we could get... so far + // BASIC and SIMPLE seem to yield the same results. I might be doing something wrong. + case SIMPLE: + case COMPLEX: + cn = createDirectCategoryPath(this); + Composite directDataType = new StructureDataType(cn.getParent(), cn.getName(), 0, + composite.getDataTypeManager()); + + List directClassPdbMembers = getDirectBaseClassMembers(monitor); + List myVirtualLayoutBases = preprocessVirtualBases(monitor); + + // TODO: consider moving down below next line. + boolean allVbtFound = + reconcileVirtualBaseTables(composite.getDataTypeManager(), vbtManager); + + addLayoutPdbMembers(directClassPdbMembers, layoutMembers); + insertVirtualFunctionTablePointers(directClassPdbMembers); + + if (!DefaultCompositeMember.applyDataTypeMembers(directDataType, false, 0, + directClassPdbMembers, msg -> Msg.warn(this, msg), monitor)) { + clearComponents(directDataType); + } + int directClassLength = getCompositeLength(directDataType); + + if (directClassLength == 0) { + // Not using the direct type (only used it to get the directClassLength), so + // remove it and add the members to the main type instead. + directDataType.getDataTypeManager().remove(directDataType, monitor); + } + else { + // this does not deal with the case where more members from memberData get + // added below and must still fit in "size." + if (directClassLength > size) { + // Redo it with the size of the overall structure/class + directDataType.getDataTypeManager().remove(directDataType, monitor); + directDataType = new StructureDataType(cn.getParent(), cn.getName(), 0, + composite.getDataTypeManager()); + if (!DefaultCompositeMember.applyDataTypeMembers(directDataType, false, + size, directClassPdbMembers, msg -> Msg.warn(this, msg), monitor)) { + clearComponents(directDataType); + } + directClassLength = getCompositeLength(directDataType); + } + if (getLayoutMode(layoutOptions) == OoComponentLayoutMode.SIMPLE) { + // Not using the dummy/direct type (only used it to get the + // directClassLength), so remove it and add the members to the main + // type instead. + directDataType.getDataTypeManager().remove(directDataType, monitor); + memberData.addAll(directClassPdbMembers); + //addLayoutPdbMembers(memberData, layoutMembers, monitor); + } + else { + ClassPdbMember directClassPdbMember = + new ClassPdbMember("", directDataType, false, 0, null); + memberData.add(directClassPdbMember); + hasDirect = true; + } + } + + addVirtualBases(directClassLength, memberData, myVirtualLayoutBases, allVbtFound, + monitor); + + break; + default: + throw new PdbException("Unhandled layout mode"); + } + + if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, size, memberData, + msg -> Msg.warn(this, msg), monitor)) { + clearComponents(composite); + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + private List getDirectBaseClassMembers(TaskMonitor monitor) + throws CancelledException { + List myDirectClassPdbMembers = new ArrayList<>(); + for (LayoutBaseClass base : getLayoutBaseClasses()) { + monitor.checkCanceled(); + CppCompositeType baseComposite = base.getBaseClassType(); + if (base instanceof DirectLayoutBaseClass) { + if (!baseComposite.isZeroSize()) { + Composite baseDataType = base.getDirectDataType(); + int offset = ((DirectLayoutBaseClass) base).getOffset(); + CategoryPath cn = + getBaseCategoryName("BaseClass_" + base.getBaseClassType().getName()); + Member baseMember = + new Member("", baseDataType, false, null, offset, cn.toString()); + addPdbMember(myDirectClassPdbMembers, baseMember); + } + } + } + return myDirectClassPdbMembers; + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + private List preprocessVirtualBases(TaskMonitor monitor) + throws CancelledException, PdbException { + List myVirtualLayoutBases = new ArrayList<>(); + for (LayoutBaseClass base : getLayoutBaseClasses()) { + monitor.checkCanceled(); + if (base instanceof VirtualLayoutBaseClass) { + addPlaceholderVirtualBaseTableEntry(((VirtualLayoutBaseClass) base)); + myVirtualLayoutBases.add((VirtualLayoutBaseClass) base); + } + } + return myVirtualLayoutBases; + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + public void createSpeculativeLayout(CompositeLayoutMode layoutOptions, VbtManager vbtManager, + TaskMonitor monitor) throws PdbException, CancelledException { + // Speculative Layout uses recursion to try to know the order of members. However, MSFT + // rearranges the order of the Base Class records such that they are not necessarily in + // the order that the class was declared, and it seems that the member order follows the + // order of the class hierarchy declaration. + // We use recursion and also also reordering so Base Classes always follow their children, + // so with multiple virtual inheritance, a parent from multiple family lines will likely + // get moved. + CategoryPath cn; + hasDirect = false; + switch (getLayoutMode(layoutOptions)) { + case MEMBERS_ONLY: + addLayoutPdbMembers(memberData, layoutMembers); + break; + case BASIC: + cn = composite.getCategoryPath(); + addLayoutPdbMembers(memberData, layoutMembers); + insertVirtualFunctionTablePointers(memberData); + break; + // TODO: evaluate... not really getting difference I thought we could get... so far + // BASIC and SIMPLE seem to yield the same results. I might be doing something wrong. + case SIMPLE: + case COMPLEX: + cn = createDirectCategoryPath(this); + Composite directDataType = new StructureDataType(cn.getParent(), cn.getName(), 0, + composite.getDataTypeManager()); + + List myAccumulatedDirectBases = new ArrayList<>(); + List myAccumulatedVirtualBases = new ArrayList<>(); + List directClassPdbMembers = new ArrayList<>(); + processBaseClassesRecursive(this, true, directClassPdbMembers, + myAccumulatedDirectBases, myAccumulatedVirtualBases, 0, monitor); + + // TODO: consider moving down below next line. + boolean allVbtFound = + reconcileVirtualBaseTables(composite.getDataTypeManager(), vbtManager); + + addLayoutPdbMembers(directClassPdbMembers, layoutMembers); + insertVirtualFunctionTablePointers(directClassPdbMembers); + + if (!DefaultCompositeMember.applyDataTypeMembers(directDataType, false, 0, + directClassPdbMembers, msg -> Msg.warn(this, msg), monitor)) { + clearComponents(directDataType); + } + int directClassLength = getCompositeLength(directDataType); + + if (directClassLength == 0) { + // Not using the direct type (only used it to get the directClassLength), so + // remove it and add the members to the main type instead. + directDataType.getDataTypeManager().remove(directDataType, monitor); + } + else { + // this does not deal with the case where more members from memberData get + // added below and must still fit in "size." + if (directClassLength > size) { + // Redo it with the size of the overall structure/class + directDataType.getDataTypeManager().remove(directDataType, monitor); + directDataType = new StructureDataType(cn.getParent(), cn.getName(), 0, + composite.getDataTypeManager()); + if (!DefaultCompositeMember.applyDataTypeMembers(directDataType, false, + size, directClassPdbMembers, msg -> Msg.warn(this, msg), monitor)) { + clearComponents(directDataType); + } + directClassLength = getCompositeLength(directDataType); + } + if (getLayoutMode(layoutOptions) == OoComponentLayoutMode.SIMPLE) { + // Not using the dummy/direct type (only used it to get the + // directClassLength), so remove it and add the members to the main + // type instead. + directDataType.getDataTypeManager().remove(directDataType, monitor); + memberData.addAll(directClassPdbMembers); + //addLayoutPdbMembers(memberData, layoutMembers, monitor); + } + else { + ClassPdbMember directClassPdbMember = + new ClassPdbMember("", directDataType, false, 0, null); + memberData.add(directClassPdbMember); + hasDirect = true; + } + } + + addVirtualBasesSpeculatively(directClassLength, memberData, + myAccumulatedVirtualBases, monitor); + + break; + default: + throw new PdbException("Unhandled layout mode"); + } + + if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, size, memberData, + msg -> Msg.warn(this, msg), monitor)) { + clearComponents(composite); + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + private void processBaseClassesRecursive(CppCompositeType cppType, boolean isDirect, + List myPdbMembers, List myAccumulatedDirectBases, + List myAccumulatedVirtualBases, int depth, TaskMonitor monitor) + throws PdbException, CancelledException { + depth++; + for (LayoutBaseClass base : cppType.getLayoutBaseClasses()) { + monitor.checkCanceled(); + CppCompositeType baseComposite = base.getBaseClassType(); + if (base instanceof DirectLayoutBaseClass) { + if (isDirect) { + if (alreadyAccumulatedByName(myAccumulatedDirectBases, base)) { + throw new PdbException( + "Direct base already seen: " + base.getBaseClassType().getName()); + } + if (!baseComposite.isZeroSize()) { + Composite baseDataType = base.getDirectDataType(); + int offset = ((DirectLayoutBaseClass) base).getOffset(); + CategoryPath cn = + getBaseCategoryName("BaseClass_" + base.getBaseClassType().getName()); + Member baseMember = + new Member("", baseDataType, false, null, offset, cn.toString()); + addPdbMember(myPdbMembers, baseMember); + } + myAccumulatedDirectBases.add(base); + } + processBaseClassesRecursive(baseComposite, false, myPdbMembers, + myAccumulatedDirectBases, myAccumulatedVirtualBases, depth, monitor); + } + else if (base instanceof VirtualLayoutBaseClass) { + if (depth == 1) { + addPlaceholderVirtualBaseTableEntry(((VirtualLayoutBaseClass) base)); + } + if (alreadyAccumulatedByName(myAccumulatedVirtualBases, base)) { + continue; + } + if (!baseComposite.isZeroSize()) { + processBaseClassesRecursive(baseComposite, false, myPdbMembers, + myAccumulatedDirectBases, myAccumulatedVirtualBases, depth, monitor); + } + myAccumulatedVirtualBases.add((VirtualLayoutBaseClass) base); + } + else { + throw new PdbException("Unknown base class type"); + } + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + void addPlaceholderVirtualBaseTableEntry(VirtualLayoutBaseClass base) throws PdbException { + PlaceholderVirtualBaseTable table = + placeholderVirtualBaseTables.get(base.getBasePointerOffset()); + if (table == null) { + table = new PlaceholderVirtualBaseTable(); + placeholderVirtualBaseTables.put(base.getBasePointerOffset(), table); + } + PlaceholderVirtualBaseTableEntry entry = + table.getEntryByIndexInTable(base.getOffetFromVbt()); + if (entry != null) { + throw new PdbException( + "Entry already exists at offset (" + base.getOffetFromVbt() + "): " + entry); + } + entry = new PlaceholderVirtualBaseTableEntry(base); + table.addEntry(base.getOffetFromVbt(), entry); + } + + PlaceholderVirtualBaseTable getPlaceholderVirtualBaseTable(int basePointerOffset) { + return placeholderVirtualBaseTables.get(basePointerOffset); + } + + Map getPlaceholderVirtualBaseTables() { + return placeholderVirtualBaseTables; + } + + private boolean reconcileVirtualBaseTables(DataTypeManager dtm, VbtManager vbtManager) + throws PdbException { + if (placeholderVirtualBaseTables.size() > 1) { + // study this. + int a = 1; + a = a + 1; + } + + boolean allVbtFound = true; + for (Entry tableEntry : placeholderVirtualBaseTables.entrySet()) { + int vbtptrOffset = tableEntry.getKey(); + PlaceholderVirtualBaseTable table = tableEntry.getValue(); + if (!table.validateOffset()) { + // TODO study this. + int a = 1; + a = a + 1; + } + DataType vbptr = getVbptrDataType(dtm, vbtManager, table); + allVbtFound &= + addOrUpdateVbtAndVbtptrMember(vbtManager, table, vbptr, vbtptrOffset, getName()); + } + return allVbtFound; + } + + private DataType getVbptrDataType(DataTypeManager dtm, VbtManager vbtManager, + PlaceholderVirtualBaseTable table) { + DataType vbptr = null; + for (int index = 1; index < table.getMaxOffset(); index++) { + PlaceholderVirtualBaseTableEntry entry = table.getEntryByIndexInTable(index); + vbptr = entry.getVirtualBaseClass().getVbptr(); + if (vbptr != null) { // take first type... assuming all are the same + break; + } + } + if (vbptr == null) { + vbptr = vbtManager.getFallbackVbptr(); + } + return vbptr; + } + + private class CppCompositeAndMember { + private CppCompositeType cppType; + private Member member; + + private CppCompositeAndMember(CppCompositeType cppType, Member member) { + this.cppType = cppType; + this.member = member; + } + + private CppCompositeType getComposite() { + return cppType; + } + + private Member getMember() { + return member; + } + } + + private boolean addOrUpdateVbtAndVbtptrMember(VbtManager vbtManager, + PlaceholderVirtualBaseTable table, DataType vbptr, int vbtptrOffset, String myClass) + throws PdbException { + + List subMangled = new ArrayList<>(); + //subMangled.add(getMangledName()); + CppCompositeAndMember cAndM = findDirectBaseCompositeAndMember(this, 0, vbtptrOffset); + if (cAndM == null) { + insertMember("{vbptr}", vbptr, false, vbtptrOffset, "{vbptr} for " + myClass); + } + else if (!"{vbptr}".equals(cAndM.getMember().getName())) { + String message = "PDB: Collision of non-{vbptr}."; + PdbLog.message(message); + Msg.info(this, message); + return false; + } + else { + CppCompositeType compositeThatContainsMember = cAndM.getComposite(); + String mangled = compositeThatContainsMember.getMangledName(); + subMangled.add(mangled); + } + if (!(vbtManager instanceof PdbVbtManager)) { + return false; + } + int entrySize = 4; // Default to something (could be wrong) + if (vbptr instanceof PointerDataType) { + entrySize = ((PointerDataType) vbptr).getDataType().getLength(); + } + + return findVbtBySymbolConstruction(table, (PdbVbtManager) vbtManager, entrySize, + getMangledName(), type, subMangled); + } + + private boolean findVbtBySymbolConstruction(PlaceholderVirtualBaseTable table, + PdbVbtManager vbtm, int entrySize, String mangledCompositeTypeName, Type mainType, + List subMangledCompositeTypeNames) { + if (!validateMangledCompositeName(mangledCompositeTypeName, mainType)) { + return false; + } + for (String mangled : subMangledCompositeTypeNames) { + if (!validateMangledCompositeName(mangled, Type.UNKNOWN)) { + return false; + } + } + StringBuilder builder = new StringBuilder(); + builder.append("??_8"); + builder.append(mangledCompositeTypeName.substring(4)); + builder.append("7B"); // Hope will always be 'B' ("const") + builder.append("@"); + String possibleName = builder.toString(); + if (findAndUpdate(table, vbtm, entrySize, possibleName)) { + return true; + } + for (String mangled : subMangledCompositeTypeNames) { + builder.deleteCharAt(builder.length() - 1); + builder.append(mangled.substring(4)); + builder.append("@"); + possibleName = builder.toString(); + if (findAndUpdate(table, vbtm, entrySize, possibleName)) { + return true; + } + } + return false; + } + + boolean findAndUpdate(PlaceholderVirtualBaseTable table, PdbVbtManager vbtm, int entrySize, + String mangledTableName) { + PdbVirtualBaseTable vbt = vbtm.createVirtualBaseTableByName(mangledTableName, entrySize); + if (vbt == null) { + return false; + } + table.setName(mangledTableName); + table.setVirtualBaseTable(vbt); + return true; + } + + private CppCompositeAndMember findDirectBaseCompositeAndMember(CppCompositeType cppType, + int offsetCppType, int vbtptrOffset) throws PdbException { + for (LayoutBaseClass base : cppType.layoutBaseClasses) { + if (!(base instanceof DirectLayoutBaseClass)) { + continue; + } + DirectLayoutBaseClass directBase = (DirectLayoutBaseClass) base; + int directBaseOffset = directBase.getOffset() + offsetCppType; + int directBaseLength = directBase.getDirectDataType().getLength(); + if (vbtptrOffset >= directBaseOffset && + vbtptrOffset < directBaseOffset + directBaseLength) { + CppCompositeType childCppType = directBase.getBaseClassType(); + CppCompositeAndMember cAndM = + findDirectBaseCompositeAndMember(childCppType, directBaseOffset, vbtptrOffset); + if (cAndM == null) { + Member member = childCppType.findLayoutMemberOrVftPtrMember(vbtptrOffset); + if (member == null) { + return null; + } + cAndM = new CppCompositeAndMember(childCppType, member); + } + return cAndM; + } + } + return null; + } + + private Member findLayoutMemberOrVftPtrMember(int offset) { + for (Member member : layoutMembers) { + if (member.getOffset() == offset) { + return member; + } + } + for (Member member : layoutVftPtrMembers) { + if (member.getOffset() == offset) { + return member; + } + } + return null; + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- +// private void addVirtualBases(int startOffset, List pdbMembers, +// List virtualBases, boolean allVbtFound, TaskMonitor monitor) +// throws PdbException, CancelledException { +// String accumulatedComment = ""; +// int memberOffset = startOffset; +// for (VirtualLayoutBaseClass virtualBase : virtualBases) { +// monitor.checkCanceled(); +// Composite baseDataType = virtualBase.getDirectDataType(); +// int virtualBaseLength = getCompositeLength(baseDataType); +// PlaceholderVirtualBaseTable pvbt = +// getPlaceholderVirtualBaseTable(virtualBase.getBasePointerOffset()); +// if (pvbt != null && pvbt.canLookupOffset()) { +// long offset = pvbt.getOffset(virtualBase.getOffetFromVbt()); +// memberOffset = (int) (offset & 0xffffffffL); +// } +// if (virtualBaseLength != 0) { +// String comment = +// "(Virtual Base " + virtualBase.getDataTypePath().getDataTypeName() + ")"; +// accumulatedComment += comment; +// ClassPdbMember virtualClassPdbMember = +// new ClassPdbMember("", baseDataType, false, memberOffset, accumulatedComment); +// pdbMembers.add(virtualClassPdbMember); +// memberOffset += virtualBaseLength; +// accumulatedComment = ""; +// } +// else { +// String comment = "((empty) Virtual Base " + +// virtualBase.getDataTypePath().getDataTypeName() + ")"; +// accumulatedComment += comment; +// } +// // If last base is empty, then its comment and any accumulated to this point +// // will not be seen (not applied to a PdbMember). TODO: Consider options, +// // though we know we have left it in this state and are OK with it for now. +// // We have not considered fall-out from this. +// } +// } + + private void addVirtualBases(int startOffset, List pdbMembers, + List virtualBases, boolean allVbtFound, TaskMonitor monitor) + throws PdbException, CancelledException { + String accumulatedComment = ""; + int memberOffset = startOffset; + List orderedBases = new ArrayList<>(); + List offsets = new ArrayList<>(); + if (!orderVirtualBases(orderedBases, offsets, virtualBases, monitor)) { + addVirtualBasesSpeculatively(startOffset, pdbMembers, virtualBases, monitor); + return; + } + + for (int index = 0; index < offsets.size(); index++) { + monitor.checkCanceled(); + VirtualLayoutBaseClass virtualBase = orderedBases.get(index); + memberOffset = offsets.get(index); + Composite baseDataType = virtualBase.getDirectDataType(); + int virtualBaseLength = getCompositeLength(baseDataType); + int basePointerOffset = virtualBase.getBasePointerOffset(); +// PlaceholderVirtualBaseTable pvbt = +// getPlaceholderVirtualBaseTable(virtualBase.getBasePointerOffset()); +// if (pvbt != null && pvbt.canLookupOffset()) { +// long offset = pvbt.getOffset(virtualBase.getOffetFromVbt()); +// memberOffset = (int) (offset & 0xffffffffL); +// } + memberOffset += basePointerOffset; + if (virtualBaseLength != 0) { + String comment = + "(Virtual Base " + virtualBase.getDataTypePath().getDataTypeName() + ")"; + accumulatedComment += comment; + ClassPdbMember virtualClassPdbMember = + new ClassPdbMember("", baseDataType, false, memberOffset, accumulatedComment); + pdbMembers.add(virtualClassPdbMember); + memberOffset += virtualBaseLength; + accumulatedComment = ""; + } + else { + String comment = "(Virtual Base (empty) " + + virtualBase.getDataTypePath().getDataTypeName() + ")"; + accumulatedComment += comment; + } + // If last base is empty, then its comment and any accumulated to this point + // will not be seen (not applied to a PdbMember). TODO: Consider options, + // though we know we have left it in this state and are OK with it for now. + // We have not considered fall-out from this. + } + } + + private boolean orderVirtualBases(List ordered, List offsets, + List unordered, TaskMonitor monitor) + throws PdbException, CancelledException { + for (VirtualLayoutBaseClass insertBase : unordered) { + monitor.checkCanceled(); + PlaceholderVirtualBaseTable pvbt = + getPlaceholderVirtualBaseTable(insertBase.getBasePointerOffset()); + if (pvbt == null || !pvbt.canLookupOffset()) { + return false; + } + long offset = pvbt.getOffset(insertBase.getOffetFromVbt()); + int memberOffset = (int) (offset & 0xffffffffL); + int index; + for (index = 0; index < offsets.size(); index++) { + int existingOffset = offsets.get(index); + if (existingOffset > memberOffset) { + break; + } + } + ordered.add(index, insertBase); + offsets.add(index, memberOffset); + } + return true; + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + private void addVirtualBasesSpeculatively(int startOffset, List pdbMembers, + List virtualBases, TaskMonitor monitor) + throws CancelledException { + String accumulatedComment = ""; + int memberOffset = startOffset; + for (VirtualLayoutBaseClass virtualBase : virtualBases) { + monitor.checkCanceled(); + Composite baseDataType = virtualBase.getDirectDataType(); + int virtualBaseLength = getCompositeLength(baseDataType); + + if (virtualBaseLength != 0) { + String comment = "((Speculative Placement) Virtual Base " + + virtualBase.getDataTypePath().getDataTypeName() + ")"; + accumulatedComment += comment; + ClassPdbMember virtualClassPdbMember = + new ClassPdbMember("", baseDataType, false, memberOffset, accumulatedComment); + pdbMembers.add(virtualClassPdbMember); + memberOffset += virtualBaseLength; + accumulatedComment = ""; + } + else { + String comment = "((empty) (Speculative Placement) Virtual Base " + + virtualBase.getDataTypePath().getDataTypeName() + ")"; + accumulatedComment += comment; + } + // If last base is empty, then its comment and any accumulated to this point + // will not be seen (not applied to a PdbMember). TODO: Consider options, + // though we know we have left it in this state and are OK with it for now. + // We have not considered fall-out from this. + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + private void addLayoutPdbMembers(List pdbMembers, List members) { + for (Member member : members) { + addPdbMember(pdbMembers, member); + } + } + + void addPdbMember(List pdbMembers, Member member) { + ClassPdbMember classPdbMember = new ClassPdbMember(member.getName(), member.getDataType(), + member.isFlexibleArray(), member.getOffset(), null); + pdbMembers.add(classPdbMember); + } + + void insertPdbMember(List pdbMembers, Member member) { + ClassPdbMember classPdbMember = new ClassPdbMember(member.getName(), member.getDataType(), + member.isFlexibleArray(), member.getOffset(), null); + int index = 0; + for (ClassPdbMember existingMember : pdbMembers) { + if (existingMember.getOffset() > member.getOffset()) { + break; + } + index++; + } + pdbMembers.add(index, classPdbMember); + } + + private int getCompositeLength(Composite myComposite) { + if (!myComposite.isNotYetDefined()) { + return myComposite.getLength(); + } + return 0; + } + + private static boolean alreadyAccumulatedByName(List list, + LayoutBaseClass item) { + DataTypePath dtp = item.getDataTypePath(); + for (LayoutBaseClass iterated : list) { + if (dtp.equals(iterated.getDataTypePath())) { + return true; + } + } + return false; + } + + CategoryPath getBaseCategoryName(String baseName) { + CategoryPath cn = getCategoryPath(); + return new CategoryPath(cn, baseName); + } + + // TODO: + // Taken from PdbUtil without change. Would have had to change access on class PdbUtil and + // this ensureSize method to public to make it accessible. Can revert to using PdbUtil + // once we move this new module from Contrib to Features/PDB. + final static void clearComponents(Composite composite) { + if (composite instanceof Structure) { + ((Structure) composite).deleteAll(); + } + else { + while (composite.getNumComponents() > 0) { + composite.delete(0); + } + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + private abstract class BaseClass { + // In the future, if CppClassType is a formal DataType, then we want to be able to get + // an already-formed unique class from the DTM. There is no reason to have a base + // class duplicated as individually created components of DirectBaseClasses. + private CppCompositeType baseClassType; + private ClassFieldAttributes attributes; + + private BaseClass(CppCompositeType baseClassType, ClassFieldAttributes attributes) { + this.baseClassType = baseClassType; + this.attributes = attributes; + } + + CppCompositeType getBaseClassType() { + return baseClassType; + } + + ClassFieldAttributes getAttributes() { + return attributes; + } + + OoComponentLayoutMode getLayoutMode(CompositeLayoutMode layoutOptions) { + return baseClassType.getLayoutMode(layoutOptions); + } + + DataTypePath getDataTypePath() { + return new DataTypePath(baseClassType.getCategoryPath().getParent(), + baseClassType.getCategoryPath().getName()); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(attributes); + builder.append(baseClassType.getName()); + return builder.toString(); + } + + Composite getDirectDataType() { + Composite c = getBaseClassType().getComposite(); + if (c.getNumComponents() == 0) { + return c; + } + if (!baseClassType.hasDirect) { + return c; + } + DataTypeComponent dtc = c.getComponent(0); // by construction this should be "Direct" + DataType dt = dtc.getDataType(); + Structure bdt; + if (!(dt instanceof Structure)) { + throw new AssertException("Not Structure for Direct"); + } + bdt = (Structure) dt; + return bdt; + } + + } + + //---------------------------------------------------------------------------------------------- + // Syntactic description of base classes. + //---------------------------------------------------------------------------------------------- + private class SyntacticBaseClass extends BaseClass { + private SyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes) { + super(baseClassType, attributes); + } + } + + private class DirectSyntacticBaseClass extends SyntacticBaseClass { + private DirectSyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes) { + super(baseClassType, attributes); + } + } + + private class VirtualSyntacticBaseClass extends SyntacticBaseClass { + private VirtualSyntacticBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes) { + super(baseClassType, attributes); + } + } + + //---------------------------------------------------------------------------------------------- + // Layout description of base classes follow + //---------------------------------------------------------------------------------------------- + private abstract class LayoutBaseClass extends BaseClass { + Structure layout = null; + + LayoutBaseClass(CppCompositeType baseClassType, ClassFieldAttributes attributes) { + super(baseClassType, attributes); + } + + void setLayout(Structure layout) { + this.layout = layout; + } + + Structure getLayout() { + if (layout == null) { + int a = 1; + a = a + 1; + } + return layout; + } + } + + private class DirectLayoutBaseClass extends LayoutBaseClass { + private int offset; + + private DirectLayoutBaseClass(CppCompositeType baseClassType, + ClassFieldAttributes attributes, int offset) { + super(baseClassType, attributes); + this.offset = offset; + } + + int getOffset() { + return offset; + } + } + + private abstract class VirtualLayoutBaseClass extends LayoutBaseClass { + private int basePointerOffset; + private DataType vbptr; + private int offsetFromVbt; + + private VirtualLayoutBaseClass(CppCompositeType baseClass, ClassFieldAttributes attributes, + int basePointerOffset, DataType vbptr, int offsetFromVbt) { + super(baseClass, attributes); + this.basePointerOffset = basePointerOffset; + this.vbptr = vbptr; + this.offsetFromVbt = offsetFromVbt; + } + + DataType getVbptr() { + return vbptr; + } + + int getOffetFromVbt() { + return offsetFromVbt; + } + + int getBasePointerOffset() { + return basePointerOffset; + } + } + + private class DirectVirtualLayoutBaseClass extends VirtualLayoutBaseClass { + private DirectVirtualLayoutBaseClass(CppCompositeType baseClass, + ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, + int offsetFromVbt) { + super(baseClass, attributes, basePointerOffset, vbptr, offsetFromVbt); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(super.toString()); + if (builder.length() > 0) { + builder.append(">"); + builder.insert(0, "<"); + } + return builder.toString(); + } + } + + private class IndirectVirtualLayoutBaseClass extends VirtualLayoutBaseClass { + private IndirectVirtualLayoutBaseClass(CppCompositeType baseClass, + ClassFieldAttributes attributes, int basePointerOffset, DataType vbptr, + int offsetFromVbt) { + super(baseClass, attributes, basePointerOffset, vbptr, offsetFromVbt); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(super.toString()); + if (builder.length() > 0) { + builder.append(">"); + builder.insert(0, " 0 && memberName.length() > 0) { + builder.append(' '); + } + builder.append(memberName); + return builder.toString(); + } + + String getName() { + return memberName; + } + + DataType getDataType() { + return dataType; + } + + boolean isFlexibleArray() { + return isFlexibleArray; + } + + ClassFieldAttributes getAttributes() { + return attributes; + } + + void setComment(String comment) { + this.comment = comment; + } + + String getComment() { + return comment; + } + } + + private class StaticMember extends AbstractMember { + private StaticMember(String name, DataType dataType, ClassFieldAttributes attributes) { + super(name, dataType, false, attributes); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(super.toString()); + if (builder.length() > 0) { + builder.insert(0, "static "); + } + return builder.toString(); + } + } + + private class Member extends AbstractMember { + private int offset; + + private Member(String name, DataType dataType, boolean isFlexibleArray, + ClassFieldAttributes attributes, int offset) { + this(name, dataType, isFlexibleArray, attributes, offset, null); + } + + private Member(String name, DataType dataType, boolean isFlexibleArray, + ClassFieldAttributes attributes, int offset, String comment) { + super(name, dataType, isFlexibleArray, attributes, comment); + this.offset = offset; + } + + int getOffset() { + return offset; + } + + } + + //---------------------------------------------------------------------------------------------- + + // Specific to PDB in name (Extends PdbMember... maybe should have more generic name) + private static class ClassPdbMember extends PdbMember { + + private DataType dataType; + private boolean isFlexibleArray; + + /** + * Class PDB member construction + * @param name member field name. + * @param dataType for the field. + * @param isFlexibleArray TODO + * @param offset member's byte offset within the root composite. + * @param comment comment for structure editor comment field; can be null. + */ + ClassPdbMember(String name, DataType dataType, boolean isFlexibleArray, int offset, + String comment) { + super(name, dataType.getName(), offset, comment); + this.dataType = dataType; + this.isFlexibleArray = isFlexibleArray; + } + + @Override + public String getDataTypeName() { + return dataType.getName(); + } + + @Override + protected WrappedDataType getDataType() throws CancelledException { + return new WrappedDataType(dataType, isFlexibleArray, false); + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + static class PlaceholderVirtualBaseTableEntry { + VirtualLayoutBaseClass virtualBaseClass; + int offsetInClass; + + PlaceholderVirtualBaseTableEntry(VirtualLayoutBaseClass virtualBaseClass) { + this.virtualBaseClass = virtualBaseClass; + } + + void setOffsetInClass(int offsetInClass) { + this.offsetInClass = offsetInClass; + } + + int getOffsetInClass() { + return offsetInClass; + } + + String getName() { + return virtualBaseClass.getBaseClassType().getName(); + } + + VirtualLayoutBaseClass getVirtualBaseClass() { + return virtualBaseClass; + } + } + + //---------------------------------------------------------------------------------------------- + static class PlaceholderVirtualBaseTable { + private String name; + private PdbVirtualBaseTable pdbVirtualBaseTable = null; + + // We do not know if every index will be given. We can check after the fact, and once + // the set of sequential integers is assured, we could create a list. + private Map entriesByIndex; + + PlaceholderVirtualBaseTable() { + this(""); + } + + PlaceholderVirtualBaseTable(String name) { + this.name = name; + entriesByIndex = new HashMap<>(); + } + + String getName() { + return name; + } + + void setName(String name) { + this.name = name; + } + + void setVirtualBaseTable(PdbVirtualBaseTable pdbVirtualBaseTable) { + this.pdbVirtualBaseTable = pdbVirtualBaseTable; + } + + boolean canLookupOffset() { + return pdbVirtualBaseTable != null; + } + + long getOffset(int ordinal) throws PdbException { + if (pdbVirtualBaseTable == null) { + throw new PdbException("pdbVirtualBaseTable not initialized"); + } + return pdbVirtualBaseTable.getOffset(ordinal); + } + + Map getEntries() { + return entriesByIndex; + } + + int getMaxOffset() { + return entriesByIndex.size() + 1; + } + + // TODO: maybe this should be called validateTableIndicies() + boolean validateOffset() { + int num = entriesByIndex.size() + 1; // assuming 0, plus 1-N) + for (int index : entriesByIndex.keySet()) { + if (index > num || index < 0) { + return false; + } + } + return true; + } + + void addEntry(int indexInTable, PlaceholderVirtualBaseTableEntry entry) { + entriesByIndex.put(indexInTable, entry); + } + + PlaceholderVirtualBaseTableEntry getEntryByIndexInTable(int indexInTable) { + return entriesByIndex.get(indexInTable); + } + + PlaceholderVirtualBaseTableEntry getEntryByName(String nameParam) { + for (Entry entry : entriesByIndex.entrySet()) { + if (nameParam.equals( + entry.getValue().getVirtualBaseClass().getBaseClassType().getName())) { + return entry.getValue(); + } + } + return null; + } + } + + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------- + static class ClassFieldAttributes { + Access access; + Property property; + + ClassFieldAttributes(Access access, Property property) { + this.access = access; + this.property = property; + } + + private Access getAccess() { + return access; + } + + private Property getProperty() { + return property; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (access.getValue() > Access.BLANK.getValue()) { + builder.append(access); + } + if (property.equals(Property.VIRTUAL)) { + builder.append(property); + } + return builder.toString(); + } + } + + //---------------------------------------------------------------------------------------------- + static enum Type { + UNKNOWN("UNKNOWN_TYPE", -1), + BLANK("", 1), + CLASS("class", 2), + STRUCT("struct", 3), + UNION("union", 4); + + private static final Map BY_VALUE = new HashMap<>(); + static { + for (Type val : values()) { + BY_VALUE.put(val.value, val); + } + } + private final String label; + private final int value; + + public String getString() { + return label; + } + + @Override + public String toString() { + if (label.length() != 0) { + return label + " "; + } + return label; + } + + public int getValue() { + return value; + } + + public static Type fromValue(int val) { + return BY_VALUE.getOrDefault(val, UNKNOWN); + } + + private Type(String label, int value) { + this.label = label; + this.value = value; + } + } + + //---------------------------------------------------------------------------------------------- + static enum Access { + UNKNOWN("UNKNOWN_ACCESS ", -1), + BLANK("", 0), + PUBLIC("public", 1), + PROTECTED("protected", 2), + PRIVATE("private", 3); + + private static final Map BY_VALUE = new HashMap<>(); + static { + for (Access val : values()) { + BY_VALUE.put(val.value, val); + } + } + private final String label; + private final int value; + + public String getString() { + return label; + } + + @Override + public String toString() { + if (label.length() != 0) { + return label + " "; + } + return label; + } + + public int getValue() { + return value; + } + + public static Access fromValue(int val) { + return BY_VALUE.getOrDefault(val, UNKNOWN); + } + + private Access(String label, int value) { + this.label = label; + this.value = value; + } + } + + //---------------------------------------------------------------------------------------------- + static enum Property { + UNKNOWN("INVALID_PROPERTY", -1), + BLANK("", 0), + VIRTUAL("virtual ", 1), + STATIC("static ", 2), + FRIEND("friend ", 3); + // Also consider , , . See MSFT. + + private static final Map BY_VALUE = new HashMap<>(); + static { + for (Property val : values()) { + BY_VALUE.put(val.value, val); + } + } + private final String label; + private final int value; + + public String getString() { + return label; + } + + @Override + public String toString() { + if (label.length() != 0) { + return label + " "; + } + return label; + } + + public int getValue() { + return value; + } + + public static Property fromValue(int val) { + return BY_VALUE.getOrDefault(val, UNKNOWN); + } + + private Property(String label, int value) { + this.label = label; + this.value = value; + } + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java new file mode 100644 index 0000000000..11523eb3ee --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -0,0 +1,270 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +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.symbol.AbstractDataMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.DumbMemBufferImpl; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractDataMsSymbol} symbols. + */ +public class DataSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractDataMsSymbol symbol; + + public DataSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractDataMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractDataMsSymbol) abstractSymbol; + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) + throws PdbException, CancelledException { + if (applyToApplier instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; + if (symbol.getSegment() == 0 && symbol.getOffset() == 0L) { + return; // silently return. + } + AbstractMsTypeApplier applier = getTypeApplier(); + DataType dataType = applier.getDataType(); + if (dataType == null) { // TODO: check that we can have null here. + return; // silently return. + } + String name = symbol.getName(); + Address address = applicator.reladdr(symbol); + + functionSymbolApplier.setLocalVariable(address, name, dataType); + } + } + + @Override + public void apply() throws CancelledException, PdbException { + // skip if both zero (i.e,. process if either is not zero) + if (symbol.getSegment() != 0 || symbol.getOffset() != 0L) { + Address symbolAddress = applicator.reladdr(symbol); + Address remapAddress = applicator.getRemapAddressByAddress(symbolAddress); + RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); + boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, true); + String name = symbol.getName(); + if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { + applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); + } + createData(symbolAddress, typeRecordNumber); + } + } + + AbstractMsTypeApplier getTypeApplier() { + return applicator.getTypeApplier(symbol.getTypeRecordNumber()); + } + + void createData(Address address, RecordNumber typeRecordNumber) { + AbstractMsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); + if (applier == null) { + applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " + + typeRecordNumber + " at " + address); + return; + } + DataType dataType = applier.getDataType(); + if (dataType == null) { + if (!(applier instanceof PrimitiveTypeApplier) || + !((PrimitiveTypeApplier) applier).isNoType()) { + applicator.appendLogMsg("Error: Failed to resolve datatype " + + applier.getMsType().getName() + " at " + address); + } + return; + } + if (!(dataType instanceof FunctionDefinition)) { + //TODO: might want to do an ApplyDatatypeCmd here!!! + DumbMemBufferImpl memBuffer = + new DumbMemBufferImpl(applicator.getProgram().getMemory(), address); + DataTypeInstance dti = DataTypeInstance.getDataTypeInstance(dataType, memBuffer); + if (dti == null) { + applicator.appendLogMsg( + "Error: Failed to apply datatype " + dataType.getName() + " at " + address); + return; + } + createData(address, dti.getDataType(), dti.getLength()); + } + } + + private void createData(Address address, DataType dataType, int dataTypeLength) { + + // Ensure that we do not clear previously established code and data + Data existingData = null; + CodeUnit cu = applicator.getProgram().getListing().getCodeUnitContaining(address); + if (cu != null) { + if ((cu instanceof Instruction) || !address.equals(cu.getAddress())) { + applicator.appendLogMsg("Warning: Did not create data type \"" + + dataType.getDisplayName() + "\" at address " + address + " due to conflict"); + return; + } + Data d = (Data) cu; + if (d.isDefined()) { + existingData = d; + } + } + + if (dataType == null) { + return; + } + if (dataType.getLength() <= 0 && dataTypeLength <= 0) { + applicator.appendLogMsg("Unknown dataTypeLength specified at address " + address + + " for " + dataType.getName()); + return; + } + + // TODO: This is really bad logic and should be refactored + // All conflicting data, not just the one containing address, + // needs to be considered and not blindly cleared. + + if (existingData != null) { + DataType existingDataType = existingData.getDataType(); + if (isEquivalent(existingData, existingData.getLength(), dataType)) { + return; + } + if (isEquivalent2(existingDataType, dataType)) { + return; + } + if (existingDataType.isEquivalent(dataType)) { + return; + } + } + if (existingData == null) { + try { + applicator.getProgram().getListing().clearCodeUnits(address, + address.add(dataTypeLength - 1), false); + if (dataType.getLength() == -1) { + applicator.getProgram().getListing().createData(address, dataType, + dataTypeLength); + } + else { + applicator.getProgram().getListing().createData(address, dataType); + } + } + catch (Exception e) { + applicator.appendLogMsg("Unable to create " + dataType.getDisplayName() + " at 0x" + + address + ": " + e.getMessage()); + } + } + else if (isDataReplaceable(existingData)) { + try { + applicator.getProgram().getListing().clearCodeUnits(address, + address.add(dataTypeLength - 1), false); + applicator.getProgram().getListing().createData(address, dataType, dataTypeLength); + } + catch (Exception e) { + applicator.appendLogMsg("Unable to replace " + dataType.getDisplayName() + + " at 0x" + address + ": " + e.getMessage()); + } + } + else { + DataType existingDataType = existingData.getDataType(); + String existingDataTypeString = + existingDataType == null ? "null" : existingDataType.getDisplayName(); + applicator.appendLogMsg("Warning: Did not create data type \"" + + dataType.getDisplayName() + "\" at address " + address + + ". Preferring existing datatype \"" + existingDataTypeString + "\""); + } + } + + private boolean isDataReplaceable(Data data) { + DataType dataType = data.getDataType(); + if (dataType instanceof Pointer) { + Pointer pointer = (Pointer) dataType; + DataType pointerDataType = pointer.getDataType(); + if (pointerDataType == null || pointerDataType.isEquivalent(DataType.DEFAULT)) { + return true; + } + } + else if (dataType instanceof Array) { + Array array = (Array) dataType; + DataType arrayDataType = array.getDataType(); + if (arrayDataType == null || arrayDataType.isEquivalent(DataType.DEFAULT)) { + return true; + } + } + + // All forms of Undefined data are replaceable + // TODO: maybe it should check the length of the data type before putting it down. + if (Undefined.isUndefined(dataType)) { + return true; + } + return false; + } + + private boolean isEquivalent(Data existingData, int existingDataTypeLength, + DataType newDataType) { + if (existingData.hasStringValue()) { + if (newDataType instanceof ArrayDataType) { + Array array = (Array) newDataType; + DataType arrayDataType = array.getDataType(); + if (arrayDataType instanceof ArrayStringable) { + if (array.getLength() == existingDataTypeLength) { + return true; + } + } + } + } + return false; + } + + /** + * "char[12] *" "char * *" + * + * "ioinfo * *" "ioinfo[64] *" + */ + private boolean isEquivalent2(DataType datatype1, DataType datatype2) { + + if (datatype1 == datatype2) { + return true; + } + + if (datatype1 == null || datatype2 == null) { + return false; + } + + if (datatype1 instanceof Array) { + Array array1 = (Array) datatype1; + if (datatype2 instanceof Array) { + Array array2 = (Array) datatype2; + return isEquivalent2(array1.getDataType(), array2.getDataType()); + } + } + else if (datatype1 instanceof Pointer) { + Pointer pointer1 = (Pointer) datatype1; + if (datatype2 instanceof Array) { + Array array2 = (Array) datatype2; + return isEquivalent2(pointer1.getDataType(), array2.getDataType()); + } + } + return datatype1.isEquivalent(datatype2); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/Default2PdbMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/Default2PdbMember.java new file mode 100644 index 0000000000..2172b51983 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/Default2PdbMember.java @@ -0,0 +1,108 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +import ghidra.app.util.bin.format.pdb.*; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.CancelledException; + +/** + * PdbMember convey PDB member information used for datatype + * reconstruction. + */ +public class Default2PdbMember extends PdbMember { + + private AbstractMsTypeApplier applier; + private DataType dataType; + + /** + * Default PDB member construction + * @param applicator {@link PdbApplicator} for which we are working. + * @param name member field name. For bitfields this also conveys the bit-size + * and optionally the bit-offset. + * @param applier fieldApplier for the field datatype or base datatype associated with the + * bitfield. + * @param offset member's byte offset within the root composite. + */ + Default2PdbMember(PdbApplicator applicator, String name, AbstractMsTypeApplier applier, + int offset) { + super(name, (applier.getDataType()).getName(), offset, null); + this.applier = applier; + dataType = null; + } + + /** + * Default PDB member construction + * @param applicator {@link PdbApplicator} for which we are working. + * @param name member field name. For bitfields this also conveys the bit-size + * and optionally the bit-offset. + * @param dataType for the field. + * @param offset member's byte offset within the root composite. + */ + Default2PdbMember(PdbApplicator applicator, String name, DataType dataType, int offset) { + super(name, dataType.getName(), offset, null); + this.applier = null; + this.dataType = dataType; + } + + AbstractMsTypeApplier getApplier() { + return applier; + } + + private DataType getDataTypeInternal() { + if (applier != null) { + return applier.getDataType(); + } + return dataType; + } + + @Override + public String getDataTypeName() { + return getDataTypeInternal().getName(); + } + + @Override + public String toString() { + String str = "name=" + getName(); + DataType dt = getDataTypeInternal(); + if (dt instanceof PdbBitField) { + PdbBitField bfDt = (PdbBitField) dataType; + str += ", type=" + bfDt.getBaseDataType().getName(); + str += ", offset=" + getOffset(); + str += ", bitSize=" + bfDt.getDeclaredBitSize() + ", bitOffset=" + + bfDt.getBitOffsetWithinBase(); + } + else { + str += ", type=" + dataType.getName(); + str += ", offset=" + getOffset(); + } + return str; + } + + @Override + protected WrappedDataType getDataType() throws CancelledException { + DataType dt = getDataTypeInternal(); + if (applier != null && applier instanceof ArrayTypeApplier) { + if (BigInteger.ZERO.compareTo(applier.getSize()) == 0) { + return new WrappedDataType(dt, true, false); + } + } + return new WrappedDataType(dt, false, false); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java new file mode 100644 index 0000000000..981f05fdc8 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java @@ -0,0 +1,75 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +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.symbol.*; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractDefinedSingleAddressRangeMsSymbol} symbols. + */ +public class DefinedSingleAddressRangeSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractDefinedSingleAddressRangeMsSymbol symbol; + + public DefinedSingleAddressRangeSymbolApplier(PdbApplicator applicator, + AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractDefinedSingleAddressRangeMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractDefinedSingleAddressRangeMsSymbol) abstractSymbol; + } + + @Override + public void apply() throws PdbException, CancelledException { + String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; + Msg.info(this, message); + PdbLog.message(message); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) + throws PdbException, CancelledException { + if (applyToApplier instanceof LocalOptimizedSymbolApplier) { +// TODO: eventually apply. +// LocalOptimizedSymbolApplier localSymbolApplier = +// (LocalOptimizedSymbolApplier) applyToApplier; + symbol.getAddressRange(); + symbol.getAddressGapList(); + if (symbol instanceof EnregisteredSymbolDARMsSymbol) { + EnregisteredSymbolDARMsSymbol sym1 = (EnregisteredSymbolDARMsSymbol) symbol; + sym1.getRangeAttribute(); + sym1.getRegister(); + } + else if (symbol instanceof EnregisteredFieldOfSymbolDARMsSymbol) { + EnregisteredFieldOfSymbolDARMsSymbol sym1 = + (EnregisteredFieldOfSymbolDARMsSymbol) symbol; + sym1.getOffsetInParent(); + sym1.getRangeAttribute(); + sym1.getRegister(); + } + } + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java new file mode 100644 index 0000000000..52516ff904 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java @@ -0,0 +1,70 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +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.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.EndMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; + +/** + * Applier for {@link EndMsSymbol} symbols. + */ +public class EndSymbolApplier extends AbstractMsSymbolApplier { + + public EndSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof EndMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + } + + @Override + public void apply() throws PdbException { + String message = + String.format("Cannot apply %s directly to program (module:0X%04X, offset:0X%08X)", + this.getClass().getSimpleName(), iter.getModuleNumber(), iter.getCurrentOffset()); + Msg.info(this, message); + PdbLog.message(message); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + if (!(applyToApplier instanceof FunctionSymbolApplier)) { + return; + } + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; +// functionSymbolApplier.endBlock(); + } + + @Override + public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + if (applierParam instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; + functionSymbolApplier.endBlock(); + } + else if (applierParam instanceof SeparatedCodeSymbolApplier) { + SeparatedCodeSymbolApplier separatedCodeSymbolApplier = + (SeparatedCodeSymbolApplier) applierParam; + separatedCodeSymbolApplier.endBlock(); + } + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java new file mode 100644 index 0000000000..15702ff5b1 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java @@ -0,0 +1,321 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; +import java.util.List; + +import ghidra.app.util.SymbolPath; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.program.model.data.*; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractEnumMsType} types. + */ +public class EnumTypeApplier extends AbstractComplexTypeApplier { + + //private AbstractMsTypeApplier underlyingApplier = null; + +// private int length = 0; +// private boolean isSigned = false; +// + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractEnumMsType)) { + throw new IllegalArgumentException("PDB Incorrectly applying " + + type.getClass().getSimpleName() + " to " + EnumTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for enum type applier, for transforming a enum into a + * Ghidra DataType. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractEnumMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public EnumTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + AbstractMsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); + if (underlyingApplier == null) { + return BigInteger.ZERO; + } + return underlyingApplier.getSize(); + } + + private long getMask() { + switch (getLength()) { + case 1: + return 0xffL; + case 2: + return 0xffffL; + case 4: + return 0xffffffffL; + default: + return 0xffffffffffffffffL; + } + } + + private int getLength() { + // Minimum length allowed by Ghidra is 1 for enum, so all returns are min 1. + AbstractMsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); + if (underlyingApplier == null) { + return 1; + } + DataType underlyingType = underlyingApplier.getDataType(); + if (underlyingType == null) { + return 1; + } + return Integer.max(underlyingType.getLength(), 1); + } + + public boolean isSigned() { + AbstractMsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); + if (underlyingApplier == null) { + return false; + } + DataType underlyingType = underlyingApplier.getDataType(); + if (underlyingType == null) { + return false; + } + if (underlyingType instanceof AbstractIntegerDataType) { + return ((AbstractIntegerDataType) underlyingType).isSigned(); + } + return false; + } + + @Override + public EnumTypeApplier getDependencyApplier() { + if (definitionApplier != null && definitionApplier instanceof EnumTypeApplier) { + return (EnumTypeApplier) definitionApplier; + } + return this; + } + + public String getName() { + return getMsType().getName(); + } + + private AbstractMsTypeApplier getUnderlyingTypeApplier() { + AbstractMsTypeApplier under = null; + AbstractMsTypeApplier applier = (definitionApplier != null) ? definitionApplier : this; + RecordNumber underlyingRecordNumber = + ((AbstractEnumMsType) applier.getMsType()).getUnderlyingRecordNumber(); + under = applicator.getTypeApplier(underlyingRecordNumber); + if (under == null) { + applicator.appendLogMsg("Missing applier for underlying type index " + + underlyingRecordNumber + " in Enum " + msType.getName()); + } + return under; + } + + private EnumDataType createEmptyEnum(AbstractEnumMsType type) throws PdbException { + + SymbolPath fixedPath = getFixedSymbolPath(); + CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent()); + +// MsProperty property = type.getMsProperty(); +// if (property.isForwardReference()) { +// int a = 1; +// a = a + 1; +// } +//// RecordNumber underlyingRecordNumber = type.getUnderlyingRecordNumber(); +//// underlyingApplier = applicator.getApplier(underlyingRecordNumber); +// determineUnderlyingTypeApplier(); +// +// if (underlyingApplier == null) { +// return null; +// } +// DataType underlyingType = underlyingApplier.getDataType(); +// if (underlyingType != null) { +// length = underlyingType.getLength(); +// if (underlyingType instanceof AbstractIntegerDataType) { +// isSigned = ((AbstractIntegerDataType) underlyingType).isSigned(); +// } +// else if (!(underlyingType instanceof VoidDataType)) { +// String msg = "Cannot processes enum with underlying type: " + +// underlyingType.getClass().getSimpleName(); +// Msg.info(this, msg); +// PdbLog.message(msg); +// throw new PdbException(msg); +// } +// } +// else { +// AbstractMsType underlying = underlyingApplier.getMsType(); +// if (underlying instanceof PrimitiveMsType) { +// length = ((PrimitiveMsType) underlying).getTypeSize(); +// //TODO: can we set isSigned in here? ((PrimitiveMsType) underlying) +// // TODO: there might be more +// // TODO: investigate getSize() on AbstractMsType? +// // then: length = underlying.getSize(); +// } +// } +// // Ghidra does not like size of zero. +// length = Integer.max(length, 1); + + EnumDataType enumDataType = new EnumDataType(categoryPath, fixedPath.getName(), getLength(), + applicator.getDataTypeManager()); + + return enumDataType; + } + + @Override + public void apply() throws PdbException, CancelledException { + getOrCreateEnum(); + + AbstractEnumMsType type = (AbstractEnumMsType) msType; + MsProperty property = type.getMsProperty(); + if (property.isForwardReference()) { + return; + } + + applyEnumMsType((AbstractEnumMsType) msType); + + } + + @Override + public void resolve() { + if (!isForwardReference()) { + super.resolve(); + } + } + + // Mapping of fwdRef/def must be done prior to this call. + private void getOrCreateEnum() throws PdbException { + AbstractEnumMsType neededType = (AbstractEnumMsType) msType; + if (dataType != null) { + return; + } + if (isForwardReference()) { + if (definitionApplier != null) { + dataType = definitionApplier.getDataTypeInternal(); + if (dataType != null) { + return; + } + neededType = (AbstractEnumMsType) definitionApplier.getMsType(); + } + } + else { + if (fwdRefApplier != null) { + dataType = fwdRefApplier.getDataTypeInternal(); + if (dataType != null) { + return; + } + } + } + dataType = createEmptyEnum(neededType); + } + + private EnumDataType applyEnumMsType(AbstractEnumMsType type) throws PdbException { + + String fullPathName = type.getName(); + +// // TODO: evaluate whether we do full SymbolPath... see others +// SymbolPath fixedPath = getFixedSymbolPath(); +// +// RecordNumber underlyingRecordNumber = type.getUnderlyingRecordNumber(); +// MsProperty property = type.getMsProperty(); +// if (property.isForwardReference()) { +// int a = 1; +// a = a + 1; +// } +// underlyingApplier = applicator.getApplier(underlyingRecordNumber); +// +// if (underlyingApplier == null) { +// applicator.appendLogMsg("Missing applier for underlying type index " + +// underlyingRecordNumber + " in Enum " + fullPathName); +// return null; +// } +// DataType underlyingType = underlyingApplier.getDataType(); +// int length = 0; +// if (underlyingType != null) { +// length = underlyingType.getLength(); +// } +// else { +// AbstractMsType underlying = underlyingApplier.getMsType(); +// if (underlying instanceof PrimitiveMsType) { +// length = ((PrimitiveMsType) underlying).getTypeSize(); +// // TODO: there might be more +// // TODO: investigate getSize() on AbstractMsType? +// // then: length = underlying.getSize(); +// } +// } +// // Ghidra does not like size of zero. +// length = Integer.max(length, 1); +// +// CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent()); +// EnumDataType enumDataType = new EnumDataType(categoryPath, fixedPath.getName(), length, +// applicator.getDataTypeManager()); +// + + RecordNumber fieldListRecordNumber = type.getFieldDescriptorListRecordNumber(); + FieldListTypeApplier fieldListApplier = + FieldListTypeApplier.getFieldListApplierSpecial(applicator, fieldListRecordNumber); + + // Note: not doing anything with getNamespaceList() or getMethodsList() at this time. + List memberList = fieldListApplier.getMemberList(); + + int numElements = type.getNumElements(); + if (memberList.size() != numElements) { + String message = "Enum expecting " + numElements + " elements, but only " + + memberList.size() + " available for " + fullPathName; + Msg.info(this, message); + PdbLog.message(message); + } + EnumDataType enumDataType = (EnumDataType) dataType; + int length = getLength(); + boolean isSigned = isSigned(); + for (AbstractMsTypeApplier memberApplier : memberList) { + if (memberApplier instanceof EnumerateTypeApplier) { + EnumerateTypeApplier enumerateApplier = (EnumerateTypeApplier) memberApplier; + SymbolPath memberSymbolPath = new SymbolPath(enumerateApplier.getName()); + enumDataType.add(memberSymbolPath.getName(), + narrowingConversion(length, isSigned, enumerateApplier.getNumeric())); + } + else { // (member instanceof AbstractMemberMsType) + // I do not believe (until proven otherwise) that an Enum will have members of + // type AbstractMemberMsType. + PdbLog.message(getClass().getSimpleName() + ": unexpected " + + memberApplier.getClass().getSimpleName()); + } + } + return enumDataType; + } + + private long narrowingConversion(int outputSize, boolean outputSigned, Numeric numeric) { + if (!numeric.isIntegral()) { + Msg.info(this, "Non-integral numeric found: " + numeric); + return 0; + } + if (!numeric.isIntegral()) { + PdbLog.message("Using zero in place of non-integral enumerate: " + numeric); + return 0L; // + } + return numeric.getIntegral().longValue() & getMask(); +// return NarrowingConverter.narrowBigToLong(outputSize, outputSigned, numeric.getSize(), +// numeric.isSigned(), numeric.getIntegral()); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java new file mode 100644 index 0000000000..a6889993da --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java @@ -0,0 +1,93 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +import ghidra.app.util.bin.format.pdb2.pdbreader.Numeric; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractEnumerateMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.app.util.pdb.PdbNamespaceUtils; +import ghidra.program.model.data.DataType; + +/** + * Applier for {@link AbstractEnumerateMsType} types. + */ +public class EnumerateTypeApplier extends AbstractMsTypeApplier { + + private String fieldName; + private Numeric numeric; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractEnumerateMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + EnumerateTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for enumerate type applier, for transforming a enumerate into a + * Ghidra DataType. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractEnumerateMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public EnumerateTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + + @Override + public void apply() { + dataType = applyEnumerateMsType((AbstractEnumerateMsType) msType); +// DataType dataType = applyEnumerateMsType((AbstractEnumerateMsType) msType); +// ghDataType = dataType; // temporary while below is commented-out + // TODO: uncomment when above method not returning null +// ghDataTypeDB = applicator.resolve(dataType); + } + + public String getName() { + return fieldName; + } + + public Numeric getNumeric() { + return numeric; + } + + private DataType applyEnumerateMsType(AbstractEnumerateMsType type) { + + //TODO: currently dropping these on the floor. The access methods above do the same work. + + fieldName = PdbNamespaceUtils.fixUnnamed(type.getName(), index); + + // TODO: Need to build test sample with these. + // TODO: Need to see if can do real number; need to modify Numeric for both + // integral and real numbers. Possibly need to make Numeric a "type" instead + // of just something to read using ByteReader. + numeric = type.getNumeric(); + + return null; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java new file mode 100644 index 0000000000..5089fbca3a --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java @@ -0,0 +1,183 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.program.model.data.DataType; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractFieldListMsType} types and {@code NO_TYPE} when in place of the + * former type. + */ +public class FieldListTypeApplier extends AbstractMsTypeApplier { + + private List baseClassList = new ArrayList<>(); + private List memberList = new ArrayList<>(); + private List methodList = new ArrayList<>(); + private boolean isEmpty; + + // return can be null + static FieldListTypeApplier getFieldListApplierSpecial(PdbApplicator applicator, + RecordNumber recordNumber) throws PdbException { + AbstractMsTypeApplier applier = + applicator.getApplierOrNoTypeSpec(recordNumber, FieldListTypeApplier.class); + FieldListTypeApplier fieldListApplier = null; + if (applier instanceof FieldListTypeApplier) { + return (FieldListTypeApplier) applicator.getApplierOrNoTypeSpec(recordNumber, + FieldListTypeApplier.class); + } + try { + if (recordNumber.getCategory() == RecordCategory.TYPE) { + fieldListApplier = new FieldListTypeApplier(applicator, + applicator.getPdb().getTypeRecord(recordNumber), true); + } + } + catch (IllegalArgumentException e) { + applicator.appendLogMsg(e.getMessage()); + } + return fieldListApplier; + } + + /** + * Constructor. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractFieldListMsType} or {@link PrimitiveMsType} of {@code NO_TYPE} + * @throws IllegalArgumentException Upon invalid arguments. + */ + public FieldListTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + this(applicator, msType, false); + } + + /** + * Constructor with override for NO_TYPE Primitive. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractFieldListMsType} or {@link PrimitiveMsType} of {@code NO_TYPE} + * @param noType {@code true} to specify that {@code msType} is NO_TYPE. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public FieldListTypeApplier(PdbApplicator applicator, AbstractMsType msType, boolean noType) + throws IllegalArgumentException { + super(applicator, msType); + if (noType && msType instanceof PrimitiveMsType && ((PrimitiveMsType) msType).isNoType()) { + this.isEmpty = true; + } + else { + if (!(msType instanceof AbstractFieldListMsType)) { + throw new IllegalArgumentException("PDB Incorrectly applying " + + msType.getClass().getSimpleName() + " to " + this.getClass().getSimpleName()); + } + this.isEmpty = false; + } + } + + /** + * Indicates that the list is empty + * @return {@code true} if list is empty. + */ + public boolean isEmpty() { + return isEmpty; + } + + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + + @Override + public void apply() throws PdbException, CancelledException { + dataType = applyFieldListMsType((AbstractFieldListMsType) msType); + } + + public List getBaseClassList() { + return baseClassList; + } + + public List getMemberList() { + return memberList; + } + + public List getMethodList() { + return methodList; + } + + private DataType applyFieldListMsType(AbstractFieldListMsType type) + throws PdbException, CancelledException { + + applyBaseClasses(type.getBaseClassList()); + applyMembers(type.getMemberList()); + applyMethods(type.getMethodList()); + + for (AbstractIndexMsType indexType : type.getIndexList()) { + AbstractMsTypeApplier referencedTypeApplier = + applicator.getTypeApplier(indexType.getReferencedRecordNumber()); + if (referencedTypeApplier instanceof FieldListTypeApplier) { + FieldListTypeApplier subApplier = (FieldListTypeApplier) referencedTypeApplier; + baseClassList.addAll(subApplier.getBaseClassList()); + memberList.addAll(subApplier.getMemberList()); + methodList.addAll(subApplier.getMethodList()); + } + else { + String message = "referenceTypeApplier is not FieldListTypeApplier"; + Msg.info(this, message); + PdbLog.message(message); + } + } + return null; + } + + private void applyBaseClasses(List baseClasses) + throws CancelledException, PdbException { + for (MsTypeField typeIterated : baseClasses) { + // Use dummy index of zero. + AbstractMsTypeApplier applier = + applicator.getTypeApplier((AbstractMsType) typeIterated); + applier.apply(); // Need to apply here, as these are embedded records + baseClassList.add(applier); + } + } + + private void applyMembers(List members) throws CancelledException, PdbException { + for (MsTypeField typeIterated : members) { + // Use dummy index of zero. + AbstractMsTypeApplier applier = + applicator.getTypeApplier((AbstractMsType) typeIterated); + applier.apply(); // Need to apply here, as these are embedded records + memberList.add(applier); + } + } + + private void applyMethods(List methods) throws CancelledException, PdbException { + for (MsTypeField typeIterated : methods) { + // Use dummy index of zero. + AbstractMsTypeApplier applier = + applicator.getTypeApplier((AbstractMsType) typeIterated); + // TODO: note that these are likely NoTypeAppliers at the moment, as we had not + // yet implemented appliers for AbstractOneMethodMsType and + // AbstractOverloadedMethodMsType + applier.apply(); // Need to apply here, as these are embedded records + methodList.add(applier); + } + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java new file mode 100644 index 0000000000..c8edec85f8 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java @@ -0,0 +1,57 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.ExtraFrameAndProcedureInformationMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link ExtraFrameAndProcedureInformationMsSymbol} symbols. + */ +public class FrameAndProcedureInformationSymbolApplier extends AbstractMsSymbolApplier { + + private ExtraFrameAndProcedureInformationMsSymbol symbol; + + public FrameAndProcedureInformationSymbolApplier(PdbApplicator applicator, + AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof ExtraFrameAndProcedureInformationMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (ExtraFrameAndProcedureInformationMsSymbol) abstractSymbol; + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) + throws PdbException, CancelledException { + if (applyToApplier instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; +// public void applyTo(FunctionSymbolApplier functionSymbolApplier) { + functionSymbolApplier.setSpecifiedFrameSize(symbol.getProcedureFrameTotalLength()); + } + } + + @Override + public void apply() { + // Quietly do nothing + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java new file mode 100644 index 0000000000..5963f89ad8 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -0,0 +1,456 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.*; + +import ghidra.app.cmd.disassemble.DisassembleCommand; +import ghidra.app.cmd.function.*; +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.symbol.*; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +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.lang.Register; +import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.SourceType; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Applier for {@link AbstractProcedureStartMsSymbol} and {@link AbstractThunkMsSymbol} symbols. + */ +public class FunctionSymbolApplier extends AbstractMsSymbolApplier { + + private static final String BLOCK_INDENT = " "; + + private AbstractProcedureMsSymbol procedureSymbol; + private AbstractThunkMsSymbol thunkSymbol; + private Address specifiedAddress; + private Address remapAddress; + private Function function = null; + private long specifiedFrameSize = 0; + private long currentFrameSize = 0; + private BlockCommentsManager comments; + + private int symbolBlockNestingLevel; + private Address currentBlockAddress; + + // might not need this, but investigating whether it will help us. TODO remove? + private int baseParamOffset = 0; + +// private List stackVariableAppliers = new ArrayList<>(); + + private List allAppliers = new ArrayList<>(); + private RegisterChangeCalculator registerChangeCalculator; + + public FunctionSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) + throws CancelledException, NoSuchElementException { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + symbolBlockNestingLevel = 0; + comments = new BlockCommentsManager(); + currentBlockAddress = null; + + if (abstractSymbol instanceof AbstractProcedureMsSymbol) { + procedureSymbol = (AbstractProcedureMsSymbol) abstractSymbol; + specifiedAddress = applicator.reladdr(procedureSymbol); + } + else if (abstractSymbol instanceof AbstractThunkMsSymbol) { + thunkSymbol = (AbstractThunkMsSymbol) abstractSymbol; + specifiedAddress = applicator.reladdr(thunkSymbol); + } + else { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + remapAddress = applicator.getRemapAddressByAddress(specifiedAddress); + manageBlockNesting(this); + + while (notDone()) { + applicator.checkCanceled(); + AbstractMsSymbolApplier applier = applicator.getSymbolApplier(iter); + allAppliers.add(applier); + applier.manageBlockNesting(this); + } + } + + @Override + public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + if (applierParam instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; + if (procedureSymbol != null) { + long start = procedureSymbol.getDebugStartOffset(); + long end = procedureSymbol.getDebugEndOffset(); + Address blockAddress = remapAddress.add(start); + long length = end - start; + functionSymbolApplier.beginBlock(blockAddress, procedureSymbol.getName(), length); + } + else if (thunkSymbol != null) { + functionSymbolApplier.beginBlock(remapAddress, thunkSymbol.getName(), + thunkSymbol.getLength()); + } + } + } + + /** + * Returns the {@link Function} for this applier. + * @return the Function + */ + public Function getFunction() { + return function; + } + + /** + * Returns the current frame size. + * @return the current frame size. + */ + public long getCurrentFrameSize() { + return currentFrameSize; + } + + /** + * Returns the frame size as specified by the PDB + * @return the frame size. + */ + public long getSpecifiedFrameSize() { + return specifiedFrameSize; + } + + /** + * Set the specified frame size. + * @param specifiedFrameSize the frame size. + */ + void setSpecifiedFrameSize(long specifiedFrameSize) { + this.specifiedFrameSize = specifiedFrameSize; + currentFrameSize = specifiedFrameSize; + } + + /** + * Get the function name + * @return the function name + */ + public String getName() { + if (procedureSymbol != null) { + return procedureSymbol.getName(); + } + else if (thunkSymbol != null) { + return thunkSymbol.getName(); + } + return ""; + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing. + } + + @Override + public void apply() throws PdbException, CancelledException { + boolean result = applyTo(applicator.getCancelOnlyWrappingMonitor()); + if (result == false) { + throw new PdbException("failure in applying " + this.getClass().getSimpleName() + + " to program: " + getName()); + } + } + + public boolean applyTo(TaskMonitor monitor) throws PdbException, CancelledException { + return applyTo(applicator.getProgram(), remapAddress, monitor); + } + + public boolean applyTo(Program program, Address address, TaskMonitor monitor) + throws PdbException, CancelledException { + + boolean functionSuccess = applyFunction(program, address, monitor); + if (functionSuccess == false) { + return false; + } + registerChangeCalculator = new RegisterChangeCalculator(procedureSymbol, function, monitor); + + baseParamOffset = VariableUtilities.getBaseStackParamOffset(function); + + for (AbstractMsSymbolApplier applier : allAppliers) { + applier.applyTo(this); + } + + // comments + long addressDelta = address.subtract(specifiedAddress); + comments.applyTo(program, addressDelta); + + // line numbers + // TODO: not done yet +// ApplyLineNumbers applyLineNumbers = new ApplyLineNumbers(pdbParser, xmlParser, program); +// applyLineNumbers.applyTo(monitor, log); + + return true; + } + + public Integer getRegisterPrologChange(Register register) { + return registerChangeCalculator.getRegChange(applicator, register); + } + + public int getBaseParamOffset() { + return baseParamOffset; + } + + /** + * Sets a local variable (address, name, type) + * @param address Address of the variable. + * @param name name of the variable. + * @param dataType data type of the variable. + */ + void setLocalVariable(Address address, String name, DataType dataType) { + if (currentBlockAddress == null) { + return; // silently return. + } + // Currently just placing a comment. + String comment = getIndent(symbolBlockNestingLevel + 1) + "static local (stored at " + + address + ") " + dataType.getName() + " " + name; + comments.addPreComment(currentBlockAddress, comment); + } + + private boolean applyFunction(Program program, Address address, TaskMonitor monitor) { + Listing listing = program.getListing(); + + boolean forcePrimary = applicator.shouldForcePrimarySymbol(address, true); + applicator.createSymbol(address, getName(), forcePrimary); + + function = listing.getFunctionAt(address); + if (function == null) { + function = createFunction(program, address, monitor); + } + if (function != null && !function.isThunk() && + (function.getSignatureSource() == SourceType.DEFAULT || + function.getSignatureSource() == SourceType.ANALYSIS)) { + // Set the function definition + setFunctionDefinition(program, address, monitor); + + } + if (function == null) { + return false; + } + + currentFrameSize = 0; + return true; + } + + private Function createFunction(Program program, Address address, TaskMonitor monitor) { + + // Does function already exist? + Function myFunction = program.getListing().getFunctionAt(address); + if (myFunction != null) { + // Actually not sure if we should set to 0 or calculate from the function here. + // Need to investigate more, so at least keeping it as a separate 'else' for now. + return myFunction; + } + + // Disassemble + Instruction instr = program.getListing().getInstructionAt(address); + if (instr == null) { + DisassembleCommand cmd = new DisassembleCommand(address, null, true); + cmd.applyTo(program, monitor); + } + + myFunction = createFunctionCommand(program, address, monitor); + + return myFunction; + } + + private boolean setFunctionDefinition(Program program, Address address, TaskMonitor monitor) { + if (procedureSymbol == null) { + // TODO: is there anything we can do with thunkSymbol? + // long x = thunkSymbol.getParentPointer(); + return true; + } + // Rest presumes procedureSymbol. + RecordNumber typeRecordNumber = procedureSymbol.getTypeRecordNumber(); + AbstractMsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); + if (applier == null) { + applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " + + typeRecordNumber + " at " + address); + return false; + } + if (!(applier instanceof AbstractFunctionTypeApplier)) { + if (!((applier instanceof PrimitiveTypeApplier) && + ((PrimitiveTypeApplier) applier).isNoType())) { + applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " + + typeRecordNumber + " at " + address); + return false; + } + } + + DataType dataType = applier.getDataType(); + // Since we know the applier is an AbstractionFunctionTypeApplier, then dataType is either + // FunctionDefinition or no type (typedef). + if (dataType instanceof FunctionDefinition) { + FunctionDefinition def = (FunctionDefinition) dataType; + ApplyFunctionSignatureCmd sigCmd = + new ApplyFunctionSignatureCmd(address, def, SourceType.IMPORTED); + if (!sigCmd.applyTo(program, monitor)) { + applicator.appendLogMsg( + "failed to apply signature to function at address " + address.toString()); + return false; + } + } + return true; + } + + private Function createFunctionCommand(Program program, Address entryPoint, + TaskMonitor monitor) { + CreateFunctionCmd funCmd = new CreateFunctionCmd(entryPoint); + if (!funCmd.applyTo(program, monitor)) { + applicator.appendLogMsg("Failed to apply function at address " + entryPoint.toString() + + "; attempting to use possible existing function"); + return program.getListing().getFunctionAt(entryPoint); + } + return funCmd.getFunction(); + } + + private boolean notDone() { + return (symbolBlockNestingLevel > 0) && iter.hasNext(); + } + + public int endBlock() { + if (--symbolBlockNestingLevel < 0) { + applicator.appendLogMsg( + "Block Nesting went negative for " + getName() + " at " + remapAddress); + } + if (symbolBlockNestingLevel == 0) { + //currentFunctionSymbolApplier = null; + } + return symbolBlockNestingLevel; + } + + public void beginBlock(Address startAddress, String name, long length) { + + int nestingLevel = beginBlock(startAddress); + if (!applicator.getPdbApplicatorOptions().applyCodeScopeBlockComments()) { + return; + } + + String indent = getIndent(nestingLevel); + + String baseComment = "level " + nestingLevel + ", length " + length; + + String preComment = indent + "PDB: Block Beg, " + baseComment; + if (!name.isEmpty()) { + preComment += " (" + name + ")"; + } + comments.addPreComment(startAddress, preComment); + + String postComment = indent + "PDB: Block End, " + baseComment; + Address endAddress = startAddress.add(((length <= 0) ? 0 : length - 1)); + comments.addPostComment(endAddress, postComment); + } + + private int beginBlock(Address startAddress) { + currentBlockAddress = startAddress; + ++symbolBlockNestingLevel; + return symbolBlockNestingLevel; + } + + private String getIndent(int indentLevel) { + String indent = ""; + for (int i = 1; i < indentLevel; i++) { + indent += BLOCK_INDENT; + } + return indent; + } + + // Method copied from ApplyStackVariables (ghidra.app.util.bin.format.pdb package) + // on 20191119. TODO: Do we need something like this? + /** + * Get the stack offset after it settles down. + * @param monitor TaskMonitor + * @return stack offset that stack variables will be relative to. + * @throws CancelledException upon user cancellation. + */ + private int getFrameBaseOffset(TaskMonitor monitor) throws CancelledException { + + int retAddrSize = function.getProgram().getDefaultPointerSize(); + + if (retAddrSize != 8) { + // don't do this for 32 bit. + return -retAddrSize; // 32 bit has a -4 byte offset + } + + Register frameReg = function.getProgram().getCompilerSpec().getStackPointer(); + Address entryAddr = function.getEntryPoint(); + AddressSet scopeSet = new AddressSet(); + scopeSet.addRange(entryAddr, entryAddr.add(64)); + CallDepthChangeInfo valueChange = + new CallDepthChangeInfo(function, scopeSet, frameReg, monitor); + InstructionIterator instructions = + function.getProgram().getListing().getInstructions(scopeSet, true); + int max = 0; + while (instructions.hasNext()) { + monitor.checkCanceled(); + Instruction next = instructions.next(); + int newValue = valueChange.getDepth(next.getMinAddress()); + if (newValue < -(20 * 1024) || newValue > (20 * 1024)) { + continue; + } + if (Math.abs(newValue) > Math.abs(max)) { + max = newValue; + } + } + return max; + } + + private static class RegisterChangeCalculator { + + private Map registerChangeByRegisterName = new HashMap<>(); + private CallDepthChangeInfo callDepthChangeInfo; + private Address debugStart; + + private RegisterChangeCalculator(AbstractProcedureMsSymbol procedureSymbol, + Function function, TaskMonitor monitor) throws CancelledException { + callDepthChangeInfo = createCallDepthChangInfo(procedureSymbol, function, monitor); + } + + private CallDepthChangeInfo createCallDepthChangInfo( + AbstractProcedureMsSymbol procedureSymbol, Function function, TaskMonitor monitor) + throws CancelledException { + if (procedureSymbol == null) { + return null; + } + Register frameReg = function.getProgram().getCompilerSpec().getStackPointer(); + Address entryAddr = function.getEntryPoint(); + debugStart = entryAddr.add(procedureSymbol.getDebugStartOffset()); + AddressSet scopeSet = new AddressSet(); + scopeSet.addRange(entryAddr, debugStart); + return new CallDepthChangeInfo(function, scopeSet, frameReg, monitor); + } + + public Integer getRegChange(PdbApplicator applicator, Register register) { + if (callDepthChangeInfo == null || register == null) { + return null; + } + Integer change = registerChangeByRegisterName.get(register); + if (change != null) { + return change; + } + change = callDepthChangeInfo.getRegDepth(debugStart, register); + registerChangeByRegisterName.put(register, change); + return change; + } + + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java new file mode 100644 index 0000000000..8482dc6e55 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java @@ -0,0 +1,73 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.NamespaceUtils; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractLabelMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.FunctionManager; +import ghidra.program.model.symbol.Namespace; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractLabelMsSymbol} symbols. + */ +public class LabelSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractLabelMsSymbol symbol; + + public LabelSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractLabelMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractLabelMsSymbol) abstractSymbol; + } + + @Override + public void apply() throws PdbException, CancelledException { + if (!applicator.getPdbApplicatorOptions().applyInstructionLabels()) { + return; + } + // Place compiler generated symbols (e.g., $LN9) within containing function when possible + String name = symbol.getName(); + Address symbolAddress = applicator.reladdr(symbol); + FunctionManager functionManager = applicator.getProgram().getFunctionManager(); + // TODO: What do we do with labels such as this?... "__catch$?test_eh1@@YAHXZ$7" + if (name.startsWith("$") && !name.contains(Namespace.DELIMITER)) { + Function f = functionManager.getFunctionContaining(symbolAddress); + if (f != null && !f.getName().equals(name)) { + name = NamespaceUtils.getNamespaceQualifiedName(f, name, true); + } + } + boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); + if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { + applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); + } + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java new file mode 100644 index 0000000000..d72c00b5ee --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java @@ -0,0 +1,77 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +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.symbol.*; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractLocalSymbolInOptimizedCodeMsSymbol} symbols. + */ +public class LocalOptimizedSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractLocalSymbolInOptimizedCodeMsSymbol symbol; + + public LocalOptimizedSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractLocalSymbolInOptimizedCodeMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractLocalSymbolInOptimizedCodeMsSymbol) abstractSymbol; + } + + @Override + public void apply() throws PdbException, CancelledException { + String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; + Msg.info(this, message); + PdbLog.message(message); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) + throws PdbException, CancelledException { + if (!applicator.getPdbApplicatorOptions().applyFunctionVariables()) { + return; + } + if (applyToApplier instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; + doWork(functionSymbolApplier); + } + } + + private void doWork(FunctionSymbolApplier functionSymbolApplier) + throws CancelledException, PdbException { + // TODO: Not doing anything with the information yet. + symbol.getLocalVariableFlags(); + symbol.getName(); + symbol.getTypeRecordNumber(); + while (iter.hasNext() && + (iter.peek() instanceof AbstractDefinedSingleAddressRangeMsSymbol)) { + applicator.checkCanceled(); + DefinedSingleAddressRangeSymbolApplier rangeApplier = + new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + rangeApplier.applyTo(this); + } + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java new file mode 100644 index 0000000000..9c67bf3316 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java @@ -0,0 +1,274 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +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.*; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractMemberFunctionMsType} types. + */ +public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { + +// private boolean hasThisPointer = false; + private AbstractMsTypeApplier thisPointerApplier = null; + private CompositeTypeApplier containingCompositeApplier = null; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractMemberFunctionMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + MemberFunctionTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for the applicator that applies {@link AbstractMemberFunctionMsType}, + * transforming it into a Ghidra {@link DataType}. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractMemberFunctionMsType} to processes. + * @throws IllegalArgumentException Upon type mismatch. + */ + public MemberFunctionTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + + @Override + protected CallingConvention getCallingConvention() { + return ((AbstractMemberFunctionMsType) msType).getCallingConvention(); + } + + @Override + protected boolean hasThisPointer() throws CancelledException, PdbException { + AbstractMsTypeApplier applier = applicator.getTypeApplier( + ((AbstractMemberFunctionMsType) msType).getThisPointerRecordNumber()); + if ((applier instanceof PrimitiveTypeApplier && + ((PrimitiveTypeApplier) applier).isNoType())) { + return false; // such as for static member functions + } + return true; + } + + @Override + protected RecordNumber getReturnRecordNumber() { + return ((AbstractMemberFunctionMsType) msType).getReturnRecordNumber(); + } + + @Override + protected RecordNumber getArgListRecordNumber() { + return ((AbstractMemberFunctionMsType) msType).getArgListRecordNumber(); + } + + @Override + public void apply() throws PdbException, CancelledException { + predefineClasses(); + applyFunction(getCallingConvention(), hasThisPointer()); + } + + private void predefineClasses() throws CancelledException, PdbException { + AbstractMemberFunctionMsType procType = (AbstractMemberFunctionMsType) msType; + if (hasThisPointer()) { + thisPointerApplier = getThisPointerApplier(procType); + applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointer( + thisPointerApplier); + if (thisPointerApplier instanceof PointerTypeApplier) { + AbstractMsTypeApplier underlyingApplier = + getThisUnderlyingApplier((PointerTypeApplier) thisPointerApplier); + applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointerUnderlyingType( + underlyingApplier); + if (underlyingApplier instanceof CompositeTypeApplier) { + predefineClass((CompositeTypeApplier) underlyingApplier); + } + } + } + + AbstractComplexTypeApplier containingApplier = getContainingComplexApplier(procType); + applicator.getPdbApplicatorMetrics().witnessMemberFunctionContainingType(containingApplier); + if (containingApplier instanceof CompositeTypeApplier) { + // Do nothing at this time if Enum or something else + predefineClass((CompositeTypeApplier) containingApplier); + } + } + + private void predefineClass(CompositeTypeApplier applier) { + SymbolPath containingClassSymbolPath = applier.getFixedSymbolPath(); + applicator.predefineClass(containingClassSymbolPath); + } + +// private AbstractPointerMsType getThisType(AbstractMemberFunctionMsType procType) +// throws CancelledException, PdbException { +// int thisPointerTypeIndex = procType.getThisPointerTypeIndex(); +// AbstractMsTypeApplier applier = applicator.getTypeApplier(thisPointerTypeIndex); +// +// if ((applier instanceof PrimitiveTypeApplier && +// ((PrimitiveTypeApplier) applier).isNoType())) { +// return null; // such as for static member functions +// } +// if (!(applier instanceof PointerTypeApplier)) { +// applicator.getLog().appendMsg("thisApplier is invalid type for " + msType.getName()); +// return null; +// } +// AbstractMsType thisMsType = applier.getMsType(); +// // shouldn't need to do this next test, as an applier should only get this type +// if (!(thisMsType instanceof AbstractPointerMsType)) { +// applicator.getLog().appendMsg("thisMsType is invalid type for " + msType.getName()); +// return null; +// } +// return (AbstractPointerMsType) thisMsType; +// +// } +// +// private void processContainingClass(AbstractMemberFunctionMsType procType) +// throws CancelledException, PdbException { +// int containingClassTypeIndex = procType.getContainingClassTypeIndex(); +// +// CompositeTypeApplier containingCompositeApplier = +// applicator.getCompositeApplier(containingClassTypeIndex); +//// +//// ApplyCompositeType containingCompositeApplier = +//// (ApplyCompositeType) applicator.getExpectedTypeApplier(containingClassTypeIndex, +//// ApplyCompositeType.class); +// +//// AbstractApplyMsType containingTypeApplier = +//// applicator.getTypeApplier(containingClassTypeIndex, false); +//// if (containingTypeApplier == null) { +//// applicator.getLog().appendMsg( +//// "containingClassApplier is null for " + msType.getName()); +//// return null; +//// } +//// if (!(containingTypeApplier instanceof ApplyCompositeType)) { +//// applicator.getLog().appendMsg( +//// "containingClassApplier is invalid type for " + msType.getName()); +//// return null; +//// } +//// ApplyCompositeType containingCompositeApplier = (ApplyCompositeType) containingTypeApplier; +// SymbolPath containingClassSymbolPath = containingCompositeApplier.getFixedSymbolPath(); +// applicator.predefineClass(containingClassSymbolPath); +// +// } + +// private boolean hasThisPointer(AbstractMemberFunctionMsType procType) +// throws CancelledException, PdbException { +// int thisPointerTypeIndex = procType.getThisPointerTypeIndex(); +// AbstractMsTypeApplier applier = applicator.getTypeApplier(thisPointerTypeIndex); +// if ((applier instanceof PrimitiveTypeApplier && +// ((PrimitiveTypeApplier) applier).isNoType())) { +// return false; // such as for static member functions +// } +// return true; +// } + + private AbstractMsTypeApplier getThisPointerApplier(AbstractMemberFunctionMsType procType) { + AbstractMsTypeApplier applier = + applicator.getTypeApplier(procType.getThisPointerRecordNumber()); + +// if ((applier instanceof PrimitiveTypeApplier && +// ((PrimitiveTypeApplier) applier).isNoType())) { +// return null; // such as for static member functions +// } +// // Cannot just check of PointerTypeApplier because could instead be a +// // PrimitiveTypeApplier with PointerDataType as dataType +// if (!(applier.getDataType() instanceof PointerDataType)) { +// applicator.appendLogMsg(applier.getMsType().getClass().getSimpleName() + +// " this type is invalid type for " + msType.getClass().getSimpleName()); +// return null; +// } + applicator.addApplierDependency(this, applier); + return applier; + } + + private AbstractMsTypeApplier getThisUnderlyingApplier(PointerTypeApplier thisApplier) { + return thisApplier.getUnmodifiedUnderlyingTypeApplier(); + } + + private AbstractComplexTypeApplier getContainingComplexApplier( + AbstractMemberFunctionMsType procType) throws PdbException { + return AbstractComplexTypeApplier.getComplexApplier(applicator, + procType.getContainingClassRecordNumber()); + } + +// private void processPointerUnderlyingType() +// throws CancelledException, PdbException { +// +// AbstractMsTypeApplier thisUnderlyingTypeApplier = thisPointerApplier.getUnmodifiedUnderlyingTypeApplier(); +// +// if (!(thisUnderlyingTypeApplier instanceof CompositeTypeApplier)) { +// applicator.getLog().appendMsg( +// "thisUnderlyingTypeApplier is invalid type for " + msType.getName()); +// return; +// } +// CompositeTypeApplier thisUnderlyingCompositeApplier = +// (CompositeTypeApplier) thisUnderlyingTypeApplier; +// SymbolPath thisUnderlyingClassSymbolPath = +// thisUnderlyingCompositeApplier.getFixedSymbolPath(); +// applicator.predefineClass(thisUnderlyingClassSymbolPath); +// } + +// private AbstractPointerMsType processThisPointer(AbstractMemberFunctionMsType procType) +// throws CancelledException, PdbException { +// int thisPointerTypeIndex = procType.getThisPointerTypeIndex(); +// AbstractMsTypeApplier thisPointerApplier = applicator.getTypeApplier(thisPointerTypeIndex); +// +// if ((thisPointerApplier instanceof PrimitiveTypeApplier && +// ((PrimitiveTypeApplier) thisPointerApplier).isNoType())) { +// return null; // such as for static member functions +// } +// if (!(thisPointerApplier instanceof PointerTypeApplier)) { +// applicator.getLog().appendMsg("thisApplier is invalid type for " + msType.getName()); +// return null; +// } +// return (AbstractPointerMsType) thisPointerApplier.getMsType(); +// } +// +// private void processPointerUnderlyingType(AbstractPointerMsType thisPointerMsType) +// throws CancelledException, PdbException { +// +// int thisUnderlyingTypeIndex = thisPointerMsType.getUnderlyingTypeIndex(); +// AbstractMsTypeApplier thisUnderlyingTypeApplier = +// applicator.getTypeApplier(thisUnderlyingTypeIndex); +// +// // TODO: does not recurse below one level of modifiers... consider doing a recursion. +// if (thisUnderlyingTypeApplier instanceof ModifierTypeApplier) { +// ModifierTypeApplier x = (ModifierTypeApplier) thisUnderlyingTypeApplier; +// int y = ((AbstractModifierMsType) (x.getMsType())).getModifiedTypeIndex(); +// thisUnderlyingTypeApplier = applicator.getTypeApplier(y); +// } +// if (!(thisUnderlyingTypeApplier instanceof CompositeTypeApplier)) { +// applicator.getLog().appendMsg( +// "thisUnderlyingTypeApplier is invalid type for " + msType.getName()); +// return; +// } +// CompositeTypeApplier thisUnderlyingCompositeApplier = +// (CompositeTypeApplier) thisUnderlyingTypeApplier; +// SymbolPath thisUnderlyingClassSymbolPath = +// thisUnderlyingCompositeApplier.getFixedSymbolPath(); +// applicator.predefineClass(thisUnderlyingClassSymbolPath); +// } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java new file mode 100644 index 0000000000..029a81ab2d --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java @@ -0,0 +1,97 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractMemberMsType} types. + */ +public class MemberTypeApplier extends AbstractMsTypeApplier { + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractMemberMsType)) { + throw new IllegalArgumentException("PDB Incorrectly applying " + + type.getClass().getSimpleName() + " to " + MemberTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for member type applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractMemberMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public MemberTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + + @Override + public void apply() throws PdbException, CancelledException { + dataType = applyMemberMsType((AbstractMemberMsType) msType); +// DataType dataType = applyMemberMsType((AbstractMemberMsType) msType); +// ghDataType = dataType; // temporary while below is commented-out + // TODO: uncomment when above method not returning null +// ghDataTypeDB = applicator.resolve(dataType); + } + + public String getName() { + return ((AbstractMemberMsType) msType).getName(); + } + + public BigInteger getOffset() { + return ((AbstractMemberMsType) msType).getOffset(); + } + + public ClassFieldMsAttributes getAttribute() { + return ((AbstractMemberMsType) msType).getAttribute(); + } + + public AbstractMsTypeApplier getFieldTypeApplier() { + return applicator.getTypeApplier(((AbstractMemberMsType) msType).getFieldTypeRecordNumber()); + } + + private DataType applyMemberMsType(AbstractMemberMsType type) { + +// String memberName = type.getName(); +// BigInteger memberOffset = type.getOffset(); +// ClassFieldMsAttributes memberAttributes = type.getAttribute(); +// int fieldTypeIndex = type.getFieldTypeRecordIndex(); +// +// AbstractMsTypeApplier fieldTypeApplier = applicator.getTypeApplier(fieldTypeIndex); +// +// DataType fieldDataType = fieldTypeApplier.getDataType(); +// +//// DataType fieldDataType = getConvertedDataType(applicator, fieldTypeIndex); + + return null; + + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java new file mode 100644 index 0000000000..3d63599f1c --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java @@ -0,0 +1,136 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractModifierMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractModifierMsType} types. + */ +//public class ModifierTypeApplier extends AbstractMsTypeApplier { +public class ModifierTypeApplier extends AbstractMsTypeApplier { + + private boolean isDeferred = false; + + private AbstractMsTypeApplier modifiedTypeApplier = null; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractModifierMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + ModifierTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for modifier type applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractModifierMsType} to processes. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public ModifierTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + //============================================================================================== + public void setDeferred() { + isDeferred = true; + } + + @Override + public boolean isDeferred() { + return isDeferred; + } + + @Override + void deferredApply() throws PdbException, CancelledException { + // Do nothing. Already applied. Just needs late resolve + } + + //============================================================================================== + @Override + public BigInteger getSize() { + if (modifiedTypeApplier == null) { + return BigInteger.ZERO; + } + return modifiedTypeApplier.getSize(); + } + + @Override + public void apply() throws PdbException, CancelledException { +// dataType = applyModifierMsType((AbstractModifierMsType) msType); + applyOrDeferForDependencies(); + } + + private void applyOrDeferForDependencies() { + AbstractModifierMsType type = (AbstractModifierMsType) msType; + applyModifierMsType(type); + AbstractMsTypeApplier modifiedApplier = + applicator.getTypeApplier(type.getModifiedRecordNumber()); + if (modifiedApplier.isDeferred()) { + applicator.addApplierDependency(this, modifiedApplier); + setDeferred(); + } + else { +// applyModifierMsType(type); +// defer(false); + } + } + + @Override + public DataType getDataType() { + return modifiedTypeApplier.getDataType(); + } + + private DataType applyModifierMsType(AbstractModifierMsType type) { + modifiedTypeApplier = applicator.getTypeApplier(type.getModifiedRecordNumber()); + + return modifiedTypeApplier.getDataType(); + } + +// ghDataTypeDB = applicator.resolve(dataType); + +// boolean underlyingIsCycleBreakable() { +// // TODO: need to deal with InterfaceTypeApplier (will it be incorporated into +// // CompostieTypeapplier?) Is it in this list of places to break (i.e., can it contain)? +// return (modifiedTypeApplier != null && +// (modifiedTypeApplier instanceof CompositeTypeApplier || +// modifiedTypeApplier instanceof EnumTypeApplier)); +// } + + @Override + DataType getCycleBreakType() { + // hope to eliminate the null check if/when modifierTypeApplier is created at time of + // construction + if (modifiedTypeApplier == null) { + return null; + } + return modifiedTypeApplier.getCycleBreakType(); + } + + public AbstractMsTypeApplier getModifiedTypeApplier() { + return modifiedTypeApplier; + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java new file mode 100644 index 0000000000..6e57214090 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java @@ -0,0 +1,169 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +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.*; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractNestedTypeMsType} and {@link AbstractNestedTypeExtMsType} types. + */ +public class NestedTypeApplier extends AbstractMsTypeApplier { + private AbstractMsTypeApplier nestedTypeDefinitionApplier = null; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractNestedTypeMsType) && + !(type instanceof AbstractNestedTypeExtMsType)) { + throw new IllegalArgumentException("PDB Incorrectly applying " + + type.getClass().getSimpleName() + " to " + NestedTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for nested type applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractNestedTypeMsType} or {@link AbstractNestedTypeExtMsType} to + * process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public NestedTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + if (nestedTypeDefinitionApplier == null) { + return BigInteger.ZERO; + } + return nestedTypeDefinitionApplier.getSize(); + } + + /** + * Returns the name of this nested type. + * @return Name of the nested type. + */ + public String getTypeName() { + if (nestedTypeDefinitionApplier == null) { + return ""; + } + return nestedTypeDefinitionApplier.getMsType().getName(); + } + + /** + * Returns the nested (member?) name for this nested type. + * @return (Member?) Name for the nested type. + */ + public String getMemberName() { + if (nestedTypeDefinitionApplier == null) { + return ""; + } + if (msType instanceof AbstractNestedTypeMsType) { + return ((AbstractNestedTypeMsType) msType).getName(); + } + return ((AbstractNestedTypeExtMsType) msType).getName(); + } + + AbstractMsTypeApplier getNestedTypeDefinitionApplier() { + return applicator.getTypeApplier(getNestedTypeDefinitionRecordNumber()); + } + + RecordNumber getNestedTypeDefinitionRecordNumber() { + if (msType instanceof AbstractNestedTypeMsType) { + return ((AbstractNestedTypeMsType) msType).getNestedTypeDefinitionRecordNumber(); + } + return ((AbstractNestedTypeExtMsType) msType).getNestedTypeDefinitionRecordNumber(); + } + + /** + * Indicates if there are attributes. Returns false if not "applied" yet. + * @return [@code true} if there are attributes. + */ + public boolean hasAttributes() { + if (nestedTypeDefinitionApplier == null) { + return false; + } + if (nestedTypeDefinitionApplier.getMsType() instanceof AbstractNestedTypeMsType) { + return false; + } + return true; + } + + /** + * Returns the attributes if they exist. + * @return the attributes or null if they do not exist. + */ + public ClassFieldMsAttributes getAttributes() { + AbstractMsType type = nestedTypeDefinitionApplier.getMsType(); + if (type instanceof AbstractNestedTypeExtMsType) { + return ((AbstractNestedTypeExtMsType) type).getClassFieldAttributes(); + } + return null; + } + + @Override + public void apply() throws PdbException, CancelledException { + if (msType instanceof AbstractNestedTypeMsType) { + dataType = applyNestedTypeMsType((AbstractNestedTypeMsType) msType); + } + else { + dataType = applyNestedTypeExtMsType((AbstractNestedTypeExtMsType) msType); + } + } + + private DataType applyNestedTypeMsType(AbstractNestedTypeMsType type) { + nestedTypeDefinitionApplier = applicator.getTypeApplier(type.getNestedTypeDefinitionRecordNumber()); + return nestedTypeDefinitionApplier.getDataType(); + } + + private DataType applyNestedTypeExtMsType(AbstractNestedTypeExtMsType type) { + nestedTypeDefinitionApplier = applicator.getTypeApplier(type.getNestedTypeDefinitionRecordNumber()); + return nestedTypeDefinitionApplier.getDataType(); + } + +// ghDataTypeDB = applicator.resolve(dataType); + +// boolean underlyingIsCycleBreakable() { +// // TODO: need to deal with InterfaceTypeApplier (will it be incorporated into +// // CompostieTypeapplier?) Is it in this list of places to break (i.e., can it contain)? +// return (modifiedTypeApplier != null && +// (modifiedTypeApplier instanceof CompositeTypeApplier || +// modifiedTypeApplier instanceof EnumTypeApplier)); +// } + + @Override + DataType getCycleBreakType() { + // hope to eliminate the null check if/when modifierTypeApplier is created at time of + // construction + //TODO: look into this + return dataType; +// if (modifiedTypeApplier == null) { +// return null; +// } +// return modifiedTypeApplier.getCycleBreakType(applicator); + } + + public AbstractMsTypeApplier getNestedTypeApplier() { + return nestedTypeDefinitionApplier; + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java new file mode 100644 index 0000000000..1a4c0aee6b --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java @@ -0,0 +1,45 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; + +/** + * A dummy {@link AbstractMsSymbolApplier}, which, at a minimum, reads the symbol from the + * {@link SymbolGroup}, allowing proper sequencing of other symbols within the + * {@link SymbolGroup}. + */ +public class NoSymbolApplier extends AbstractMsSymbolApplier { + + AbstractMsSymbol symbol; + + public NoSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + symbol = iter.next(); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing. + } + + @Override + public void apply() { + // Do nothing. + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java new file mode 100644 index 0000000000..0aea6bc6d9 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java @@ -0,0 +1,50 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; + +/** + * Used for creating a wrapper for when there is not associated type to the PDB type (or if we + * have not yet created the association). + */ +public class NoTypeApplier extends AbstractMsTypeApplier { + + /** + * Constructor for nested type applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public NoTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, msType); + } + + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + + @Override + public void apply() { + // Do nothing (maybe should log something... not sure) + // applicator.getLog().appendMsg(""); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java new file mode 100644 index 0000000000..0137e99b14 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java @@ -0,0 +1,22 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +//---------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------- +enum OoComponentLayoutMode { + UNKNOWN, MEMBERS_ONLY, BASIC, SIMPLE, COMPLEX +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java new file mode 100644 index 0000000000..e23bab1615 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -0,0 +1,406 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.*; + +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.util.exception.CancelledException; + +/** + * Manages Address/Section/Segment-related PDB items. + * Has method for providing real addresses. + */ +public class PdbAddressManager { + + private static final Address badAddress = Address.NO_ADDRESS; // using NO_ADDRESS as a marker + + //============================================================================================== + private Map realAddressesBySection; + private List memoryGroupRefinement; + private List memorySectionRefinement; + private List allSegmentsInfo; + private Map remapAddressByAddress; + + private PdbApplicator applicator; + private Address imageBase; + + //============================================================================================== + // API + //============================================================================================== + /** + * Manager + * @param applicator {@link PdbApplicator} for which this class is working. + * @param imageBase Address from which all other addresses are based. + * @throws PdbException If Program is null; + */ + PdbAddressManager(PdbApplicator applicator, Address imageBase) throws PdbException { + Objects.requireNonNull(applicator, "applicator may not be null"); + Objects.requireNonNull(imageBase, "imageBase may not be null"); + this.applicator = applicator; + this.imageBase = imageBase; + realAddressesBySection = new HashMap<>(); + memoryGroupRefinement = new ArrayList<>(); + memorySectionRefinement = new ArrayList<>(); + allSegmentsInfo = new ArrayList<>(); + remapAddressByAddress = new HashMap<>(); + + determineMemoryBlocks(); + } + + /** + * Returns the Address for the given section and offset. + * @param symbol The {@link AddressMsSymbol} + * @return The Address + */ + // Returns an address using the section and offset. + Address reladdr(AddressMsSymbol symbol) { + return reladdr(symbol.getSegment(), symbol.getOffset()); + } + + /** + * Returns the Address for the given section and offset. Will attempt to map the address + * to a new address if the {@link PdbApplicatorOptions} + * @param segment The segment + * @param offset The offset + * @return The Address, which can be {@code Address.NO_ADDRESS} if it was the original address. + */ + // Returns an address using the section and offset. + Address reladdr(int segment, long offset) { + if (segment < 0 || segment > allSegmentsInfo.size()) { + return Address.NO_ADDRESS; + } + else if (segment == allSegmentsInfo.size()) { + // Was getting issues of _IMAGE_DOSHEADER showing up with a segemnt index one + // beyond the end. + segment = 0; // The anomaly of last segment meaning the first. + } + SegmentInfo segmentInfo = allSegmentsInfo.get(segment); + if (offset >= segmentInfo.getLength()) { + return Address.NO_ADDRESS; + } + return segmentInfo.getStartAddress().add(offset); + } + + /** + * Write the mapped address for a query address, where where the mapping is + * derived by using a the address of a PDB symbol as the key and finding the address of + * a symbol in the program of the same "unique" name. This is accomplished using public + * mangled symbols. If the program symbol came from the PDB, then it maps to itself. + * @param address the query address + * @param remapAddress the mapped address + */ + void putRemapAddressByAddress(Address address, Address remapAddress) { + Address lookup = remapAddressByAddress.get(address); + if (lookup == null) { + remapAddressByAddress.put(address, remapAddress); + } + else if (!lookup.equals(remapAddress) && lookup != badAddress) { + applicator.appendLogMsg("Trying to map a mapped address to a new address... key: " + + address + ", currentMap: " + lookup + ", newMap: " + remapAddress); + remapAddressByAddress.put(address, badAddress); + } + } + + /** + * Returns the Address of an existing symbol for the query address, where the mapping is + * derived by using a the address of a PDB symbol as the key and finding the address of + * a symbol in the program of the same "unique" name. This is accomplished using public + * mangled symbols. If the program symbol came from the PDB, then it maps to itself. + * @param address the query address + * @return the remapAddress + */ + Address getRemapAddressByAddress(Address address) { + if (!Address.NO_ADDRESS.equals(address) && + applicator.getPdbApplicatorOptions().remapAddressUsingExistingPublicMangledSymbols()) { + return remapAddressByAddress.getOrDefault(address, address); + } + return address; + } + + /** + * Method for callee to set the real address for the section. + * @param sectionNum the section number + * @param realAddress The Address + */ + void putRealAddressesBySection(int sectionNum, long realAddress) { + realAddressesBySection.put(sectionNum, realAddress); + } + + /** + * Method for callee to add a Memory Group symbol to the Memory Group list. + * @param symbol the symbol. + */ + void addMemoryGroupRefinement(PeCoffGroupMsSymbol symbol) { + memoryGroupRefinement.add(symbol); + } + + /** + * Method for callee to add a Memory Section symbol to the Memory Section list. + * @param symbol the symbol. + */ + void addMemorySectionRefinement(PeCoffSectionMsSymbol symbol) { + memorySectionRefinement.add(symbol); + } + + /** + * Dumps memory section refinement to log. + * @throws CancelledException Upon user cancellation + */ + void logReport() throws CancelledException { + logMemorySectionRefinement(); + logMemoryGroupRefinement(); + } + + //============================================================================================== + //============================================================================================== + private class SegmentInfo { + private Address start; + private long length; + + SegmentInfo(Address startIn, long lengthIn) { + start = startIn; + length = lengthIn; + } + + public Address getStartAddress() { + return start; + } + + public long getLength() { + return length; + } + } + + private void determineMemoryBlocks() { + // Set section/segment 0 to image base. (should be what is header), but what is its size? + // TODO... made up size for now... is there something else? We could + long segmentZeroLength = 0x7fffffff; + allSegmentsInfo.add(new SegmentInfo(imageBase, segmentZeroLength)); + AbstractDatabaseInterface dbi = applicator.getPdb().getDatabaseInterface(); + if (dbi instanceof DatabaseInterfaceNew) { + DebugData debugData = ((DatabaseInterfaceNew) dbi).getDebugData(); + List imageSectionHeaders = debugData.getImageSectionHeaders(); + for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) { + long virtualAddress = imageSectionHeader.getVirtualAddress(); + // TODO: not sure when unionPAVS is physical address vs. virtual size. Perhaps + // it keys off whether virtualAddress is not some special value such as + // 0x00000000 or 0xffffffff. + long size = imageSectionHeader.getUnionPAVS(); + allSegmentsInfo.add(new SegmentInfo(imageBase.add(virtualAddress), size)); + } + } + // else instance of DatabaseInterface; TODO: what can we do here? + + // TODO: what should we do with these? Not doing anything at the moment + AbstractPdb pdb = applicator.getPdb(); + List segmentMapList = pdb.getDatabaseInterface().getSegmentMapList(); + for (SegmentMapDescription segmentMapDescription : segmentMapList) { + segmentMapDescription.getSegmentOffset(); + segmentMapDescription.getLength(); + } + } + + //============================================================================================== + //============================================================================================== + /** + * Dumps memory section refinement to log. + * @throws CancelledException Upon user cancellation + */ + private void logMemorySectionRefinement() throws CancelledException { + // Offer memory refinement (could have done it as symbols came in; we just collected + // them and are dealing with them now... ultimately not sure if we will want to use + // this refinement. + // Look at SectionFlags.java for characteristics information. + // TODO: should we perform refinement of program memory blocks? + PdbLog.message("\nMemorySectionRefinement"); + for (PeCoffSectionMsSymbol sym : memorySectionRefinement) { + applicator.checkCanceled(); + String name = sym.getName(); + int section = sym.getSectionNumber(); + int relativeVirtualAddress = sym.getRva(); + int align = sym.getAlign(); + int length = sym.getLength(); + int characteristics = sym.getCharacteristics(); + Address address = imageBase.add(relativeVirtualAddress); + PdbLog.message(String.format( + "%s: [%04X(%08X)](%s) Align:%02X, Len:%08X, Characteristics:%08X", name, section, + relativeVirtualAddress, address.toString(), align, length, characteristics)); + } + } + + /** + * Dumps group section refinement to log. + * @throws CancelledException Upon user cancellation + */ + private void logMemoryGroupRefinement() throws CancelledException { + // Note that I've seen example where PE header has two .data sections (one for initialized + // and the other for uninitialized, 0x2800 and 0x250 in size, respectively), but the PDB + // information shows two sections totally 0x2a50 size, but sizes of 0x2750 and 0x0300, + // the latter of which is marked as ".bss" in name. This suggests that the PE header is + // more focused on what needs initialized, which includes 0x2750 of .data and 0xa0 of + // .bss, the remaining 0x250 of .bss is not initialized. These .bss portion that needs + // initialized is lumped with the .data section in the PE header... only my opinion... + // however, this leaves us with question of what we do here. Do believe the PDB over + // the PE? (See vcamp110.arm.pdb and (arm) vcamp110.dll). + // TODO: should we perform refinement of program memory blocks? + PdbLog.message("\nMemoryGroupRefinement"); + for (PeCoffGroupMsSymbol sym : memoryGroupRefinement) { + applicator.checkCanceled(); + String name = sym.getName(); + int segment = sym.getSegment(); + long offset = sym.getOffset(); + int length = sym.getLength(); + int characteristics = sym.getCharacteristics(); + Address address = reladdr(sym); + PdbLog.message(String.format("%s: [%04X:%08X](%s) Len:%08X, Characteristics:%08X", name, + segment, offset, address.toString(), length, characteristics)); + } + } + + //============================================================================================== + //============================================================================================== + // TODO: This is not complete... It was a research thought, which might get looked at in the + // future. + /** + * Tries to align section/segment information of the PDB in {@link SegmentMapDescription} from + * the {@link AbstractDatabaseInterface} header substream with the memory blocks of the + * {@link Program}. Initializes the lookup table to be used for processing the PDB. + *

    + * We have seen cases where blocks of the program are combined into a single block representing + * one segment in the PDB. + *

    + * The PDB's {@link SegmentMapDescription} is not always fully populated, though the length + * field seems to be consistently available. + * @throws PdbException if there was a problem processing the data. + */ + @SuppressWarnings("unused") // for method not being called and local variables ununsed. + private void reconcileMemoryBlocks() throws PdbException { +// ImageSectionHeader imageSectionHeader = +// pdb.getDatabaseInterface().getDebugData().getImageSectionHeader(); + + AbstractPdb pdb = applicator.getPdb(); + Program program = applicator.getProgram(); + if (program == null) { + return; + } + + Memory mem = program.getMemory(); + MemoryBlock[] blocks = mem.getBlocks(); + List segmentMapList = pdb.getDatabaseInterface().getSegmentMapList(); + /** + * Program has additional "Headers" block set up by the {@link PeLoader}. + */ + int progIndexLimit = blocks.length; + int pdbIndexLimit = segmentMapList.size(); + int progIndex = 1; + int pdbIndex = 0; + + // Set section/segment 0 to image base. (should be what is header) + + List myAllSegmentsInfo = new ArrayList<>(); // Contender set of segment info (vs what is in class) + + allSegmentsInfo.add(new SegmentInfo(blocks[0].getStart(), blocks[0].getSize())); + // Try to match memory in order, grouping as needed. + long blockAccum = 0; + while (progIndex < progIndexLimit && pdbIndex < pdbIndexLimit) { + SegmentMapDescription segmentDescription = segmentMapList.get(pdbIndex); + Address blockStart = blocks[progIndex].getStart(); + while (blockAccum < segmentDescription.getLength() && progIndex < progIndexLimit) { +// progIndex++; + Address addr1 = blocks[progIndex].getStart(); + Address addr2 = blockStart.add(blockAccum); + if (!blocks[progIndex].getStart().equals(blockStart.add(blockAccum))) { + // Problem... blocks are not adjacent... TODO: how do we reconcile? + throw new PdbException("Memory block reconciliation failure"); + } + blockAccum += blocks[progIndex].getSize(); + if (blockAccum == segmentDescription.getLength()) { + myAllSegmentsInfo.add(new SegmentInfo(blockStart, blockAccum)); + progIndex++; + pdbIndex++; + blockAccum = 0; + break; + } + else if (blockAccum > segmentDescription.getLength()) { + // Problem... TODO: how do we reconcile? + throw new PdbException( + "Memory block reconciliation failure--needs reverse aggregation"); + } + progIndex++; + } + } + if (pdbIndex == pdbIndexLimit - 1 && + segmentMapList.get(pdbIndex).getLength() == 0xffffffffL) { + pdbIndex++; + } + if (progIndex != progIndexLimit || pdbIndex != pdbIndexLimit) { + // Problem... TODO: didn't both end iterations together + throw new PdbException("Memory block reconciliation failure--remaining data"); + } + } + + //============================================================================================== + // TODO: This is not complete... It was a research thought, which might get looked at in the + // future. + @SuppressWarnings("unused") // for method not being called. + private boolean garnerSectionSegmentInformation() throws PdbException { + AbstractPdb pdb = applicator.getPdb(); + if (pdb.getDatabaseInterface() == null) { + return false; + } + +// ImageSectionHeader imageSectionHeader = +// pdb.getDatabaseInterface().getDebugData().getImageSectionHeader(); + + int num = 1; + for (AbstractModuleInformation module : pdb.getDatabaseInterface().getModuleInformationList()) { + if ("* Linker *".equals(module.getModuleName())) { + List linkerSymbolList = + applicator.getSymbolGroupForModule(num).getSymbols(); + for (AbstractMsSymbol symbol : linkerSymbolList) { + if (symbol instanceof PeCoffSectionMsSymbol) { + PeCoffSectionMsSymbol section = (PeCoffSectionMsSymbol) symbol; + int sectionNum = section.getSectionNumber(); + long realAddress = section.getRva(); + section.getLength(); + section.getCharacteristics(); + section.getAlign(); + section.getName(); + realAddressesBySection.put(sectionNum, realAddress); + } + if (symbol instanceof PeCoffGroupMsSymbol) { + PeCoffGroupMsSymbol group = (PeCoffGroupMsSymbol) symbol; + group.getName(); + group.getSegment(); + group.getLength(); + group.getOffset(); + group.getCharacteristics(); + } + } + return true; + } + num++; + } + return false; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java new file mode 100644 index 0000000000..81151949fc --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -0,0 +1,1328 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; +import java.util.*; + +import ghidra.app.cmd.label.SetLabelPrimaryCmd; +import ghidra.app.util.NamespaceUtils; +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.importer.MessageLog; +import ghidra.app.util.pdb.PdbCategoryUtils; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.graph.*; +import ghidra.graph.algo.GraphNavigator; +import ghidra.graph.jung.JungDirectedGraph; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.*; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.InvalidInputException; +import ghidra.util.task.CancelOnlyWrappingTaskMonitor; +import ghidra.util.task.TaskMonitor; + +public class PdbApplicator { + + /** + * Returns integer value of BigInteger or Integer.MAX_VALUE if does not fit. + * @param myApplicator PdbApplicator for which we are working. + * @param big BigInteger value to convert. + * @return the integer value. + */ + public static long bigIntegerToLong(PdbApplicator myApplicator, BigInteger big) { + try { + return big.longValueExact(); + } + catch (ArithmeticException e) { + String msg = "BigInteger value greater than max Long: " + big; + PdbLog.message(msg); + myApplicator.appendLogMsg(msg); + return Long.MAX_VALUE; + } + } + + /** + * Returns integer value of BigInteger or Integer.MAX_VALUE if does not fit. + * @param myApplicator PdbApplicator for which we are working. + * @param big BigInteger value to convert. + * @return the integer value. + */ + public static int bigIntegerToInt(PdbApplicator myApplicator, BigInteger big) { + try { + return big.intValueExact(); + } + catch (ArithmeticException e) { + String msg = "BigInteger value greater than max Integer: " + big; + PdbLog.message(msg); + myApplicator.appendLogMsg(msg); + return Integer.MAX_VALUE; + } + } + + //============================================================================================== + private String pdbFilename; + private AbstractPdb pdb; + + private PdbApplicatorMetrics pdbApplicatorMetrics; + + //============================================================================================== + private Program program; + + private PdbApplicatorOptions applicatorOptions; + private MessageLog log; + private TaskMonitor monitor; + private CancelOnlyWrappingTaskMonitor cancelOnlyWrappingMonitor; + + //============================================================================================== + private Address imageBase; + private DataTypeManager dataTypeManager; + private PdbAddressManager pdbAddressManager; + private List symbolGroups; + + //============================================================================================== + // If we have symbols and memory with VBTs in them, then a better VbtManager is created. + VbtManager vbtManager; + PdbRegisterNameToProgramRegisterMapper registerNameToRegisterMapper; + + //============================================================================================== + private int resolveCount; + private PdbCategoryUtils categoryUtils; + private PdbPrimitiveTypeApplicator pdbPrimitiveTypeApplicator; + private TypeApplierParser typeApplierParser; + private ComplexTypeApplierMapper complexApplierMapper; + private JungDirectedGraph> applierDependencyGraph; + /** + * This namespace map documents as follows: + *

    +	 *   false = simple namespace
    +	 *   true = class namespace
    +	 *  
    + */ + private Map isClassByNamespace; + + //============================================================================================== + private SymbolApplierParser symbolApplierParser; + + // Investigating... might change from String to AbstractSymbolApplier. + private Map> labelsByAddress; + // Investigations into source/line info + private Map> recordNumbersByFileName; + private Map> recordNumbersByModuleNumber; + + //============================================================================================== + // TODO: eventually put access methods on AbstractPdb to get filename from it (deep down). + public PdbApplicator(String pdbFilename, AbstractPdb pdb) { + Objects.requireNonNull(pdbFilename, "pdbFilename cannot be null"); + Objects.requireNonNull(pdb, "pdb cannot be null"); + this.pdbFilename = pdbFilename; + this.pdb = pdb; + } + + //============================================================================================== + //============================================================================================== + /** + * Applies the PDB to the {@link Program} or {@link DataTypeManager}. Either, but not both, + * can be null. + * @param programParam The {@link Program} to which to apply the PDB. Can be null in certain + * circumstances. + * @param dataTypeManagerParam The {@link DataTypeManager} to which to apply data types. Can be + * null in certain circumstances. + * @param imageBaseParam Address bases from which symbol addresses are based. If null, uses + * the image base of the program (both cannot be null). + * @param applicatorOptionsParam {@link PdbApplicatorOptions} used for applying the PDB. + * @param monitorParam TaskMonitor uses for watching progress and cancellation notices. + * @param logParam The MessageLog to which to output messages. + * @throws PdbException if there was a problem processing the data. + * @throws CancelledException Upon user cancellation + */ + public void applyTo(Program programParam, DataTypeManager dataTypeManagerParam, + Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, + TaskMonitor monitorParam, MessageLog logParam) throws PdbException, CancelledException { + + initializeApplyTo(programParam, dataTypeManagerParam, imageBaseParam, + applicatorOptionsParam, monitorParam, logParam); + + if (!applicatorOptions.applyPublicSymbolsOnly()) { + processTypes(); + } + + if (program != null && !applicatorOptions.applyDataTypesOnly()) { + if (applicatorOptions.applyPublicSymbolsOnly()) { + processPublicSymbols(); + } + else { + processSymbols(); + } + } + + pdbAddressManager.logReport(); + + String applicatorMetrics = pdbApplicatorMetrics.getPostProcessingReport(); + Msg.info(this, applicatorMetrics); + PdbLog.message(applicatorMetrics); + Msg.info(this, "PDB Terminated Normally"); + } + + //============================================================================================== + private void processTypes() throws CancelledException, PdbException { + setMonitorMessage("PDB: Applying to DTM " + dataTypeManager.getName() + "..."); + + PdbResearch.initCheckBreak(); // for developmental debug + + resolveCount = 0; + +// PdbResearch.childWalk(this, monitor); + +// PdbResearch.studyDataTypeConflicts(this, monitor); +// PdbResearch.studyCompositeFwdRefDef(pdb, monitor); +// PdbResearch.study1(pdb, monitor); + + complexApplierMapper.mapAppliers(monitor); + + processSequentially(); + +// dumpSourceFileRecordNumbers(); + +// PdbResearch.developerDebugOrder(this, monitor); + + processDeferred(); + + resolveSequentially(); + + Msg.info(this, "resolveCount: " + resolveCount); + + // Currently, defining classes needs to have a program. When this is no longer true, + // then this call can be performed with the data types only work. + if (program != null) { + defineClasses(); + } + + // Process typedefs, which are in the symbols. + processGlobalTypdefSymbols(); + } + + //============================================================================================== + private void processSymbols() throws CancelledException, PdbException { +// PdbResearch.studyAggregateSymbols(this, monitor); + + // TODO: not sure if the following will be relevant here, elsewhere, or nowhere. +// if (!pdbAddressManager.garnerSectionSegmentInformation()) { +// return; +// } + + // Doing globals before publics, as publics are those that can have mangled names. By + // applying the non-mangled symbols first, we can get full type information from the + // underlying type. Then we can apply the mangled symbols and demangle them without + // affecting our ability to lay down PDB type information--any type information from + // the mangled symbols can happen afterward. + processGlobalSymbolsNoTypedefs(); + processPublicSymbols(); + + // Seems that we shouldn't do the following, as it could be a buffer of invalid symbols + // that hadn't been gone through for garbage collection of sorts. + //processNonPublicOrGlobalSymbols(); + + // Seems that we shouldn't do the following, as the ones that are needed seem to be + // referenced from a global symbol using a ReferencedSymbol. If we process the module + // symbols, as below, then collisions can start to appear at addresses. This has + // happened to me when I forgot to clear the results from a previous build, in which + // case I could find symbols referring to a location within the old build and within + // the latest build at the particular address corresponding to its location within that + // build. So a module might have symbols that had not been garbage-collected. + processModuleSymbols(); + + // These are good to process (one particular module for the linker). +// processLinkerSymbols(); + + // Get additional thunks (that old pdb analyzer got). + processThunkSymbolsFromNonLinkerModules(); + + //processAllSymbols(); + +// dumpLabels(); + } + + //============================================================================================== + //============================================================================================== + private void initializeApplyTo(Program programParam, DataTypeManager dataTypeManagerParam, + Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, + TaskMonitor monitorParam, MessageLog logParam) throws PdbException, CancelledException { + + validateAndSetParameters(programParam, dataTypeManagerParam, imageBaseParam, + applicatorOptionsParam, monitorParam, logParam); + + cancelOnlyWrappingMonitor = new CancelOnlyWrappingTaskMonitor(monitor); + pdbApplicatorMetrics = new PdbApplicatorMetrics(); + + pdbAddressManager = new PdbAddressManager(this, imageBase); + symbolGroups = createSymbolGroups(); + + categoryUtils = setPdbCatogoryUtils(pdbFilename); + pdbPrimitiveTypeApplicator = new PdbPrimitiveTypeApplicator(dataTypeManager); + typeApplierParser = new TypeApplierParser(this); + complexApplierMapper = new ComplexTypeApplierMapper(this); + applierDependencyGraph = new JungDirectedGraph<>(); + isClassByNamespace = new TreeMap<>(); + if (program != null) { + // Currently, this must happen after symbolGroups are created. + PdbVbtManager pdbVbtManager = new PdbVbtManager(this); + //pdbVbtManager.CreateVirtualBaseTables(); // Depends on symbolGroups + vbtManager = pdbVbtManager; + registerNameToRegisterMapper = new PdbRegisterNameToProgramRegisterMapper(program); + } + else { + vbtManager = new VbtManager(getDataTypeManager()); + } + + symbolApplierParser = new SymbolApplierParser(this); + + // Investigations + labelsByAddress = new HashMap<>(); + // Investigations into source/line info + recordNumbersByFileName = new HashMap<>(); + recordNumbersByModuleNumber = new HashMap<>(); + } + + private void validateAndSetParameters(Program programParam, + DataTypeManager dataTypeManagerParam, Address imageBaseParam, + PdbApplicatorOptions applicatorOptionsParam, TaskMonitor monitorParam, + MessageLog logParam) throws PdbException { + if (programParam == null) { + if (dataTypeManagerParam == null) { + throw new PdbException( + "programParam and dataTypeManagerParam may not both be null."); + } + if (imageBaseParam == null) { + throw new PdbException("programParam and imageBaseParam may not both be null."); + } + } + applicatorOptions = + (applicatorOptionsParam != null) ? applicatorOptionsParam : new PdbApplicatorOptions(); + if (applicatorOptions.applyDataTypesOnly() && applicatorOptions.applyPublicSymbolsOnly()) { + throw new PdbException("Cannot have both: applyDataTypesOnly, applyPublicSymbolOnly."); + } + monitor = (monitorParam != null) ? monitorParam : TaskMonitor.DUMMY; + log = (logParam != null) ? logParam : new MessageLog(); + program = programParam; + dataTypeManager = + (dataTypeManagerParam != null) ? dataTypeManagerParam : program.getDataTypeManager(); + imageBase = (imageBaseParam != null) ? imageBaseParam : program.getImageBase(); + } + + private List createSymbolGroups() throws CancelledException, PdbException { + List mySymbolGroups = new ArrayList<>(); + int num = pdb.getDatabaseInterface().getNumModules(); + // moduleNumber zero is our global/public group. + for (int moduleNumber = 0; moduleNumber <= num; moduleNumber++) { + monitor.checkCanceled(); + Map symbols = + pdb.getDatabaseInterface().getModuleSymbolsByOffset(moduleNumber); + SymbolGroup symbolGroup = new SymbolGroup(symbols, moduleNumber); + mySymbolGroups.add(symbolGroup); + } + return mySymbolGroups; + } + + //============================================================================================== + // Basic utility methods. + //============================================================================================== + /** + * Returns the {@link PdbApplicatorOptions} for this PdbApplicator. + * @return the {@link PdbApplicatorOptions} for this PdbApplicator. + */ + PdbApplicatorOptions getPdbApplicatorOptions() { + return applicatorOptions; + } + + /** + * Check to see if this monitor has been canceled + * @throws CancelledException if monitor has been cancelled + */ + void checkCanceled() throws CancelledException { + monitor.checkCanceled(); + } + + /** + * Sets the message displayed on the task monitor + * @param message the message to display + */ + void setMonitorMessage(String message) { + monitor.setMessage(message); + } + + /** + * Sets the message displayed on the task monitor + * @param message the message to display + */ + void appendLogMsg(String message) { + log.appendMsg(message); + } + + /** + * Returns the {@link TaskMonitor} to available for this analyzer. + * @return the monitor. + */ + TaskMonitor getMonitor() { + return monitor; + } + + /** + * Returns the {@link CancelOnlyWrappingTaskMonitor} to available for this analyzer. + * @return the monitor. + */ + TaskMonitor getCancelOnlyWrappingMonitor() { + return cancelOnlyWrappingMonitor; + } + + /** + * Returns the {@link PdbApplicatorMetrics} being used for this applicator. + * @return the {@link PdbApplicatorMetrics}. + */ + PdbApplicatorMetrics getPdbApplicatorMetrics() { + return pdbApplicatorMetrics; + } + + /** + * Returns the {@link AbstractPdb} being analyzed. + * @return {@link AbstractPdb} being analyzed. + */ + AbstractPdb getPdb() { + return pdb; + } + + /** + * Returns the {@link Program} for which this analyzer is working. + * @return {@link Program} for which this analyzer is working. + */ + Program getProgram() { + return program; + } + + //============================================================================================== + // Information for a putative PdbTypeApplicator: + + /** + * Returns the {@link DataTypeManager} associated with this analyzer. + * @return DataTypeManager which this analyzer is using. + */ + DataTypeManager getDataTypeManager() { + return dataTypeManager; + } + + // for PdbTypeApplicator (new) + DataOrganization getDataOrganization() { + return dataTypeManager.getDataOrganization(); + } + + PdbPrimitiveTypeApplicator getPdbPrimitiveTypeApplicator() { + return pdbPrimitiveTypeApplicator; + } + + //============================================================================================== + // CategoryPath-related methods. + //============================================================================================== + /** + * Get the {@link CategoryPath} associated with the {@link SymbolPath} specified, rooting + * it either at the PDB Category. + * @param symbolPath Symbol path to be used to create the CategoryPath. Null represents global + * namespace. + * @return {@link CategoryPath} created for the input. + */ + CategoryPath getCategory(SymbolPath symbolPath) { + return categoryUtils.getCategory(symbolPath); + } + + /** + * Returns the {@link CategoryPath} for a typedef with with the give {@link SymbolPath} and + * module number; 1 <= moduleNumber <= {@link AbstractDatabaseInterface#getNumModules()}, + * except that modeleNumber of 0 represents publics/globals. + * @param moduleNumber module number + * @param symbolPath SymbolPath of the symbol + * @return the CategoryPath + */ + CategoryPath getTypedefsCategory(int moduleNumber, SymbolPath symbolPath) { + return categoryUtils.getTypedefsCategory(moduleNumber, symbolPath); + } + + /** + * Returns the {@link CategoryPath} for Anonymous Functions Category for the PDB. + * @return the {@link CategoryPath} + */ + CategoryPath getAnonymousFunctionsCategory() { + return categoryUtils.getAnonymousFunctionsCategory(); + } + + /** + * Returns the {@link CategoryPath} for Anonymous Types Category for the PDB. + * @return the {@link CategoryPath} + */ + public CategoryPath getAnonymousTypesCategory() { + return categoryUtils.getAnonymousTypesCategory(); + } + + /** + * Returns the name of what should be the next Anonymous Function (based on the count of + * the number of anonymous functions) so that there is a unique name for the function. + * @return the name for the next anonymous function. + */ + String getNextAnonymousFunctionName() { + return categoryUtils.getNextAnonymousFunctionName(); + } + + /** + * Updates the count of the anonymous functions. This is a separate call from + * {@link #getNextAnonymousFunctionName()} because the count should only be updated after + * the previous anonymous function has been successfully created/stored. + */ + void incrementNextAnonymousFunctionName() { + categoryUtils.incrementNextAnonymousFunctionName(); + } + + private PdbCategoryUtils setPdbCatogoryUtils(String pdbFilename) + throws CancelledException, PdbException { + + List categoryNames = new ArrayList<>(); + int num = pdb.getDatabaseInterface().getNumModules(); + for (int index = 1; index <= num; index++) { + monitor.checkCanceled(); + String moduleName = + pdb.getDatabaseInterface().getModuleInformation(index).getModuleName(); + categoryNames.add(moduleName); + } + + int index = pdbFilename.lastIndexOf("\\"); + if (index == -1) { + index = pdbFilename.lastIndexOf("/"); + } + return new PdbCategoryUtils(pdbFilename.substring(index + 1), categoryNames); + } + + //============================================================================================== + // Applier-based-DataType-dependency-related methods. + //============================================================================================== + void addApplierDependency(AbstractMsTypeApplier depender) { + Objects.requireNonNull(depender); + applierDependencyGraph.addVertex(depender.getDependencyApplier()); + } + + void addApplierDependency(AbstractMsTypeApplier depender, AbstractMsTypeApplier dependee) { + Objects.requireNonNull(depender); + Objects.requireNonNull(dependee); + // TODO: Possibly do checks on dependee and depender types for actual creation + // of dependency--making this the one-stop-shop of this logic. Then make calls to + // this method from all possibly places. (Perhaps, for example, if depender is a + // pointer, then the logic would say "no.") + // + // Examples of where dependency should possibly be created (by not doing it, we are + // getting .conflict data types) include: + // structure or enum as a function return type or argument type. + // + applierDependencyGraph.addEdge( + new DefaultGEdge<>(depender.getDependencyApplier(), dependee.getDependencyApplier())); + } + + List getVerticesInPostOrder() { + setMonitorMessage("PDB: Determining data type dependency order..."); + return GraphAlgorithms.getVerticesInPostOrder(applierDependencyGraph, + GraphNavigator.topDownNavigator()); + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + AbstractMsTypeApplier getApplierSpec(RecordNumber recordNumber, + Class expected) throws PdbException { + return typeApplierParser.getApplierSpec(recordNumber, expected); + } + + AbstractMsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber, + Class expected) throws PdbException { + return typeApplierParser.getApplierOrNoTypeSpec(recordNumber, expected); + } + + AbstractMsTypeApplier getTypeApplier(RecordNumber recordNumber) { + return typeApplierParser.getTypeApplier(recordNumber); + } + + AbstractMsTypeApplier getTypeApplier(AbstractMsType type) { + return typeApplierParser.getTypeApplier(type); + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + public int findModuleNumberBySectionOffsetContribution(int section, long offset) + throws PdbException { + for (AbstractSectionContribution sectionContribution : pdb.getDatabaseInterface().getSectionContributionList()) { + int sectionContributionOffset = sectionContribution.getOffset(); + int maxSectionContributionOffset = + sectionContributionOffset + sectionContribution.getLength(); + if (offset >= sectionContributionOffset && offset < maxSectionContributionOffset) { + return sectionContribution.getModule(); + } + } + throw new PdbException("Module not found for section/offset"); + } + + //============================================================================================== + private void processDataTypesSequentially() throws CancelledException, PdbException { + AbstractTypeProgramInterface tpi = pdb.getTypeProgramInterface(); + int num = tpi.getTypeIndexMaxExclusive() - tpi.getTypeIndexMin(); + monitor.initialize(num); + setMonitorMessage("PDB: Processing " + num + " data type components..."); + for (int indexNumber = + tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) { + monitor.checkCanceled(); + PdbResearch.checkBreak(indexNumber); + AbstractMsTypeApplier applier = + getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); + //PdbResearch.checkBreak(indexNumber, applier); + applier.apply(); + monitor.incrementProgress(1); + } + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + // Investigations into source/line info + void putRecordNumberByFileName(RecordNumber recordNumber, String filename) { + Set recordNumbers = recordNumbersByFileName.get(filename); + if (recordNumbers == null) { + recordNumbers = new HashSet<>(); + recordNumbersByFileName.put(filename, recordNumbers); + } + recordNumbers.add(recordNumber); + } + + //============================================================================================== + void putRecordNumberByModuleNumber(RecordNumber recordNumber, int moduleNumber) { + Set recordNumbers = recordNumbersByModuleNumber.get(moduleNumber); + if (recordNumbers == null) { + recordNumbers = new HashSet<>(); + recordNumbersByModuleNumber.put(moduleNumber, recordNumbers); + } + recordNumbers.add(recordNumber); + } + + //============================================================================================== + void dumpSourceFileRecordNumbers() { + PdbLog.message("RecordNumbersByFileName"); + for (Map.Entry> entry : recordNumbersByFileName.entrySet()) { + String filename = entry.getKey(); + PdbLog.message("FileName: " + filename); + for (RecordNumber recordNumber : entry.getValue()) { + AbstractMsType msType = pdb.getTypeRecord(recordNumber); + PdbLog.message(recordNumber.toString() + "\n" + msType); + } + } + PdbLog.message("RecordNumbersByModuleNumber"); + for (Map.Entry> entry : recordNumbersByModuleNumber.entrySet()) { + int moduleNumber = entry.getKey(); + PdbLog.message("ModuleNumber: " + moduleNumber); + for (RecordNumber recordNumber : entry.getValue()) { + AbstractMsType msType = pdb.getTypeRecord(recordNumber); + PdbLog.message(recordNumber.toString() + "\n" + msType); + } + } + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + private void processItemTypesSequentially() throws CancelledException, PdbException { + AbstractTypeProgramInterface ipi = pdb.getItemProgramInterface(); + int num = ipi.getTypeIndexMaxExclusive() - ipi.getTypeIndexMin(); + monitor.initialize(num); + setMonitorMessage("PDB: Processing " + num + " item type components..."); + for (int indexNumber = ipi.getTypeIndexMin(); indexNumber < num; indexNumber++) { + monitor.checkCanceled(); + AbstractMsTypeApplier applier = + getTypeApplier(RecordNumber.itemRecordNumber(indexNumber)); + applier.apply(); + monitor.incrementProgress(1); + } + } + + //============================================================================================== + private void processSequentially() throws CancelledException, PdbException { + processDataTypesSequentially(); + processItemTypesSequentially(); + } + + //============================================================================================== + private void processDeferred() throws CancelledException, PdbException { + List verticesInPostOrder = getVerticesInPostOrder(); + monitor.initialize(verticesInPostOrder.size()); + setMonitorMessage("PDB: Processing " + verticesInPostOrder.size() + + " deferred data type dependencies..."); + for (AbstractMsTypeApplier applier : verticesInPostOrder) { + monitor.checkCanceled(); + PdbResearch.checkBreak(applier.index); + //checkBreak(applier.index, applier); + if (applier.isDeferred()) { + applier.deferredApply(); + } + monitor.incrementProgress(1); + } + } + + //============================================================================================== + private void resolveSequentially() throws CancelledException { + AbstractTypeProgramInterface tpi = pdb.getTypeProgramInterface(); + int num = tpi.getTypeIndexMaxExclusive() - tpi.getTypeIndexMin(); + monitor.initialize(num); + setMonitorMessage("PDB: Resolving " + num + " data type components..."); + Date start = new Date(); + long longStart = start.getTime(); + for (int indexNumber = + tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) { + monitor.checkCanceled(); + PdbResearch.checkBreak(indexNumber); + AbstractMsTypeApplier applier = + getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); + PdbResearch.checkBreak(indexNumber, applier); + applier.resolve(); + monitor.incrementProgress(1); + } + Date stop = new Date(); + long longStop = stop.getTime(); + long timeDiff = longStop - longStart; + Msg.info(this, "Resolve time: " + timeDiff + " mS"); + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + DataType resolve(DataType dataType) { + if ("Cr_z_internal_state".equals(dataType.getName())) { + int a = 1; + a = a + 1; + } + if ("z_stream_s".equals(dataType.getName())) { + int a = 1; + a = a + 1; + } + + DataType resolved = getDataTypeManager().resolve(dataType, + DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER); + resolveCount++; + return resolved; + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + + //============================================================================================== + // SymbolGroup-related methods. + //============================================================================================== + SymbolGroup getSymbolGroup() { + return getSymbolGroupForModule(0); + } + + SymbolGroup getSymbolGroupForModule(int moduleNumber) { + return symbolGroups.get(moduleNumber); + } + +// public AbstractMsSymbol getSymbolForModuleAndOffset(int moduleNumber, long offset) +// throws PdbException { +// return pdb.getDatabaseInterface().getSymbolForModuleAndOffsetOfRecord(moduleNumber, offset); +// } + + //============================================================================================== + // Address-related methods. + //============================================================================================== + /** + * Returns the Address for the given section and offset. + * @param symbol The {@link AddressMsSymbol} + * @return The Address + */ + Address reladdr(AddressMsSymbol symbol) { + return pdbAddressManager.reladdr(symbol); + } + + /** + * Returns the Address for the given section and offset. + * @param segment The segment + * @param offset The offset + * @return The Address + */ + Address reladdr(int segment, long offset) { + return pdbAddressManager.reladdr(segment, offset); + } + + /** + * Write the mapped address for a query address, where where the mapping is + * derived by using a the address of a PDB symbol as the key and finding the address of + * a symbol in the program of the same "unique" name. This is accomplished using public + * mangled symbols. If the program symbol came from the PDB, then it maps to itself. + * @param address the query address + * @param remapAddress the mapped address + */ + void putRemapAddressByAddress(Address address, Address remapAddress) { + pdbAddressManager.putRemapAddressByAddress(address, remapAddress); + } + + /** + * Returns the Address of an existing symbol for the query address, where the mapping is + * derived by using a the address of a PDB symbol as the key and finding the address of + * a symbol in the program of the same "unique" name. This is accomplished using public + * mangled symbols. If the program symbol came from the PDB, then it maps to itself. + * @param address the query address + * @return the remapAddress + */ + Address getRemapAddressByAddress(Address address) { + return pdbAddressManager.getRemapAddressByAddress(address); + } + + /** + * Method for callee to set the real address for the section. + * @param sectionNum the section number + * @param realAddress The Address + */ + void putRealAddressesBySection(int sectionNum, long realAddress) { + pdbAddressManager.putRealAddressesBySection(sectionNum, realAddress); + } + + /** + * Method for callee to add a Memory Group symbol to the Memory Group list. + * @param symbol the symbol. + */ + void addMemoryGroupRefinement(PeCoffGroupMsSymbol symbol) { + pdbAddressManager.addMemoryGroupRefinement(symbol); + } + + /** + * Method for callee to add a Memory Section symbol to the Memory Section list. + * @param symbol the symbol. + */ + void addMemorySectionRefinement(PeCoffSectionMsSymbol symbol) { + pdbAddressManager.addMemorySectionRefinement(symbol); + } + + //============================================================================================== + // Virtual-Base-Table-related methods. + //============================================================================================== + VbtManager getVbtManager() { + return vbtManager; + } + + //============================================================================================== + // + //============================================================================================== + Register getRegister(String pdbRegisterName) { + return registerNameToRegisterMapper.getRegister(pdbRegisterName); + } + + //============================================================================================== + //============================================================================================== + @SuppressWarnings("unused") // for method not being called. + /** + * Process all symbols. User should not then call other methods: + * {@link #processGlobalSymbols()}, (@link #processPublicSymbols()}, and + * {@link #processNonPublicOrGlobalSymbols()}. + * @throws CancelledException upon user cancellation + * @throws PdbException upon issue processing the request + */ + private void processAllSymbols() throws CancelledException, PdbException { + processMainSymbols(); + processModuleSymbols(); + } + + //============================================================================================== + @SuppressWarnings("unused") // for method not being called. + private void processMainSymbols() throws CancelledException, PdbException { + // Get a count + SymbolGroup symbolGroup = getSymbolGroup(); + int totalCount = symbolGroup.size(); + setMonitorMessage("PDB: Applying " + totalCount + " main symbol components..."); + monitor.initialize(totalCount); + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + processSymbolGroup(0, iter); + } + + //============================================================================================== + private void processModuleSymbols() throws CancelledException { + int totalCount = 0; + int num = pdb.getDatabaseInterface().getNumModules(); + for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) { + monitor.checkCanceled(); + SymbolGroup symbolGroup = getSymbolGroupForModule(moduleNumber); + totalCount += symbolGroup.size(); + } + setMonitorMessage("PDB: Applying " + totalCount + " module symbol components..."); + monitor.initialize(totalCount); + + // Process symbols list for each module + for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) { + monitor.checkCanceled(); + // Process module symbols list + SymbolGroup symbolGroup = getSymbolGroupForModule(moduleNumber); + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + processSymbolGroup(moduleNumber, iter); +// catelogSymbols(index, symbolGroup); + // do not call monitor.incrementProgress(1) here, as it is updated inside of + // processSymbolGroup. + } + } + +// private Set> moduleSymbols = new HashSet<>(); +// +// private void catelogSymbols(int moduleNumber, SymbolGroup symbolGroup) +// throws CancelledException { +// symbolGroup.initGet(); +// while (symbolGroup.hasNext()) { +// monitor.checkCanceled(); +// AbstractMsSymbol symbol = symbolGroup.peek(); +// moduleSymbols.add(symbol.getClass()); +// symbolGroup.next(); +// } +// } +// + //============================================================================================== + private void processSymbolGroup(int moduleNumber, AbstractMsSymbolIterator iter) + throws CancelledException { + iter.initGet(); + while (iter.hasNext()) { + monitor.checkCanceled(); + procSym(iter); + monitor.incrementProgress(1); + } + } + + //============================================================================================== + /** + * Process public symbols. User should not then call {@link #processAllSymbols()}; but + * has these other methods available to supplement this one: {@link #processGlobalSymbolsNoTypedefs()} + * and {@link #processNonPublicOrGlobalSymbols()}. + * @throws CancelledException upon user cancellation + * @throws PdbException upon issue processing the request + */ + private void processPublicSymbols() throws CancelledException, PdbException { + + SymbolGroup symbolGroup = getSymbolGroup(); + + PublicSymbolInformation publicSymbolInformation = + pdb.getDatabaseInterface().getPublicSymbolInformation(); + List offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets(); + setMonitorMessage("PDB: Applying " + offsets.size() + " public symbol components..."); + monitor.initialize(offsets.size()); + + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + for (long offset : offsets) { + monitor.checkCanceled(); + iter.initGetByOffset(offset); + if (!iter.hasNext()) { + break; + } + pdbApplicatorMetrics.witnessPublicSymbolType(iter.peek()); + procSym(iter); + monitor.incrementProgress(1); + } + } + + /** + * Process global symbols--no typedef. User should not then call {@link #processAllSymbols()}; + * but has these other methods available to supplement this one: (@link #processPublicSymbols()} + * and {@link #processNonPublicOrGlobalSymbols()}. + * @throws CancelledException upon user cancellation + * @throws PdbException upon issue processing the request + */ + private void processGlobalSymbolsNoTypedefs() throws CancelledException, PdbException { + + SymbolGroup symbolGroup = getSymbolGroup(); + + GlobalSymbolInformation globalSymbolInformation = + pdb.getDatabaseInterface().getGlobalSymbolInformation(); + List offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets(); + setMonitorMessage("PDB: Applying global symbols..."); + monitor.initialize(offsets.size()); + + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + for (long offset : offsets) { + monitor.checkCanceled(); + iter.initGetByOffset(offset); + if (!iter.hasNext()) { + break; + } + AbstractMsSymbol symbol = iter.peek(); + pdbApplicatorMetrics.witnessGlobalSymbolType(symbol); + if (!(symbol instanceof AbstractUserDefinedTypeMsSymbol)) { // Not doing typedefs here + procSym(iter); + } + monitor.incrementProgress(1); + } + } + + /** + * Process global typdef symbols. + * @throws CancelledException upon user cancellation + * @throws PdbException upon issue processing the request + */ + private void processGlobalTypdefSymbols() throws CancelledException, PdbException { + + SymbolGroup symbolGroup = getSymbolGroup(); + + GlobalSymbolInformation globalSymbolInformation = + pdb.getDatabaseInterface().getGlobalSymbolInformation(); + List offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets(); + setMonitorMessage("PDB: Applying typedefs..."); + monitor.initialize(offsets.size()); + + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + for (long offset : offsets) { + monitor.checkCanceled(); + iter.initGetByOffset(offset); + if (!iter.hasNext()) { + break; + } + AbstractMsSymbol symbol = iter.peek(); + if (symbol instanceof AbstractUserDefinedTypeMsSymbol) { // Doing typedefs here + procSym(iter); + } + monitor.incrementProgress(1); + } + } + + /** + * Processing non-public, non-global symbols. User should not then call + * {@link #processAllSymbols()}; but has these other methods available to supplement this one: + * {@link #processGlobalSymbolsNoTypedefs()} and (@link #processPublicSymbols()}. + * @throws CancelledException upon user cancellation + * @throws PdbException upon issue processing the request + */ + @SuppressWarnings("unused") // for method not being called. + private void processNonPublicOrGlobalSymbols() throws CancelledException, PdbException { + Set offsetsRemaining = getSymbolGroup().getOffsets(); + for (long off : pdb.getDatabaseInterface().getPublicSymbolInformation().getModifiedHashRecordSymbolOffsets()) { + monitor.checkCanceled(); + offsetsRemaining.remove(off); + } + for (long off : pdb.getDatabaseInterface().getGlobalSymbolInformation().getModifiedHashRecordSymbolOffsets()) { + monitor.checkCanceled(); + offsetsRemaining.remove(off); + } + + setMonitorMessage( + "PDB: Applying " + offsetsRemaining.size() + " other symbol components..."); + monitor.initialize(offsetsRemaining.size()); + //getCategoryUtils().setModuleTypedefsCategory(null); + + SymbolGroup symbolGroup = getSymbolGroup(); + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + for (long offset : offsetsRemaining) { + monitor.checkCanceled(); + iter.initGetByOffset(offset); + AbstractMsSymbol symbol = iter.peek(); + procSym(iter); + monitor.incrementProgress(1); + } + } + + //============================================================================================== + private int findLinkerModuleNumber() { + if (pdb.getDatabaseInterface() != null) { + int num = 1; + for (AbstractModuleInformation module : pdb.getDatabaseInterface().getModuleInformationList()) { + if (isLinkerModule(module.getModuleName())) { + return num; + } + num++; + } + } + appendLogMsg("Not processing linker symbols because linker module not found"); + return -1; + } + + private boolean isLinkerModule(String name) { + return "* Linker *".equals(name); + } + + //============================================================================================== + @SuppressWarnings("unused") // for method not being called. + private boolean processLinkerSymbols() throws CancelledException { + + int linkerModuleNumber = findLinkerModuleNumber(); + if (linkerModuleNumber == -1) { + return false; + } + + SymbolGroup symbolGroup = getSymbolGroupForModule(linkerModuleNumber); + if (symbolGroup == null) { + Msg.info(this, "No symbols to process from linker module."); + return false; + } + + setMonitorMessage("PDB: Applying " + symbolGroup.size() + " linker symbol components..."); + monitor.initialize(symbolGroup.size()); + + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + while (iter.hasNext()) { + checkCanceled(); + pdbApplicatorMetrics.witnessLinkerSymbolType(iter.peek()); + procSym(iter); + monitor.incrementProgress(1); + } + return true; + } + + //============================================================================================== + private void processThunkSymbolsFromNonLinkerModules() throws CancelledException { + + int linkerModuleNumber = findLinkerModuleNumber(); + + int totalCount = 0; + int num = pdb.getDatabaseInterface().getNumModules(); + for (int index = 1; index <= num; index++) { + monitor.checkCanceled(); + if (index == linkerModuleNumber) { + continue; + } + SymbolGroup symbolGroup = getSymbolGroupForModule(index); + totalCount += symbolGroup.size(); + } + setMonitorMessage("PDB: Processing module thunks..."); + monitor.initialize(totalCount); + + // Process symbols list for each module + for (int index = 1; index <= num; index++) { + monitor.checkCanceled(); + if (index == linkerModuleNumber) { + continue; + } + SymbolGroup symbolGroup = getSymbolGroupForModule(index); + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + while (iter.hasNext()) { + monitor.checkCanceled(); + AbstractMsSymbol symbol = iter.peek(); + if (symbol instanceof AbstractThunkMsSymbol) { + procSym(iter); + } + else { + iter.next(); + } + monitor.incrementProgress(1); + } + } + + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + AbstractMsSymbolApplier getSymbolApplier(AbstractMsSymbolIterator iter) + throws CancelledException, NoSuchElementException { + return symbolApplierParser.getSymbolApplier(iter); + } + + //============================================================================================== + void procSym(AbstractMsSymbolIterator iter) throws CancelledException { + try { + AbstractMsSymbolApplier applier = getSymbolApplier(iter); + applier.apply(); + } + catch (PdbException e) { + // skipping symbol + Msg.info(this, "Error applying symbol to program: " + e.toString()); + } + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + boolean isClass(SymbolPath path) { + return isClassByNamespace.get(path); + } + + //============================================================================================== + void predefineClass(SymbolPath classPath) { + isClassByNamespace.put(classPath, true); + for (SymbolPath path = classPath.getParent(); path != null; path = path.getParent()) { + if (!isClassByNamespace.containsKey(path)) { + isClassByNamespace.put(path, false); // path is simple namespace + } + } + } + + //============================================================================================== + private void defineClasses() throws CancelledException { + // create namespace and classes in an ordered fashion use tree map + monitor.initialize(isClassByNamespace.size()); + setMonitorMessage("PDB: Defining classes..."); + for (Map.Entry entry : isClassByNamespace.entrySet()) { + monitor.checkCanceled(); + SymbolPath path = entry.getKey(); + boolean isClass = entry.getValue(); + Namespace parentNamespace = + NamespaceUtils.getNonFunctionNamespace(program, path.getParent()); + if (parentNamespace == null) { + String type = isClass ? "class" : "namespace"; + log.appendMsg("Error: failed to define " + type + ": " + path); + continue; + } + defineNamespace(parentNamespace, path.getName(), isClass); + monitor.incrementProgress(1); + + } + } + + //============================================================================================== + private void defineNamespace(Namespace parentNamespace, String name, boolean isClass) { + + try { + SymbolTable symbolTable = program.getSymbolTable(); + Namespace namespace = symbolTable.getNamespace(name, parentNamespace); + if (namespace != null) { + if (isClass) { + if (namespace instanceof GhidraClass) { + return; + } + if (isSimpleNamespaceSymbol(namespace)) { + NamespaceUtils.convertNamespaceToClass(namespace); + return; + } + } + else if (namespace.getSymbol().getSymbolType() == SymbolType.NAMESPACE) { + return; + } + log.appendMsg("Unable to create class namespace due to conflicting symbol: " + + namespace.getName(true)); + } + else if (isClass) { + symbolTable.createClass(parentNamespace, name, SourceType.IMPORTED); + } + else { + symbolTable.createNameSpace(parentNamespace, name, SourceType.IMPORTED); + } + } + catch (Exception e) { + log.appendMsg("Unable to create class namespace: " + parentNamespace.getName(true) + + Namespace.DELIMITER + name + " due to exception: " + e.toString()); + } + } + + //============================================================================================== + private boolean isSimpleNamespaceSymbol(Namespace namespace) { + Symbol s = namespace.getSymbol(); + if (s.getSymbolType() != SymbolType.NAMESPACE) { + return false; + } + Namespace n = namespace; + while (n != null) { + if (n instanceof Function) { + return false; + } + n = n.getParentNamespace(); + } + return true; + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + @SuppressWarnings("unused") // for method not being called. + private void storeLabelByAddress(Address address, String label) { + Set labels = labelsByAddress.get(address); + if (labels == null) { + labels = new TreeSet<>(); + labelsByAddress.put(address, labels); + } + if (labels.contains(label)) { + // TODO investigate why we would see it again. + } + labels.add(label); + } + + @SuppressWarnings("unused") // for method not being called. + private void dumpLabels() { + for (Map.Entry> entry : labelsByAddress.entrySet()) { + Address address = entry.getKey(); + Set labels = entry.getValue(); + System.out.println("\nAddress: " + address); + for (String label : labels) { + System.out.println(label); + } + } + } + + //============================================================================================== + boolean shouldForcePrimarySymbol(Address address, boolean forceIfMangled) { + Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address); + if (primarySymbol != null) { + + if (primarySymbol.getName().startsWith("?") && forceIfMangled && + applicatorOptions.allowDemotePrimaryMangledSymbol()) { + return true; + } + + SourceType primarySymbolSource = primarySymbol.getSource(); + + if (!SourceType.ANALYSIS.isHigherPriorityThan(primarySymbolSource)) { + return true; + } + } + return false; + } + + //============================================================================================== + private static final String THUNK_NAME_PREFIX = "[thunk]:"; + + boolean createSymbol(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); + } + return true; + } + catch (InvalidInputException e) { + log.appendMsg("Unable to create symbol: " + e.getMessage()); + } + return false; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java new file mode 100644 index 0000000000..0296958d90 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java @@ -0,0 +1,278 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.HashSet; +import java.util.Set; + +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.listing.Program; + +/** + * Metrics captured during the application of a PDB. This is a Ghidra class separate from the + * PDB API that we have crafted to help us quantify and qualify the ability apply the PDB + * to a {@link DataTypeManager} and/or {@link Program}. + */ +public class PdbApplicatorMetrics { + + /** + * List of symbols seen (by their ID) as Global symbols. + */ + private static Set expectedGlobalSymbols = new HashSet<>(); + static { + // AbstractReferenceMsSymbol + expectedGlobalSymbols.add(DataReferenceStMsSymbol.PDB_ID); + expectedGlobalSymbols.add(DataReferenceMsSymbol.PDB_ID); + expectedGlobalSymbols.add(LocalProcedureReferenceMsSymbol.PDB_ID); + expectedGlobalSymbols.add(LocalProcedureReferenceStMsSymbol.PDB_ID); + expectedGlobalSymbols.add(ProcedureReferenceMsSymbol.PDB_ID); + expectedGlobalSymbols.add(ProcedureReferenceStMsSymbol.PDB_ID); + expectedGlobalSymbols.add(AnnotationReferenceMsSymbol.PDB_ID); + expectedGlobalSymbols.add(TokenReferenceToManagedProcedureMsSymbol.PDB_ID); + + // AbstractDataMsSymbol + expectedGlobalSymbols.add(GlobalData16MsSymbol.PDB_ID); + expectedGlobalSymbols.add(GlobalData3216MsSymbol.PDB_ID); + expectedGlobalSymbols.add(GlobalData32MsSymbol.PDB_ID); + expectedGlobalSymbols.add(GlobalData32StMsSymbol.PDB_ID); + expectedGlobalSymbols.add(LocalData16MsSymbol.PDB_ID); + expectedGlobalSymbols.add(LocalData3216MsSymbol.PDB_ID); + expectedGlobalSymbols.add(LocalData32MsSymbol.PDB_ID); + expectedGlobalSymbols.add(LocalData32StMsSymbol.PDB_ID); + expectedGlobalSymbols.add(GlobalManagedDataMsSymbol.PDB_ID); + expectedGlobalSymbols.add(GlobalManagedDataStMsSymbol.PDB_ID); + expectedGlobalSymbols.add(LocalManagedDataMsSymbol.PDB_ID); + expectedGlobalSymbols.add(LocalManagedDataStMsSymbol.PDB_ID); + + // AbstractUserDefinedTypeMsSymbol + expectedGlobalSymbols.add(CobolUserDefinedType16MsSymbol.PDB_ID); + expectedGlobalSymbols.add(CobolUserDefinedTypeMsSymbol.PDB_ID); + expectedGlobalSymbols.add(CobolUserDefinedTypeStMsSymbol.PDB_ID); + expectedGlobalSymbols.add(UserDefinedType16MsSymbol.PDB_ID); + expectedGlobalSymbols.add(UserDefinedTypeMsSymbol.PDB_ID); + expectedGlobalSymbols.add(UserDefinedTypeStMsSymbol.PDB_ID); + + // AbstractConstantMsSymbol + expectedGlobalSymbols.add(Constant16MsSymbol.PDB_ID); + expectedGlobalSymbols.add(ConstantMsSymbol.PDB_ID); + expectedGlobalSymbols.add(ConstantStMsSymbol.PDB_ID); + expectedGlobalSymbols.add(ManagedConstantMsSymbol.PDB_ID); + } + + /** + * List of symbols seen (by their ID) as Public symbols. + */ + private static Set expectedLinkerSymbols = new HashSet<>(); + static { + expectedLinkerSymbols.add(PeCoffSectionMsSymbol.PDB_ID); + expectedLinkerSymbols.add(TrampolineMsSymbol.PDB_ID); + expectedLinkerSymbols.add(ObjectNameMsSymbol.PDB_ID); + expectedLinkerSymbols.add(Compile3MsSymbol.PDB_ID); + expectedLinkerSymbols.add(Compile2MsSymbol.PDB_ID); + expectedLinkerSymbols.add(Compile2StMsSymbol.PDB_ID); + expectedLinkerSymbols.add(EnvironmentBlockMsSymbol.PDB_ID); + } + + private Set> cannotApplyTypes = new HashSet<>(); + private Set> unexpectedMemberFunctionThisPointerTypes = + new HashSet<>(); + private Set> unexpectedMemberFunctionThisPointerUnderlyingTypes = + new HashSet<>(); + private Set> unexpectedMemberFunctionContainerTypes = + new HashSet<>(); + private Set> cannotApplySymbols = new HashSet<>(); + private Set> unexpectedGlobalSymbols = new HashSet<>(); + private Set> unexpectedPublicSymbols = new HashSet<>(); + private boolean witnessEnumerateNarrowing = false; + + /** + * Method to capture data/item type that cannot be applied. + * @param type The data/item type witnessed. + */ + public void witnessCannotApplyDataType(AbstractMsType type) { + cannotApplyTypes.add(type.getClass()); + } + + /** + * Method to capture symbol type that cannot be applied. + * @param symbol The symbol type witnessed. + */ + public void witnessCannotApplySymbolType(AbstractMsSymbol symbol) { + cannotApplySymbols.add(symbol.getClass()); + } + + /** + * Method to capture symbol type that was unexpected as a Global symbol. + * @param symbol The symbol type witnessed. + */ + public void witnessGlobalSymbolType(AbstractMsSymbol symbol) { + if (!expectedGlobalSymbols.contains(symbol.getPdbId())) { + unexpectedGlobalSymbols.add(symbol.getClass()); + } + } + + /** + * Method to capture symbol type that was unexpected as a Public symbol. + * @param symbol The symbol type witnessed. + */ + public void witnessPublicSymbolType(AbstractMsSymbol symbol) { + if (!(symbol instanceof AbstractPublicMsSymbol)) { + unexpectedPublicSymbols.add(symbol.getClass()); + } + } + + /** + * Method to capture symbol type that was unexpected as a Linker symbol. + * @param symbol The symbol type witnessed. + */ + public void witnessLinkerSymbolType(AbstractMsSymbol symbol) { + if (!expectedLinkerSymbols.contains(symbol.getPdbId())) { + // do nothing for now + } + } + + /** + * Method to capture witnessing of Enumerate narrowing. + */ + public void witnessEnumerateNarrowing() { + witnessEnumerateNarrowing = true; + } + + /** + * Method to capture unusual this pointer types. + * @param applier The {@AbstractMsTypeApplier} for the supposed this pointer. + */ + public void witnessMemberFunctionThisPointer(AbstractMsTypeApplier applier) { + // We know that we have seen PrimitiveMsTypes that are pointer types. + if (applier instanceof PointerTypeApplier) { + return; + } + unexpectedMemberFunctionThisPointerTypes.add(applier.getMsType().getClass()); + } + + /** + * Method to capture unusual underlying types for a normal pointer for this pointer. + * @param applier The {@AbstractMsTypeApplier} for the supposed this pointer. + */ + public void witnessMemberFunctionThisPointerUnderlyingType(AbstractMsTypeApplier applier) { + if (applier instanceof CompositeTypeApplier) { + return; + } + unexpectedMemberFunctionThisPointerUnderlyingTypes.add(applier.getMsType().getClass()); + } + + /** + * Method to capture unusual containing types for a member function. + * @param applier The {@AbstractMsTypeApplier} for the supposed this pointer. + */ + public void witnessMemberFunctionContainingType(AbstractMsTypeApplier applier) { + if (applier instanceof CompositeTypeApplier) { + return; + } + unexpectedMemberFunctionContainerTypes.add(applier.getMsType().getClass()); + } + + //============================================================================================== + + /** + * Return some post-processing metrics for applying the PDB + * @return {@link String} of pretty output. + */ + public String getPostProcessingReport() { + StringBuilder builder = new StringBuilder(); + builder.append("===Begin PdbApplicatorMetrics Report===\n"); + builder.append(reportNonappliableTypes()); + builder.append(reportUnunsualThisPointerTypes()); + builder.append(reportUnunsualThisPointerUnderlyingTypes()); + builder.append(reportUnunsualMemberFunctionContainerTypes()); + builder.append(reportNonappliableSymbols()); + builder.append(reportUnexpectedPublicSymbols()); + builder.append(reportUnexpectedGlobalSymbols()); + builder.append(reportEnumerateNarrowing()); + builder.append("====End PdbApplicatorMetrics Report====\n"); + return builder.toString(); + } + + private String reportNonappliableTypes() { + StringBuilder builder = new StringBuilder(); + for (Class clazz : cannotApplyTypes) { + builder.append("Could not apply one or more instances of PDB data type: " + + clazz.getSimpleName() + "\n"); + } + return builder.toString(); + } + + private String reportUnunsualThisPointerTypes() { + StringBuilder builder = new StringBuilder(); + for (Class clazz : unexpectedMemberFunctionThisPointerTypes) { + builder.append("Unusual this pointer type: " + clazz.getSimpleName() + "\n"); + } + return builder.toString(); + } + + private String reportUnunsualThisPointerUnderlyingTypes() { + StringBuilder builder = new StringBuilder(); + for (Class clazz : unexpectedMemberFunctionThisPointerUnderlyingTypes) { + builder.append("Unusual this pointer underlying type: " + clazz.getSimpleName() + "\n"); + } + return builder.toString(); + } + + private String reportUnunsualMemberFunctionContainerTypes() { + StringBuilder builder = new StringBuilder(); + for (Class clazz : unexpectedMemberFunctionContainerTypes) { + builder.append("Unusual member function container: " + clazz.getSimpleName() + "\n"); + } + return builder.toString(); + } + + private String reportNonappliableSymbols() { + StringBuilder builder = new StringBuilder(); + for (Class clazz : cannotApplySymbols) { + builder.append("Could not apply one or more instances of PDB symbol type: " + + clazz.getSimpleName() + "\n"); + } + return builder.toString(); + } + + private String reportUnexpectedPublicSymbols() { + StringBuilder builder = new StringBuilder(); + for (Class clazz : unexpectedPublicSymbols) { + builder.append("Unexpected one or more instances of PDB public symbol type: " + + clazz.getSimpleName() + "\n"); + } + return builder.toString(); + } + + private String reportUnexpectedGlobalSymbols() { + StringBuilder builder = new StringBuilder(); + for (Class clazz : unexpectedGlobalSymbols) { + builder.append("Unexpected one or more instances of PDB global symbol type: " + + clazz.getSimpleName() + "\n"); + } + return builder.toString(); + } + + private String reportEnumerateNarrowing() { + if (witnessEnumerateNarrowing) { + return "Enumerate narrowing was witnessed\n"; + } + return ""; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java new file mode 100644 index 0000000000..102532a674 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java @@ -0,0 +1,213 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb; + +/** + * Options used while using a {@link PdbApplicator} to apply a PDB ({@link AbstractPdb}) to a + * Ghidra program. These can be optional values used during our development of this PdbApplicator, + * and thus might not be found in the finished product. + */ +public class PdbApplicatorOptions extends Exception { + + private static final boolean defaultApplyCodeScopeBlockComments = false; + private static final boolean defaultApplyInstructionLabels = false; + private static final boolean defaultApplyDataTypesOnly = false; + private static final boolean defaultApplyPublicSymbolsOnly = false; + private static final boolean defaultRemapAddressesUsingExistingPublicSymbols = false; + private static final boolean defaultAllowDemotePrimaryMangledSymbol = true; + + // TODO: set the following to true if we come up with a reasonably good solution + private static final boolean defaultApplyFunctionVariables = false; + + private static final CompositeLayoutMode defaultCompositeLayoutMode = + CompositeLayoutMode.MEMBERS_ONLY; +// private static final CompositeLayoutMode defaultCompositeLayoutMode = +// CompositeLayoutMode.BASIC_SIMPLE_COMPLEX; +// private static final CompositeLayoutMode defaultCompositeLayoutMode = +// CompositeLayoutMode.SIMPLE_COMPLEX; +// private static final CompositeLayoutMode defaultCompositeLayoutMode = +// CompositeLayoutMode.COMPLEX; + + //============================================================================================== + private boolean applyCodeScopeBlockComments; + private boolean applyInstructionLabels; + private boolean applyDataTypesOnly; + private boolean applyPublicSymbolsOnly; + private boolean remapAddressesUsingExistingPublicSymbols; + private boolean allowDemotePrimaryMangledSymbol; + + private boolean applyFunctionVariables; // investigation. might produce bad results. + + private CompositeLayoutMode compositeLayoutMode; + + /** + * Constructor + */ + public PdbApplicatorOptions() { + setDefaults(); + } + + /** + * Set the options back to their default values + */ + public void setDefaults() { + applyCodeScopeBlockComments = defaultApplyCodeScopeBlockComments; + applyInstructionLabels = defaultApplyInstructionLabels; + applyDataTypesOnly = defaultApplyDataTypesOnly; + applyPublicSymbolsOnly = defaultApplyPublicSymbolsOnly; + remapAddressesUsingExistingPublicSymbols = defaultRemapAddressesUsingExistingPublicSymbols; + allowDemotePrimaryMangledSymbol = defaultAllowDemotePrimaryMangledSymbol; + applyFunctionVariables = defaultApplyFunctionVariables; + compositeLayoutMode = defaultCompositeLayoutMode; + } + + /** + * Enable/disable developmental debug. + * @param applyCodeScopeBlockComments {@code true} to turn applyCodeScopeBlockComments on + */ + public void setApplyCodeScopeBlockComments(boolean applyCodeScopeBlockComments) { + this.applyCodeScopeBlockComments = applyCodeScopeBlockComments; + } + + /** + * Returns {@code true} if applyCodeScopeBlockComments is "on." + * @return {@code true} if applyCodeScopeBlockComments is "on." + */ + public boolean applyCodeScopeBlockComments() { + return applyCodeScopeBlockComments; + } + + /** + * Enable/disable developmental debug. + * @param applyInstructionLabels {@code true} to turn applyInstructionLabels on + */ + public void setApplyInstructionLabels(boolean applyInstructionLabels) { + this.applyInstructionLabels = applyInstructionLabels; + } + + /** + * Returns {@code true} if applyInstructionLabels is "on." + * @return {@code true} if applyInstructionLabels is "on." + */ + public boolean applyInstructionLabels() { + return applyInstructionLabels; + } + + /** + * Enable/disable the option to only apply data types (skipping symbol information). + * In other words, the default is to apply symbols. + * @param applyDataTypesOnly {@code true} to turn applyDataTypesOnly on + */ + public void setApplyDataTypesOnly(boolean applyDataTypesOnly) { + this.applyDataTypesOnly = applyDataTypesOnly; + } + + /** + * Returns {@code true} if applyDataTypesOnly is "on." + * @return {@code true} if applyDataTypesOnly is "on." + */ + public boolean applyDataTypesOnly() { + return applyDataTypesOnly; + } + + /** + * Enable/disable the option to only apply public symbols. + * @param applyPublicSymbolsOnly {@code true} to turn applyPublicSymbolsOnly on + */ + public void setApplyPublicSymbolsOnly(boolean applyPublicSymbolsOnly) { + this.applyPublicSymbolsOnly = applyPublicSymbolsOnly; + } + + /** + * Returns {@code true} if applyPublicSymbolsOnly is "on." + * @return {@code true} if applyPublicSymbolsOnly is "on." + */ + public boolean applyPublicSymbolsOnly() { + return applyPublicSymbolsOnly; + } + + /** + * Enable/disable the option to attempt to map addresses using existing mangled symbols + * (typically public symbols). + * @param enable {@code true} to turn remapAddressesUsingExistingPublicSymbols on + */ + public void setRemapAddressUsingExistingPublicMangledSymbols(boolean enable) { + this.remapAddressesUsingExistingPublicSymbols = enable; + } + + /** + * Returns {@code true} if remapAddressesUsingExistingPublicSymbols is "on." + * @return {@code true} if remapAddressesUsingExistingPublicSymbols is "on." + */ + public boolean remapAddressUsingExistingPublicMangledSymbols() { + return remapAddressesUsingExistingPublicSymbols; + } + + /** + * Enable/disable the option to allow another symbol be set to primary when the existing + * primary symbol is a mangled symbol, regardless of the Symbol SourceType. This is + * typically used when we can get better data type information from the PDB record than + * we can from the demangler. + * @param enable {@code true} to turn allowDemotePrimaryMangledSymbol on + */ + public void setAllowDemotePrimaryMangledSymbol(boolean enable) { + this.allowDemotePrimaryMangledSymbol = enable; + } + + /** + * Returns {@code true} if allowDemotePrimaryMangledSymbol is "on." + * @return {@code true} if allowDemotePrimaryMangledSymbol is "on." + */ + public boolean allowDemotePrimaryMangledSymbol() { + return allowDemotePrimaryMangledSymbol; + } + + /** + * Enable/disable the option to apply function params and locals, which might produce improper + * results. + * @param applyFunctionVariables {@code true} to turn applyPublicSymbolsOnly on + */ + public void setApplyFunctionVariables(boolean applyFunctionVariables) { + this.applyFunctionVariables = applyFunctionVariables; + } + + /** + * Returns {@code true} if applyFunctionVariables is "on." + * @return {@code true} if applyFunctionVariables is "on." + */ + public boolean applyFunctionVariables() { + return applyFunctionVariables; + } + + /** + * Set the CompositeLayoutMode. + * @param compositeLayoutMode composite layout mode + */ + public void setCompositeLayoutMode(CompositeLayoutMode compositeLayoutMode) { + this.compositeLayoutMode = compositeLayoutMode; + } + + /** + * Returns the mode for physically layout out composites. + * @return the layout mode. + */ + public CompositeLayoutMode getCompositeLayoutMode() { + return compositeLayoutMode; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java new file mode 100644 index 0000000000..b02ce78f43 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java @@ -0,0 +1,698 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.*; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType; +import ghidra.program.model.data.*; +import ghidra.util.exception.AssertException; + +/** + * Takes care of allocating unique instances of primitive data types for the {@link PdbApplicator}, + * and is used principally by the many instances of {@link PrimitiveTypeApplier}. + */ +public class PdbPrimitiveTypeApplicator { + + private final static DataType NO_TYPE_DATATYPE = + new TypedefDataType("", Undefined1DataType.dataType); + + //============================================================================================== + private DataTypeManager dataTypeManager; + + //============================================================================================== + private DataType voidGhidraPrimitive = null; + private DataType charGhidraPrimitive = null; + private DataType signedCharGhidraPrimitive = null; + private DataType unsignedCharGhidraPrimitive = null; + + //private Map booleanGhidraPrimitives = new HashMap<>(); + private Map integralGhidraPrimitives = new HashMap<>(); + private Map unsignedIntegralGhidraPrimitives = new HashMap<>(); + private Map floatGhidraPrimitives = new HashMap<>(); + private Map complexGhidraPrimitives = new HashMap<>(); + + private Map otherPrimitives = new HashMap<>(); + + //============================================================================================== + /** + * Constructor + * @param dataTypeManager The {@link DataTypeManager} associated with these types. + */ + public PdbPrimitiveTypeApplicator(DataTypeManager dataTypeManager) { + Objects.requireNonNull(dataTypeManager, "dataTypeManager cannot be null"); + this.dataTypeManager = dataTypeManager; + } + + /** + * Returns the {@link DataTypeManager} associated with this analyzer. + * @return DataTypeManager which this analyzer is using. + */ + private DataTypeManager getDataTypeManager() { + return dataTypeManager; + } + + DataType resolve(DataType dataType) { + return getDataTypeManager().resolve(dataType, + DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER); + } + + //============================================================================================== + DataType getNoType(PrimitiveMsType type) { + return NO_TYPE_DATATYPE; + } + + DataType getVoidType() { + if (voidGhidraPrimitive == null) { + DataType dataType = new VoidDataType(getDataTypeManager()); + voidGhidraPrimitive = resolve(dataType); + } + return voidGhidraPrimitive; + } + + DataType getCharType() { + if (charGhidraPrimitive == null) { + DataType dataType = new CharDataType(getDataTypeManager()); + charGhidraPrimitive = resolve(dataType); + } + return charGhidraPrimitive; + } + + DataType getSignedCharType() { + if (signedCharGhidraPrimitive == null) { + DataType dataType = new SignedCharDataType(getDataTypeManager()); + signedCharGhidraPrimitive = resolve(dataType); + } + return signedCharGhidraPrimitive; + } + + DataType getUnsignedCharType() { + if (unsignedCharGhidraPrimitive == null) { + DataType dataType = new UnsignedCharDataType(getDataTypeManager()); + unsignedCharGhidraPrimitive = resolve(dataType); + } + return unsignedCharGhidraPrimitive; + } + + DataType getUnicode16Type() { + // For now, we are returning WideChar16 for Unicode16. + return new WideChar16DataType(getDataTypeManager()); + } + + DataType getUnicode32Type() { + // For now, we are returning WideChar32 for Unicode32. + return new WideChar32DataType(getDataTypeManager()); + } + + WideCharDataType getWideCharType() { + return new WideCharDataType(getDataTypeManager()); + } + + DataType get8BitIntegerType() { + String name = "int8"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 1) { + type = IntegerDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(1)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get8BitUnsignedIntegerType() { + String name = "uint8"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 1) { + type = UnsignedIntegerDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(1)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get16BitIntegerType() { + String name = "int16"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 2) { + type = IntegerDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(2)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get16BitUnsignedIntegerType() { + String name = "uint16"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 2) { + type = UnsignedIntegerDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(2)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get16BitShortType() { + String name = "short16"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getShortSize() == 2) { + type = ShortDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(2)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get16BitUnsignedShortType() { + String name = "ushort16"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getShortSize() == 2) { + type = UnsignedShortDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(2)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get32BitIntegerType() { + String name = "int32"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 4) { + type = IntegerDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(4)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get32BitUnsignedIntegerType() { + String name = "uint32"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 4) { + type = UnsignedIntegerDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(4)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get32BitLongType() { + String name = "long32"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getLongSize() == 4) { + type = LongDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(4)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get32BitUnsignedLongType() { + String name = "ulong32"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getLongSize() == 4) { + type = UnsignedLongDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(4)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get64BitLongType() { + String name = "long64"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getLongSize() == 8) { + type = LongDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(8)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get64BitUnsignedLongType() { + String name = "ulong64"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getLongSize() == 8) { + type = UnsignedLongDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(8)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get64BitIntegerType() { + String name = "int64"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 8) { + type = IntegerDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(8)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get64BitUnsignedIntegerType() { + String name = "uint64"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 8) { + type = UnsignedIntegerDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(8)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get128BitLongType() { + String name = "ulong128"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getLongSize() == 16) { + type = LongDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(16)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get128BitUnsignedLongType() { + String name = "ulong128"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getLongSize() == 16) { + type = UnsignedLongDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(16)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get128BitIntegerType() { + String name = "int128"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 16) { + type = IntegerDataType.dataType; + } + else { + type = createTypedef(name, getIntegralType(16)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get128BitUnsignedIntegerType() { + String name = "uint128"; + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + DataType type; + if (getDataTypeManager().getDataOrganization().getIntegerSize() == 16) { + type = UnsignedIntegerDataType.dataType; + } + else { + type = createTypedef(name, getUnsignedIntegralType(16)); + } + DataType resolved = resolve(type); + otherPrimitives.put(name, resolved); + return resolved; + } + + private DataType createTypedef(String name, DataType dataType) { + DataType typedefDataType = new TypedefDataType(name, dataType); + return resolve(typedefDataType); + } + + DataType createTypedefNamedSizedType(String name, int size) { + DataType dataType = new TypedefDataType(name, Undefined.getUndefinedDataType(size)); + return resolve(dataType); + } + + DataType createTypedefNamedSizedType(PrimitiveMsType type) { + return createTypedefNamedSizedType(type.getName(), type.getTypeSize()); + } + + DataType createUnmappedPdbType(PrimitiveMsType type) { + String name = String.format("UnmappedPdbType%04X", type.getNumber()); + return createTypedefNamedSizedType(name, 1); + } + + private DataType getIntegralType(int size) { + DataType dataType = integralGhidraPrimitives.get(size); + if (dataType != null) { + return dataType; + } + DataType resolved = + resolve(AbstractIntegerDataType.getSignedDataType(size, getDataTypeManager())); + integralGhidraPrimitives.put(size, resolved); + return resolved; + } + + private DataType getUnsignedIntegralType(int size) { + DataType dataType = unsignedIntegralGhidraPrimitives.get(size); + if (dataType != null) { + return dataType; + } + DataType resolved = + resolve(AbstractIntegerDataType.getUnsignedDataType(size, getDataTypeManager())); + unsignedIntegralGhidraPrimitives.put(size, resolved); + return resolved; + } + + DataType get16BitRealType() { + return getRealType(2, "float16"); + } + + DataType get32BitRealType() { + return getRealType(4, "float32"); + } + + DataType get32BitPartialPrecisionRealType() { + // TODO: Do we have / can we craft this type? + return createTypedefNamedSizedType("T_REAL32PP", 4); + } + + DataType get48BitRealType() { + return getRealType(6, "float48"); + } + + DataType get64BitRealType() { + return getRealType(8, "float64"); + } + + DataType get80BitRealType() { + return getRealType(10, "float80"); + } + + DataType get128BitRealType() { + return getRealType(16, "float128"); + } + + /* + * First get type from "other" list, which are typedefs to underlying primitives. If it does + * not exist, then find the proper underlying primitive, create the typedef, and cache this + * newly minted (typedef) unique primitive type. + */ + private DataType getRealType(int size, String name) { + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + dataType = floatGhidraPrimitives.get(size); + DataType resolved; + if (dataType == null) { + resolved = resolve(AbstractFloatDataType.getFloatDataType(size, getDataTypeManager())); + floatGhidraPrimitives.put(size, resolved); + if (resolved instanceof Undefined) { // Not a real type implemented in Ghidra. + DataType type = createTypedef(name, resolved); + resolved = resolve(type); + } + } + else { + resolved = dataType; + } + otherPrimitives.put(name, resolved); + return resolved; + } + + DataType get16BitComplexType() { + return getComplexType(16); + } + + DataType get32BitComplexType() { + return getComplexType(4); + } + + DataType get32BitPartialPrecisionComplexType() { + return createTypedefNamedSizedType("T_CPLX32PP", 8); + } + + DataType get48BitComplexType() { + return getComplexType(48); + } + + DataType get64BitComplexType() { + return getComplexType(8); + } + + DataType get80BitComplexType() { + return getComplexType(10); + } + + DataType get128BitComplexType() { + return getComplexType(128); + } + + private DataType getComplexType(int size) { + DataType dataType = complexGhidraPrimitives.get(size); + if (dataType != null) { + return dataType; + } + switch (size) { + case 32: + // Case 32 is presumably 32 bits per real/imag. This is 4 bytes each, or 8 + // bytes total + // Use the internal type. + dataType = new Complex8DataType(getDataTypeManager()); + break; + case 64: + // Case 64 is presumably 64 bits per real/imag. This is 8 bytes each, or 16 + // bytes total + // Use the internal type. + dataType = new Complex16DataType(getDataTypeManager()); + break; + case 80: + // TODO: Replace with Complex20DataType when it is available. + dataType = createTypedefNamedSizedType("T_CPLX80", 20); + break; + case 128: + // Case 128 is presumably 128 bits per real/imag. This is 16 bytes each, or 32 + // bytes total + // Use the internal type. + dataType = new Complex32DataType(getDataTypeManager()); + break; + default: + String message = "Programming error: Complex size not supported" + size; + PdbLog.message(message); + throw new AssertException(message); + } + DataType resolved = resolve(dataType); + complexGhidraPrimitives.put(size, resolved); + return resolved; + } + + DataType get8BitBooleanType() { + return getBooleanType(1, "T_BOOL08"); + } + + DataType get16BitBooleanType() { + return getBooleanType(2, "T_BOOL16"); + } + + DataType get32BitBooleanType() { + return getBooleanType(4, "T_BOOL32"); + } + + DataType get64BitBooleanType() { + return getBooleanType(8, "T_BOOL64"); + } + + DataType get128BitBooleanType() { + return getBooleanType(16, "T_BOOL128"); + } + + /* + * First get type from "other" list, which are typedefs to underlying primitives. If it does + * not exist, then find the proper underlying primitive, create the typedef, and cache this + * newly minted (typedef) unique primitive type. + */ + private DataType getBooleanType(int size, String name) { + DataType dataType = otherPrimitives.get(name); + if (dataType != null) { + return dataType; + } + if (size == getBooleanSize()) { // TODO: see TODO inside called method. + dataType = new BooleanDataType(getDataTypeManager()); + } + else { + dataType = getIntegralType(size); + } + DataType resolved = resolve(dataType); + otherPrimitives.put(name, resolved); + return resolved; + } + + /* + * Mimics a Ghidra getBoolean type that has a data organizationhierarchy for which one can + * call getSize() on the type to determine the size of the boolean on the current + * architecture. + */ + private int getBooleanSize() { + return 1; + // TODO: change to the following line when it is available. + //return applicator.getDataTypeManager().getDataOrganization().getBooleanSize(); + } + + private Pointer getPointerType(int ptrSize, DataType baseType) { + if (getDataTypeManager().getDataOrganization().getPointerSize() == ptrSize) { + return getDataTypeManager().getPointer(baseType); + } + return getDataTypeManager().getPointer(baseType, ptrSize); + } + + Pointer get16NearPointerType(PrimitiveMsType type, DataType baseType) { + return getPointerType(type.getTypeSize(), baseType); + } + + Pointer get1616FarPointerType(PrimitiveMsType type, DataType baseType) { + return getPointerType(type.getTypeSize(), baseType); + } + + Pointer get1616HugePointerType(PrimitiveMsType type, DataType baseType) { + return getPointerType(type.getTypeSize(), baseType); + } + + Pointer get32PointerType(PrimitiveMsType type, DataType baseType) { + return getPointerType(type.getTypeSize(), baseType); + } + + Pointer get1632PointerType(PrimitiveMsType type, DataType baseType) { + return getPointerType(type.getTypeSize(), baseType); + } + + Pointer get64PointerType(PrimitiveMsType type, DataType baseType) { + return getPointerType(type.getTypeSize(), baseType); + } + + Pointer get128PointerType(PrimitiveMsType type, DataType baseType) { + return getPointerType(type.getTypeSize(), baseType); + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java new file mode 100644 index 0000000000..0e91814602 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java @@ -0,0 +1,63 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.HashMap; +import java.util.Map; + +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.Program; +import ghidra.util.Msg; + +/** + * Maps PDB register name to program {@link Register}. + */ +public class PdbRegisterNameToProgramRegisterMapper { + + // Only need to map names that are different (probably not counting case, as rsp and RSP + // are equivalent. + private static Map registerNameMap = new HashMap<>(); + static { + //registerNameMap.put("rsp", "RSP"); + registerNameMap.put("fbp", "RBP"); + } + + private Program program; + private Map pdbRegisterNameToRegisterMap; + + public PdbRegisterNameToProgramRegisterMapper(Program program) { + this.program = program; + pdbRegisterNameToRegisterMap = new HashMap<>(); + } + + Register getRegister(String pdbRegisterName) { + Register register = pdbRegisterNameToRegisterMap.get(pdbRegisterName); + if (register != null) { + return register; + } + String registerName = registerNameMap.get(pdbRegisterName); + if (registerName == null) { + registerName = pdbRegisterName; + } + register = program.getRegister(registerName); + pdbRegisterNameToRegisterMap.put(pdbRegisterName, register); + if (register == null) { + Msg.info(this, "Program register not found for " + registerName); + } + return register; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java new file mode 100644 index 0000000000..961db15a91 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java @@ -0,0 +1,1001 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.*; + +import ghidra.app.util.bin.format.pdb.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; +import mdemangler.*; +import mdemangler.object.MDObjectCPP; + +public class PdbResearch { + + //============================================================================================== + private static Set debugIndexNumbers; + + //============================================================================================== + static void initCheckBreak() { + debugIndexNumbers = new TreeSet<>(); + + debugIndexNumbers.add(12527); + +// debugIndexNumbers.add(180462); + +// debugIndexNumbers.add(4673); //flex array + +// debugIndexNumbers.add(4469); +// debugIndexNumbers.add(4470); + +// debugIndexNumbers.add(11843); //chrome +// debugIndexNumbers.add(12720); //chrome + +// debugIndexNumbers.add(4385); + +// debugIndexNumbers.add(4825); + +// debugIndexNumbers.add(4246); + +// debugIndexNumbers.add(4389); + +// debugIndexNumbers.add(4380); + +// debugIndexNumbers.add(4332); + +// debugIndexNumbers.add(11843); + +// debugIndexNumbers.add(2972763); +// debugIndexNumbers.add(2972764); +// debugIndexNumbers.add(2972766); +// debugIndexNumbers.add(2972769); + +// debugIndexNumbers.add(87810); +// debugIndexNumbers.add(218584); + +// debugIndexNumbers.add(4126); + +// debugIndexNumbers.add(2960288); + +// // nested classes. +// debugIndexNumbers.add(7895); +// debugIndexNumbers.add(7895); +// +// debugIndexNumbers.add(4549); + + // chrome +// debugIndexNumbers.add(9696); +// debugIndexNumbers.add(9697); +// debugIndexNumbers.add(9699); +// debugIndexNumbers.add(9700); +// debugIndexNumbers.add(9701); +// debugIndexNumbers.add(9708); +// debugIndexNumbers.add(9709); +// debugIndexNumbers.add(216056); +// debugIndexNumbers.add(216012); +// debugIndexNumbers.add(216013); +// debugIndexNumbers.add(216016); +// debugIndexNumbers.add(216058); + +// // chrome: enum fwdref def +// debugIndexNumbers.add(5809); //field list with enumerate + +// // chrome: enum fwdref def +// debugIndexNumbers.add(9631); +// debugIndexNumbers.add(30695); + +// // chrome: last fwdref ummatched +// debugIndexNumbers.add(216055); + +// // chrome: enum namespace broken +// debugIndexNumbers.add(17034); + +// // chrome: anon func and function pointer +// debugIndexNumbers.add(197736); +// debugIndexNumbers.add(197737); + +// // nt: composite +// debugIndexNumbers.add(4499); +// debugIndexNumbers.add(4760); + +// // chrome: anon func +// debugIndexNumbers.add(6577); + +// // chrome: argument +// debugIndexNumbers.add(42433); + +// // gray: tagLOCALETAB array +// debugIndexNumbers.add(4887); + +// // gray: tagPARAMDESCEX and tagVARIANT +// debugIndexNumbers.add(6033); +// debugIndexNumbers.add(6037); +// debugIndexNumbers.add(6039); +// debugIndexNumbers.add(6075); + +// // gray: _IMAGE_OPTIONAL_HEADER64 and _IMAGE_DATA_DIRECTORY (array) +// debugIndexNumbers.add(4974); +// debugIndexNumbers.add(4975); +// debugIndexNumbers.add(4977); +// debugIndexNumbers.add(4982); +// debugIndexNumbers.add(4992); + +// // gray: def before fwdref +// debugIndexNumbers.add(4859); +// debugIndexNumbers.add(4876); + +// debugIndexNumbers.add(5367); +// // ********* NEXT SET ********** +// debugIndexNumbers.add(6660); +// debugIndexNumbers.add(6835); +// debugIndexNumbers.add(129037); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(236516); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(117107); +// debugIndexNumbers.add(117125); + + // ********* NEXT SET ********** + //GRAY +// debugIndexNumbers.add(4176); +// debugIndexNumbers.add(4188); +// debugIndexNumbers.add(4199); +// debugIndexNumbers.add(4257); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(111583); +// debugIndexNumbers.add(111585); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(195850); +// debugIndexNumbers.add(195851); +// debugIndexNumbers.add(195853); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(11180); +// debugIndexNumbers.add(192618); +// debugIndexNumbers.add(192619); +// debugIndexNumbers.add(192620); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(4111); +// debugIndexNumbers.add(42432); +// debugIndexNumbers.add(42433); +// debugIndexNumbers.add(29156); +// debugIndexNumbers.add(29157); +// debugIndexNumbers.add(29194); +// debugIndexNumbers.add(214780); +// debugIndexNumbers.add(237308); +// +// debugIndexNumbers.add(232902); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(5980); +// debugIndexNumbers.add(6224); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(6331); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(81379); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(251910); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(33617); +// debugIndexNumbers.add(33621); + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(183821); //fwd ref +// debugIndexNumbers.add(183828); //def 1 +// debugIndexNumbers.add(214748); //def 2 +// debugIndexNumbers.add(228395); //def 3 +// debugIndexNumbers.add(235802); //def 4 + +// // ********* NEXT SET ********** +// debugIndexNumbers.add(4193); +// debugIndexNumbers.add(4203); +// debugIndexNumbers.add(4280); + + // ********* NEXT SET ********** +// // big class +// debugIndexNumbers.add(108379); +// +// debugIndexNumbers.add(105594); // fwdref is 105430 +// +// debugIndexNumbers.add(105444); + + // ********* NEXT SET ********** +// // big class +// debugIndexNumbers.add(105212); +// +// // member 2 (def) of big class (fwdref 105103) +// debugIndexNumbers.add(105444); +// +// // member 3 (def) of big class (fwdref 105104) +// debugIndexNumbers.add(105594); +// +// // base classes of 105444 (field list 105443) +// debugIndexNumbers.add(5251); // fwdref is 5072 +// debugIndexNumbers.add(105594); // fwdref is 105430 +// +// // first and only member of 5251 +// debugIndexNumbers.add(5051); // fwdref is 4505 + + // ********* NEXT SET ********** +// // big class +// debugIndexNumbers.add(7624); // fwdref is 7619 +// +// debugIndexNumbers.add(6116); // fwdref is 5956 +// +// debugIndexNumbers.add(6189); // fwdref is 6086 +// +// // base class of 6189 +// debugIndexNumbers.add(6236); // fwdref is 6168 +// +// // member of 6236 +// debugIndexNumbers.add(6251); // fwdref is 6220 +// +// // member of 6251 +// debugIndexNumbers.add(6263); // fwdref is 6237 +// +// // base class / member of 6263 +// debugIndexNumbers.add(6284); // fwdref is 6252 +// +// // base class / member of 6284 +// debugIndexNumbers.add(6328); // fwdref is 6264 +// +// // member of 6328 +// debugIndexNumbers.add(6335); // fwdref is 6285 +// +// // base class of 6335 +// debugIndexNumbers.add(6341); // fwdref is 6329 + } + + /** + * Developmental method for breakpoints. TODO: will delete this from production. + * @param recordNumber tmp (set negative to ignore) + */ + static void checkBreak(int recordNumber) { + if (debugIndexNumbers.contains(recordNumber)) { + int a = 1; + a = a + 1; + } + } + + /** + * Developmental method for breakpoints. TODO: will delete this from production. + * @param recordNumber tmp (set negative to ignore) + * @param applier tmp + */ + static void checkBreak(int recordNumber, AbstractMsTypeApplier applier) { + + String nn = applier.getMsType().getName(); + if ("std::__1::__map_value_compare,std::__1::__value_type,std::__1::basic_string >,std::__1::less,1>".equals( + nn)) { + int a = 1; + a = a + 1; + } + if ("class std::__1::__iostream_category".equals(nn)) { + int a = 1; + a = a + 1; + } + if ("std::__1::__do_message".equals(nn)) { + int a = 1; + a = a + 1; + } + + //checkBreak(recordNumber); + } + + //============================================================================================== + //============================================================================================== + private Set developerDebugOrderIndexNumbers; + + private void initDeveloperOrderRecordNumbers() { + developerDebugOrderIndexNumbers = new TreeSet<>(); + + // big class + developerDebugOrderIndexNumbers.add(105212); + + // member 2 (def) of big class (fwdref 105103) + developerDebugOrderIndexNumbers.add(105444); + + // member 3 (def) of big class (fwdref 105104) + developerDebugOrderIndexNumbers.add(105594); + + // base classes of 105444 (field list 105443) + developerDebugOrderIndexNumbers.add(5251); // fwdref is 5072 + developerDebugOrderIndexNumbers.add(105594); // fwdref is 105430 + + // first and only member of 5251 + developerDebugOrderIndexNumbers.add(5051); // fwdref is 4505 + } + + void developerDebugOrder(PdbApplicator applicator, TaskMonitor monitor) + throws CancelledException, PdbException { + initDeveloperOrderRecordNumbers(); + for (int indexNumber : developerDebugOrderIndexNumbers) { + monitor.checkCanceled(); + AbstractMsTypeApplier applier = + applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); + applier.apply(); + } + + } + + //============================================================================================== + //============================================================================================== + static void childWalk(PdbApplicator applicator, TaskMonitor monitor) + throws CancelledException, PdbException { + SymbolGroup symbolGroup = applicator.getSymbolGroup(); + GlobalSymbolInformation globalSymbolInformation = + applicator.getPdb().getDatabaseInterface().getGlobalSymbolInformation(); + List offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets(); + applicator.setMonitorMessage("PDB: Applying typedefs..."); + monitor.initialize(offsets.size()); + + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + for (long offset : offsets) { + monitor.checkCanceled(); + iter.initGetByOffset(offset); + if (!childWalkSym(applicator, symbolGroup.getModuleNumber(), iter)) { + break; + } + monitor.incrementProgress(1); + } + } + + static private boolean childWalkSym(PdbApplicator applicator, int moduleNumber, + AbstractMsSymbolIterator iter) throws PdbException, CancelledException { + if (!iter.hasNext()) { + return false; + } + AbstractMsSymbol symbol = iter.peek(); //temporary during development + AbstractMsSymbolApplier applier = applicator.getSymbolApplier(iter); + if (applier instanceof TypedefSymbolApplier) { + TypedefSymbolApplier typedefApplier = (TypedefSymbolApplier) applier; + AbstractMsTypeApplier typeApplier = + applicator.getTypeApplier(typedefApplier.getTypeRecordNumber()); + System.out.println("UDT " + typedefApplier.getName() + " depends on " + + typeApplier.getMsType().toString()); +// applier.apply(); +// procSym(symbolGroup); + } + else if (applier instanceof ReferenceSymbolApplier) { + ReferenceSymbolApplier refSymbolApplier = (ReferenceSymbolApplier) applier; + SymbolGroup refSymbolGroup = refSymbolApplier.getInitializedReferencedSymbolGroup(); + // recursion + childWalkSym(applicator, refSymbolGroup.getModuleNumber(), refSymbolGroup.iterator()); + } + else if (applier instanceof DataSymbolApplier) { + DataSymbolApplier dataSymbolApplier = (DataSymbolApplier) applier; + AbstractMsTypeApplier typeApplier = dataSymbolApplier.getTypeApplier(); + childWalkType(moduleNumber, typeApplier); + } + else if (applier instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applier; + functionSymbolApplier.getFunction(); +// AbstractMsTypeApplier typeApplier = functionSymbolApplier.getTypeApplier(); +// childWalkType(symbolGroup.getModuleNumber(), typeApplier); + } +// else if (applier instanceof ConstanctSymbolApplier) { +// ConstantSymbolApplier constantSymbolApplier = (ConstantSymbolApplier) applier; +// } + else { + int a = 1; + a = a + 1; + } + return true; + } + + //============================================================================================== + static private boolean childWalkType(int moduleNumber, AbstractMsTypeApplier applier) { + int b = 1; + b = b + 1; + if (applier instanceof AbstractFunctionTypeApplier) { + int a = 1; + a = a + 1; + } + return true; + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + static void studyDataTypeConflicts(PdbApplicator applicator, TaskMonitor monitor) { + DataTypeConflictHandler handler = + DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER; + DataTypeManager dtm = applicator.getDataTypeManager(); + + // First set + Composite testStruct1 = createComposite(dtm, "____blah____"); + Pointer pointer1 = new PointerDataType(testStruct1, -1, dtm); + + FunctionDefinitionDataType fn1 = + new FunctionDefinitionDataType(CategoryPath.ROOT, "____fn1____", dtm); + fn1.setReturnType(pointer1); + fn1.setGenericCallingConvention(GenericCallingConvention.cdecl); + fn1.setArguments(new ParameterDefinition[0]); + + Composite internalStruct1 = createComposite(dtm, "____internal____"); + Pointer internalPointer1 = new PointerDataType(internalStruct1, -1, dtm); + + fillComposite(testStruct1, monitor, internalPointer1); + fillComposite(internalStruct1, monitor, null); + + // Second set + Composite testStruct2 = createComposite(dtm, "____blah____"); + Pointer pointer2 = new PointerDataType(testStruct2, -1, dtm); + + FunctionDefinitionDataType fn2 = + new FunctionDefinitionDataType(CategoryPath.ROOT, "____fn2____", dtm); + fn2.setReturnType(pointer2); + fn2.setGenericCallingConvention(GenericCallingConvention.cdecl); + fn2.setArguments(new ParameterDefinition[0]); + + Composite internalStruct2 = createComposite(dtm, "____internal____"); + Pointer internalPointer2 = new PointerDataType(internalStruct2, -1, dtm); + + fillComposite(testStruct2, monitor, internalPointer2); +// fillComposite(internalStruct2, monitor, null); + + // Resolve + DataType t1 = dtm.resolve(testStruct1, handler); + DataType f1 = dtm.resolve(fn1, handler); + + DataType t2 = dtm.resolve(testStruct2, handler); + DataType f2 = dtm.resolve(fn2, handler); + + PdbLog.message(t1.toString()); + PdbLog.message(f1.toString()); + PdbLog.message(t2.toString()); + PdbLog.message(f2.toString()); + } + + private static Composite createComposite(DataTypeManager dtm, String name) { + Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm); + return composite; + } + + private static void fillComposite(Composite composite, TaskMonitor monitor, DataType extra) { + List members = new ArrayList<>(); + DefaultTestPdbMember member; + int size = 8; + DataType intxy = IntegerDataType.dataType; + member = new DefaultTestPdbMember("x", intxy, 0); + members.add(member); + member = new DefaultTestPdbMember("y", intxy, 4); + members.add(member); + if (extra != null) { + member = new DefaultTestPdbMember("z", extra, 8); + members.add(member); + size += extra.getLength(); + } + try { + if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, size, members, + msg -> reconstructionWarn(msg), monitor)) { + ((Structure) composite).deleteAll(); + } + } + catch (Exception e) { + Msg.info(null, "Research exception thrown"); + } + } + + private static void reconstructionWarn(String msg) { + Msg.warn(null, msg); + } + + private static class DefaultTestPdbMember extends PdbMember { + + private DataType dataType; + + /** + * Default PDB member construction + * @param name member field name. + * @param dataType for the field. + * @param offset member's byte offset within the root composite. + */ + DefaultTestPdbMember(String name, DataType dataType, int offset) { + super(name, dataType.getName(), offset, null); + this.dataType = dataType; + } + + @Override + public String getDataTypeName() { + return dataType.getName(); + } + + @Override + protected WrappedDataType getDataType() throws CancelledException { + if (dataType instanceof ArrayDataType) { + int size = 1; // mocking for now + if (size == 0) { + return new WrappedDataType(dataType, true, false); + } + } + return new WrappedDataType(dataType, false, false); + } + + } + + //============================================================================================== + //============================================================================================== + /* + * Studying names of functions where they might involve function definition + * reuse caused by Templates and/or Identical Code Folding. + */ + static void studyAggregateSymbols(PdbApplicator applicator, TaskMonitor monitor) + throws CancelledException { + Map> mapByAddress = new HashMap<>(); + processPublicSymbols(applicator, mapByAddress, monitor); + processGlobalSymbols(applicator, mapByAddress, monitor); + processModuleSymbols(applicator, mapByAddress, monitor); + dumpMap(mapByAddress); + } + + private static void processPublicSymbols(PdbApplicator applicator, + Map> map, TaskMonitor monitor) throws CancelledException { + AbstractPdb pdb = applicator.getPdb(); + SymbolGroup symbolGroup = applicator.getSymbolGroup(); + + PublicSymbolInformation publicSymbolInformation = + pdb.getDatabaseInterface().getPublicSymbolInformation(); + List offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets(); + applicator.setMonitorMessage( + "PDB: Applying " + offsets.size() + " public symbol components..."); + monitor.initialize(offsets.size()); + + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + for (long offset : offsets) { + monitor.checkCanceled(); + iter.initGetByOffset(offset); + if (!iter.hasNext()) { + break; + } + AbstractMsSymbol symbol = iter.peek(); + //applicator.getPdbApplicatorMetrics().witnessPublicSymbolType(symbol); + processPublicSymbol(applicator, map, symbol); + processProcedureSymbol(applicator, map, symbol); + monitor.incrementProgress(1); + } + } + + private static void processGlobalSymbols(PdbApplicator applicator, + Map> map, TaskMonitor monitor) throws CancelledException { + AbstractPdb pdb = applicator.getPdb(); + SymbolGroup symbolGroup = applicator.getSymbolGroup(); + + GlobalSymbolInformation globalSymbolInformation = + pdb.getDatabaseInterface().getGlobalSymbolInformation(); + List offsets = globalSymbolInformation.getModifiedHashRecordSymbolOffsets(); + applicator.setMonitorMessage("PDB: Applying global symbols..."); + monitor.initialize(offsets.size()); + + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + for (long offset : offsets) { + monitor.checkCanceled(); + iter.initGetByOffset(offset); + if (!iter.hasNext()) { + break; + } + AbstractMsSymbol symbol = iter.peek(); + //applicator.getPdbApplicatorMetrics().witnessGlobalSymbolType(symbol); + processPublicSymbol(applicator, map, symbol); + processProcedureSymbol(applicator, map, symbol); + monitor.incrementProgress(1); + } + } + + private static void processModuleSymbols(PdbApplicator applicator, + Map> map, TaskMonitor monitor) throws CancelledException { + AbstractPdb pdb = applicator.getPdb(); + int totalCount = 0; + int num = pdb.getDatabaseInterface().getNumModules(); + for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) { + monitor.checkCanceled(); + SymbolGroup symbolGroup = applicator.getSymbolGroupForModule(moduleNumber); + if (symbolGroup == null) { + continue; + } + totalCount += symbolGroup.size(); + } + applicator.setMonitorMessage( + "PDB: Applying " + totalCount + " module symbol components..."); + monitor.initialize(totalCount); + + // Process symbols list for each module + for (int moduleNumber = 1; moduleNumber <= num; moduleNumber++) { + monitor.checkCanceled(); + +// String moduleName = +// pdb.getDatabaseInterface().getModuleInformation(index).getModuleName(); + + // Process module symbols list + SymbolGroup symbolGroup = applicator.getSymbolGroupForModule(moduleNumber); + if (symbolGroup == null) { + continue; + } + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + processSymbolGroup(applicator, map, moduleNumber, iter, monitor); + // do not call monitor.incrementProgress(1) here, as it is updated inside of + // processSymbolGroup. + } + } + + private static void processSymbolGroup(PdbApplicator applicator, Map> map, + int moduleNumber, AbstractMsSymbolIterator iter, TaskMonitor monitor) + throws CancelledException { + iter.initGet(); + while (iter.hasNext()) { + monitor.checkCanceled(); + AbstractMsSymbol symbol = iter.next(); + if (symbol != null) { + processPublicSymbol(applicator, map, symbol); + processProcedureSymbol(applicator, map, symbol); + } + monitor.incrementProgress(1); + } + } + + private static void processPublicSymbol(PdbApplicator applicator, Map> map, + AbstractMsSymbol symbol) { + Stuff stuff; + if (!(symbol instanceof AbstractPublicMsSymbol)) { + return; + } + // If it can be known and determined to not be a function, then return. + if (symbol instanceof AbstractPublic32MsSymbol && + !((AbstractPublic32MsSymbol) symbol).isFunction()) { + return; + } + Address address = applicator.reladdr((AbstractPublicMsSymbol) symbol); + String name = ((AbstractPublicMsSymbol) symbol).getName(); + String demangledName = getDemangledQualifiedName(name); + if (demangledName != null) { + stuff = new Stuff(symbol, demangledName, What.PUBLIC_QUAL_FROM_MANGLED); + } + else { + stuff = new Stuff(symbol, name, What.PUBLIC_NOT_MANGLED); + } + addStuff(map, address, stuff); + } + + private static void processProcedureSymbol(PdbApplicator applicator, + Map> map, AbstractMsSymbol symbol) { + if (symbol instanceof AbstractProcedureMsSymbol) { + Address address = applicator.reladdr((AbstractProcedureMsSymbol) symbol); + String name = ((AbstractProcedureMsSymbol) symbol).getName(); + Stuff stuff = new Stuff(symbol, name, What.GLOBAL); + addStuff(map, address, stuff); + } + } + + private static void addStuff(Map> map, Address address, Stuff stuff) { + List list = map.get(address); + if (list == null) { + list = new ArrayList<>(); + map.put(address, list); + } + list.add(stuff); + } + + private static void dumpMap(Map> map) { + for (Map.Entry> entry : map.entrySet()) { + Address address = entry.getKey(); + List list = entry.getValue(); + for (Stuff stuff : list) { + PdbLog.message(address + " " + stuff.getWhat() + " " + stuff.getName()); + } + } + } + + /** + * Gets a demangles the name and returns the qualified name. Returns null if not mangled + * or if error in demangling. + * @param mangledString the mangled string to be decoded + * @return the qualified name of the demangled string or null if not mangled or error. + */ + private static String getDemangledQualifiedName(String mangledString) { + if (mangledString.charAt(0) != '?') { + return null; + } + MDMangGhidra demangler = new MDMangGhidra(); + try { + MDParsableItem parsableItem = demangler.demangle(mangledString, true); + if (parsableItem instanceof MDObjectCPP) { + MDObjectCPP mdObject = (MDObjectCPP) parsableItem; + return mdObject.getQualifiedName().toString(); + } + return parsableItem.toString(); + } + catch (MDException e) { + // Couldn't demangle. + Msg.info(null, e.getMessage()); + return null; + } + } + + //---------------------------------------------------------------------------------------------- + private static enum What { + PUBLIC_NOT_MANGLED, PUBLIC_QUAL_FROM_MANGLED, GLOBAL + } + + private static class Stuff { + AbstractMsSymbol symbol; + String name; + What what; + + Stuff(AbstractMsSymbol symbol, String name, What what) { + this.symbol = symbol; + this.name = name; + this.what = what; + } + + AbstractMsSymbol getSymbol() { + return symbol; + } + + String getName() { + return name; + } + + What getWhat() { + return what; + } + } + + //============================================================================================== + //============================================================================================== + static void studyCompositeFwdRefDef(AbstractPdb pdb, TaskMonitor monitor) + throws CancelledException { + int indexNumber = pdb.getTypeProgramInterface().getTypeIndexMin(); + int indexLimit = pdb.getTypeProgramInterface().getTypeIndexMaxExclusive(); + int num = indexLimit - indexNumber; + boolean covered[] = new boolean[indexLimit]; + + monitor.initialize(num); + monitor.setMessage("Study: NAMES_START " + (indexLimit - indexNumber)); + PdbLog.message("STUDY_START: studyCompositeFwdRefDef"); + //System.out.println("STUDY_START"); + while (indexNumber < indexLimit) { + monitor.checkCanceled(); + if (!covered[indexNumber]) { + AbstractMsType type = pdb.getTypeRecord(RecordNumber.typeRecordNumber(indexNumber)); + covered[indexNumber] = true; + String name = getSpecialRecordStart(type); + if (name != null) { + MsProperty p; + String ps; + int c; + boolean isFwdRef = false; + Map> map = new HashMap<>(); + if (type instanceof AbstractCompositeMsType) { + AbstractCompositeMsType compType = (AbstractCompositeMsType) type; + c = compType.getNumElements(); + p = compType.getMsProperty(); + isFwdRef = p.isForwardReference(); + if (c == 0 && !isFwdRef) { + int a = 1; + a = a + 1; + // For PDBs that we have looked at, if count is zero + // for a fwdref, then the field list record number is zero; + // if count is zero for a def, then, the field list record + // number refers to an actual field list. + // So... seems we can trust fwdref and ignore count. + if (compType.getFieldDescriptorListRecordNumber() == RecordNumber.NO_TYPE) { + int b = 1; + b = b + 1; + } + } + else if (c != 0 && isFwdRef) { + int a = 1; + a = a + 1; + } +// ps = c + (p.isForwardReference() ? "fwdref" : ""); + } + else { //type instanceof AbstractEnumMsType + AbstractEnumMsType enumType = (AbstractEnumMsType) type; + c = 0; // made up. +// p = enumType.getMsProperty(); +// ps = p.toString(); + } + ps = type.toString(); + Set set = new HashSet<>(); + set.add(ps); + map.put(c, set); + PdbLog.message("----------\n" + name + "\n" + c + (isFwdRef ? " fwdref" : "")); + //System.out.println("----------\n" + name + "\n" + c); + int innerIndexNumber = indexNumber + 1; + while (innerIndexNumber < indexLimit) { + monitor.checkCanceled(); + if (!covered[innerIndexNumber]) { + AbstractMsType innerType = + pdb.getTypeRecord(RecordNumber.typeRecordNumber(innerIndexNumber)); + String innerName = getSpecialRecordStart(innerType); + if (name.equals(innerName)) { + covered[innerIndexNumber] = true; + isFwdRef = false; + if (type instanceof AbstractCompositeMsType) { + AbstractCompositeMsType compType = + (AbstractCompositeMsType) innerType; + c = compType.getNumElements(); + p = compType.getMsProperty(); + isFwdRef = p.isForwardReference(); + if (c == 0 && !isFwdRef) { + // For PDBs that we have looked at, if count is zero + // for a fwdref, then the field list record number is zero; + // if count is zero for a def, then, the field list record + // number refers to an actual field list. + // So... seems we can trust fwdref and ignore count. + if (compType.getFieldDescriptorListRecordNumber() == RecordNumber.NO_TYPE) { + int a = 1; + a = a + 1; + } + } + else if (c != 0 && isFwdRef) { + int a = 1; + a = a + 1; + } +// ps = c + (p.isForwardReference() ? "fwdref" : ""); + } + else { //type instanceof AbstractEnumMsType + AbstractEnumMsType enumType = (AbstractEnumMsType) type; + c = 0; // made up. +// p = enumType.getMsProperty(); +// ps = "" + c; + } + String psi = innerType.toString(); + set = map.get(c); + String message = ""; + if (set == null) { + set = new HashSet<>(); + map.put(c, set); + set.add(psi); + } + else if (!set.contains(psi)) { // conflict + message = " <-- conflict"; + set.add(psi); + } + else { + message = " <-- repeat"; + } + PdbLog.message(c + (isFwdRef ? " fwdref" : "") + message); + if (c == 0 && isFwdRef) { + PdbLog.message("Orig: " + ps + "\nNew: " + psi); + } + //System.out.println(c + message); + } + } + innerIndexNumber++; + } + } + + } + indexNumber++; + monitor.incrementProgress(1); + } + PdbLog.message("STUDY_END: studyCompositeFwdRefDef"); + //System.out.println("STUDY_END"); + } + + private static String getSpecialRecordStart(AbstractMsType type) { + if (!((type instanceof AbstractCompositeMsType || type instanceof AbstractEnumMsType))) { + return null; + } + + String name; + if (type instanceof AbstractCompositeMsType) { + AbstractCompositeMsType compType = (AbstractCompositeMsType) type; + if (compType instanceof AbstractClassMsType) { + name = "class " + compType.getName(); + } + else if (compType instanceof AbstractStructureMsType) { + name = "struct " + compType.getName(); + } + else if (compType instanceof AbstractUnionMsType) { + name = "union " + compType.getName(); + } + else { + name = "interface " + compType.getName(); + } + } + else { //type instanceof AbstractEnumMsType + AbstractEnumMsType enumType = (AbstractEnumMsType) type; + name = "enum " + enumType.getName(); + } + return name; + } + + //============================================================================================== + //============================================================================================== + static void study1(AbstractPdb pdb, TaskMonitor monitor) throws CancelledException { + int indexNumber = pdb.getTypeProgramInterface().getTypeIndexMin(); + int indexLimit = pdb.getTypeProgramInterface().getTypeIndexMaxExclusive(); + + Set uniqueNames = new HashSet<>(); + List orderedNames = new ArrayList<>(); + List orderedRecords = new ArrayList<>(); + + monitor.initialize(indexLimit - indexNumber); + monitor.setMessage("Study: NAMES_START"); + while (indexNumber < indexLimit) { + monitor.checkCanceled(); + String name; + String record; + AbstractMsType type = pdb.getTypeRecord(RecordNumber.typeRecordNumber(indexNumber)); + if (type instanceof AbstractCompositeMsType || type instanceof AbstractEnumMsType) { + if (type instanceof AbstractCompositeMsType) { + AbstractCompositeMsType compType = (AbstractCompositeMsType) type; + if (compType instanceof AbstractClassMsType) { + name = "class " + compType.getName(); + } + else if (compType instanceof AbstractStructureMsType) { + name = "struct " + compType.getName(); + } + else if (compType instanceof AbstractUnionMsType) { + name = "union " + compType.getName(); + } + else { + name = "interface " + compType.getName(); + } + record = compType.toString(); + } + else { //type instanceof AbstractEnumMsType + AbstractEnumMsType enumType = (AbstractEnumMsType) type; + name = "enum " + enumType.getName(); + record = enumType.toString(); + } + if (!uniqueNames.contains(name)) { + uniqueNames.add(name); + orderedNames.add(name); + } + orderedRecords.add(record); + } + indexNumber++; + monitor.incrementProgress(1); + } + + System.out.println("DUMP_START"); + monitor.setMessage("Study: DUMP_START"); + monitor.initialize(orderedNames.size()); + for (String name : orderedNames) { + for (String record : orderedRecords) { + monitor.checkCanceled(); + if (record.startsWith(name)) { + System.out.println(record); + } + } + System.out.println("----------"); + monitor.incrementProgress(1); + } + System.out.println("DUMP_END"); + + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java new file mode 100644 index 0000000000..ced7569115 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java @@ -0,0 +1,233 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.*; + +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.DataTypeManager; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Manages virtual base table lookup for PDB classes. + */ + +public class PdbVbtManager extends VbtManager { + + Map addressByMangledName; + Memory memory; + + private static Memory getMemory(PdbApplicator applicator) throws PdbException { + Program program = applicator.getProgram(); + if (program == null) { + throw new PdbException("Program null for VbtManager"); + } + return program.getMemory(); + } + + // TODO: Research whether we ever find VBT symbols put into the program by the "loader." + // If we find some this way, then need to modify PdbVbtManager to also look + // through the loader symbol for them. + private static Map findVirtualBaseTableSymbols(PdbApplicator applicator) + throws CancelledException { + + TaskMonitor monitor = applicator.getMonitor(); + SymbolGroup symbolGroup = applicator.getSymbolGroup(); + Map myAddressByMangledName = new HashMap<>(); + + PublicSymbolInformation publicSymbolInformation = + applicator.getPdb().getDatabaseInterface().getPublicSymbolInformation(); + List offsets = publicSymbolInformation.getModifiedHashRecordSymbolOffsets(); + applicator.setMonitorMessage("PDB: Searching for virtual base table symbols..."); + monitor.initialize(offsets.size()); + + AbstractMsSymbolIterator iter = symbolGroup.iterator(); + for (long offset : offsets) { + monitor.checkCanceled(); + iter.initGetByOffset(offset); + if (!iter.hasNext()) { + break; + } + AbstractMsSymbol symbol = iter.peek(); + if (symbol instanceof AbstractPublicMsSymbol) { + AbstractPublicMsSymbol pubSymbol = (AbstractPublicMsSymbol) symbol; + String name = pubSymbol.getName(); + if (name.startsWith("??_8")) { + Address address = applicator.reladdr(pubSymbol); + myAddressByMangledName.put(name, address); + } + } + monitor.incrementProgress(1); + } + return myAddressByMangledName; + } + + /** + * Virtual Base Table Lookup Manager + * @param applicator {@link PdbApplicator} for which this class is working. + * @throws PdbException If Program is null; + * @throws CancelledException upon user cancellation + */ + PdbVbtManager(PdbApplicator applicator) throws PdbException, CancelledException { + this(applicator.getDataTypeManager(), getMemory(applicator), + findVirtualBaseTableSymbols(applicator)); + } + + PdbVbtManager(DataTypeManager dataTypeManager, Memory memory, + Map addressByMangledName) { + super(dataTypeManager); + this.memory = memory; + this.addressByMangledName = addressByMangledName; + } + +// /** +// * Builds the tables +// * @throws PdbException If Program is null; +// * @throws CancelledException upon user cancellation. +// */ +// void CreateVirtualBaseTables() throws PdbException, CancelledException { +// createVirtualBaseTables(); +// } +// + PdbVirtualBaseTable createVirtualBaseTableByName(String mangledName, int entrySize) { + Address address = addressByMangledName.get(mangledName); + if (address == null) { + return null; + //throw new PdbException("Cannot find address for table name: " + mangledName); + } + return createVirtualBaseTable(address, entrySize); + } + + PdbVirtualBaseTable createVirtualBaseTable(Address address, int entrySize) { + + VirtualBaseTable vbt = vbtByAddress.get(address); + if (vbt != null) { + String message = + "PDB: warning virtual base table already exists for address: " + address; + PdbLog.message(message); + Msg.info(this, message); + } + else { + vbt = new PdbVirtualBaseTable(memory, address, entrySize); + vbtByAddress.put(address, vbt); + } + if (!(vbt instanceof PdbVirtualBaseTable)) { + int a = 1; + a = a + 1; + } + return (PdbVirtualBaseTable) vbt; + } + + /** + * Returns offset for vbtable (mangled name) and ordinal + * @param vbtMangledName mangled name of vbtable + * @param ordinal index into table + * @param size size of a vbt entry offset value + * @return the offset + * @throws PdbException if no address exists for mangled name + */ + long getOffset(String vbtMangledName, int ordinal, int size) throws PdbException { + Address address = addressByMangledName.get(vbtMangledName); + if (address == null) { + throw new PdbException( + "Virtual Base Table does not exist for symbol: " + vbtMangledName); + } + return getOffset(address, ordinal, size); + } + + /** + * Returns the offset from the virtual base table entry + * @param address Address of virtual base table + * @param ordinal index into table + * @param size size of a vbt entry offset value + * @return the offset + * @throws PdbException if no table exists for address or no entry exists for ordinal + */ + long getOffset(Address address, int ordinal, int size) throws PdbException { + VirtualBaseTable table = vbtByAddress.get(address); + if (table == null) { + throw new PdbException("Virtual Base Table does not exist for address: " + address); + } + if (!(table instanceof PdbVirtualBaseTable)) { + throw new PdbException("Not a PDB Virtual Base Table for address: " + address); + } + VirtualBaseTableEntry entry = + ((PdbVirtualBaseTable) table).getOrParseEntryByOrdinal(ordinal); + return entry.getOffset(); + } + + private void createVirtualBaseTables() { + for (Map.Entry entry : addressByMangledName.entrySet()) { + Address address = entry.getValue(); + createVirtualBaseTable(address); + } + } + + static VirtualBaseTableEntry parseVbtEntryFromMemory(Memory memory, Address address, + int ordinal, int size) throws PdbException { + if (size != 4 && size != 8) { + throw new IllegalArgumentException("Invalid size (" + size + "): must be 4 or 8."); + } + Address readAddress = address.add(ordinal * size); + long offset; + try { + offset = (size == 4) ? (long) memory.getInt(readAddress) : memory.getLong(readAddress); + } + catch (MemoryAccessException e) { + throw new PdbException( + "MemoryAccessException while trying to parse virtual base table entry at address: " + + readAddress); + } + return new VirtualBaseTableEntry(offset); + } + + static class PdbVirtualBaseTable extends VirtualBaseTable { + private Memory memory; + private Address address; + private int entrySize; + + PdbVirtualBaseTable(Memory memory, Address address, int entrySize) { + super(); + this.memory = memory; + this.address = address; + this.entrySize = entrySize; + } + + @Override + VirtualBaseTableEntry getEntry(int ordinal) throws PdbException { + return getOrParseEntryByOrdinal(ordinal); + //return entryByOrdinal.get(ordinal); + } + + VirtualBaseTableEntry getOrParseEntryByOrdinal(int ordinal) throws PdbException { + VirtualBaseTableEntry entry = entryByOrdinal.get(ordinal); + if (entry == null) { + entry = parseVbtEntryFromMemory(memory, address, ordinal, entrySize); + addEntry(ordinal, entry); + } + return entry; + } + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java new file mode 100644 index 0000000000..f0ec178c95 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java @@ -0,0 +1,66 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.PeCoffGroupMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link PeCoffGroupMsSymbol} symbols. + */ +public class PeCoffGroupSymbolApplier extends AbstractMsSymbolApplier { + + private PeCoffGroupMsSymbol symbol; + + public PeCoffGroupSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof PeCoffGroupMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (PeCoffGroupMsSymbol) abstractSymbol; + } + + @Override + public void apply() throws PdbException, CancelledException { + applicator.addMemoryGroupRefinement(symbol); + Address symbolAddress = applicator.reladdr(symbol); + if (!Address.NO_ADDRESS.equals(symbolAddress)) { + boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); + String name = symbol.getName(); + symbol.getLength(); + symbol.getCharacteristics(); + if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { + applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); + } + } + else { +// monitor.setMessage("Skipping NO_ADDRESS symbol " + symb.getName() + "..."); + } + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java new file mode 100644 index 0000000000..1f7f011ce9 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java @@ -0,0 +1,58 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.PeCoffSectionMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link PeCoffSectionMsSymbol} symbols. + */ +public class PeCoffSectionSymbolApplier extends AbstractMsSymbolApplier { + + private PeCoffSectionMsSymbol symbol; + + public PeCoffSectionSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof PeCoffSectionMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (PeCoffSectionMsSymbol) abstractSymbol; + } + + @Override + public void apply() throws PdbException, CancelledException { + int sectionNum = symbol.getSectionNumber(); + long realAddress = symbol.getRva(); + symbol.getLength(); + symbol.getCharacteristics(); + symbol.getAlign(); + symbol.getName(); + applicator.putRealAddressesBySection(sectionNum, realAddress); + applicator.addMemorySectionRefinement(symbol); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java new file mode 100644 index 0000000000..a5944bb518 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java @@ -0,0 +1,119 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +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.*; +import ghidra.program.model.data.*; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractPointerMsType} types. + */ +public class PointerTypeApplier extends AbstractMsTypeApplier { + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractPointerMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + PointerTypeApplier.class.getSimpleName()); + } + return type; + } + + private boolean isFunctionPointer = false; + + /** + * Constructor for pointer type applier, for transforming a enum into a + * Ghidra DataType. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractPointerMsType} to process + * @throws IllegalArgumentException Upon invalid arguments. + */ + public PointerTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + public boolean isFunctionPointer() { + return isFunctionPointer; + } + + @Override + public BigInteger getSize() { + return ((AbstractPointerMsType) msType).getSize(); + } + + @Override + public void apply() throws PdbException, CancelledException { + if (msType instanceof DummyMsType) { + dataType = new PointerDataType(applicator.getDataTypeManager()); + } + else { + dataType = applyAbstractPointerMsType((AbstractPointerMsType) msType); + } + } + + @Override + public void resolve() { + // Do not resolve pointer types... will be resolved naturally, as needed + } + + public AbstractMsTypeApplier getUnmodifiedUnderlyingTypeApplier() { + AbstractMsTypeApplier thisUnderlyingTypeApplier = + applicator.getTypeApplier(((AbstractPointerMsType) msType).getUnderlyingRecordNumber()); + + // TODO: does not recurse below one level of modifiers... consider doing a recursion. + if (thisUnderlyingTypeApplier instanceof ModifierTypeApplier) { + ModifierTypeApplier x = (ModifierTypeApplier) thisUnderlyingTypeApplier; + RecordNumber recNum = + ((AbstractModifierMsType) (x.getMsType())).getModifiedRecordNumber(); + thisUnderlyingTypeApplier = applicator.getTypeApplier(recNum); + } + return thisUnderlyingTypeApplier; + } + + private DataType applyAbstractPointerMsType(AbstractPointerMsType type) { + AbstractMsTypeApplier underlyingApplier = + applicator.getTypeApplier(type.getUnderlyingRecordNumber()); + + if (underlyingApplier instanceof ProcedureTypeApplier) { + isFunctionPointer = true; + } + + //DataType underlyingType = underlyingApplier.getCycleBreakType(); // out 20191211 + DataType underlyingType = underlyingApplier.getCycleBreakType(); + if (underlyingType == null) { + // TODO: we have seen underlyingTypeApplier is for NoTypeApplier for VtShapeMsType + // Figure it out, and perhaps create an applier that creates a structure or something? + return new VoidDataType(applicator.getDataTypeManager()); +// throw new PdbException("Underlying type missing for pointer."); + } + + int size = getSizeInt(); + if (size == applicator.getDataOrganization().getPointerSize()) { + size = -1; // Use default + } + Pointer pointer = + new PointerDataType(underlyingType, size, applicator.getDataTypeManager()); + return pointer; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java new file mode 100644 index 0000000000..9ea7c26dc9 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java @@ -0,0 +1,2079 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType; +import ghidra.program.model.data.DataType; + +/** + * Applier for {@link PrimitiveMsType} types. + */ +public class PrimitiveTypeApplier extends AbstractMsTypeApplier { + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof PrimitiveMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + PrimitiveTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for primitive type applier, for transforming a primitive into a + * Ghidra DataType. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link PrimitiveMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public PrimitiveTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + apply(); // Only apply in constructor for primitives + } + + @Override + public BigInteger getSize() { + return BigInteger.valueOf(((PrimitiveMsType) msType).getTypeSize()); + } + + @Override + public void apply() { + dataType = applyPrimitiveMsType((PrimitiveMsType) msType); + } + + public boolean isNoType() { + return (((PrimitiveMsType) msType).getNumber() == 0); + } + + private DataType applyPrimitiveMsType(PrimitiveMsType type) { + DataType primitiveDataType = null; +// String name = type.getName(); +// +// DataTypeManager applicatorDataTypeManager = applicator.getDataTypeManager(); +// DataTypeManager builtInDataTypeManager = BuiltInDataTypeManager.getDataTypeManager(); +// DataType dataType = +// builtInDataTypeManager.getDataType(new DataTypePath(CategoryPath.ROOT, name)); +// if (dataType != null) { +// return dataType.clone(applicatorDataTypeManager); +// } + + PdbPrimitiveTypeApplicator primitiveApplicator = applicator.getPdbPrimitiveTypeApplicator(); + + switch (type.getNumber()) { + //======================================= + // Special types + //======================================= + // No Type (uncharacterized type) + case 0x0000: + primitiveDataType = primitiveApplicator.getNoType(type); + break; + // Absolute symbol + case 0x0001: + primitiveDataType = primitiveApplicator.getNoType(type); + break; + // Segment type + case 0x0002: + primitiveDataType = primitiveApplicator.getNoType(type); + break; + // Void type + case 0x0003: + primitiveDataType = primitiveApplicator.getVoidType(); + break; + // Near pointer to void + case 0x0103: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.getVoidType()); + break; + // Far pointer to void + case 0x0203: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.getVoidType()); + break; + // Huge pointer to void + case 0x0303: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.getVoidType()); + break; + // 32-bit pointer to void + case 0x0403: + primitiveDataType = + primitiveApplicator.get32PointerType(type, primitiveApplicator.getVoidType()); + break; + // 16:32 pointer to void + case 0x0503: + primitiveDataType = + primitiveApplicator.get1632PointerType(type, primitiveApplicator.getVoidType()); + break; + // 64-bit pointer to void + case 0x0603: + primitiveDataType = + primitiveApplicator.get64PointerType(type, primitiveApplicator.getVoidType()); + break; + // 128-bit near pointer to void (LLVM doc on 0x0700) + case 0x0703: + primitiveDataType = + primitiveApplicator.get128PointerType(type, primitiveApplicator.getVoidType()); + break; + // BASIC 8 byte currency value + case 0x0004: + primitiveDataType = primitiveApplicator.createTypedefNamedSizedType(type); + break; + // Near BASIC string + case 0x0005: + primitiveDataType = primitiveApplicator.createUnmappedPdbType(type); + break; + // Far BASIC string + case 0x0006: + primitiveDataType = primitiveApplicator.createUnmappedPdbType(type); + break; + // Type not translated by cvpack + case 0x0007: + primitiveDataType = primitiveApplicator.createUnmappedPdbType(type); + break; + // OLE/COM HRESULT + case 0x0008: + primitiveDataType = primitiveApplicator.createTypedefNamedSizedType(type); + break; + // OLE/COM HRESULT __ptr32 * + case 0x0408: // TODO: Make true pointer version + primitiveDataType = primitiveApplicator.createTypedefNamedSizedType(type); + break; + // OLE/COM HRESULT __ptr64 * + case 0x0608: // TODO: Make true pointer version + primitiveDataType = primitiveApplicator.createTypedefNamedSizedType(type); + break; + // OLE/COM HRESULT __ptr128 * + case 0x0708: // TODO: Make true pointer version + primitiveDataType = primitiveApplicator.createTypedefNamedSizedType(type); + break; + // bit + case 0x0060: + primitiveDataType = primitiveApplicator.createUnmappedPdbType(type); + break; + // Pascal CHAR + case 0x0061: + primitiveDataType = primitiveApplicator.createUnmappedPdbType(type); + break; + // 32-bit BOOL where true is 0xffffffff + case 0x0062: + primitiveDataType = + primitiveApplicator.createTypedefNamedSizedType("T_BOOL32FF", 4); + break; + + //======================================= + // Signed Character types + //======================================= + // 8-bit signed + case 0x0010: + primitiveDataType = primitiveApplicator.getSignedCharType(); + break; + // 16-bit pointer to an 8-bit signed + case 0x0110: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.getSignedCharType()); + break; + // 16:16 far pointer to an 8-bit signed + case 0x0210: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.getSignedCharType()); + break; + // 16:16 huge pointer to an 8-bit signed + case 0x0310: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.getSignedCharType()); + break; + // 32-bit pointer to an 8-bit signed + case 0x0410: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.getSignedCharType()); + break; + // 16:32 pointer to an 8-bit signed + case 0x0510: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.getSignedCharType()); + break; + // 64-bit pointer to an 8-bit signed + case 0x0610: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.getSignedCharType()); + break; + // 128-bit near pointer to an 8-bit signed (LLVM doc on 0x0700) + case 0x0710: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.getSignedCharType()); + break; + + //======================================= + // Unsigned Character types + //======================================= + // 8-bit unsigned + case 0x0020: + primitiveDataType = primitiveApplicator.getUnsignedCharType(); + break; + // 16-bit pointer to an 8-bit unsigned + case 0x0120: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.getUnsignedCharType()); + break; + // 16:16 far pointer to an 8-bit unsigned + case 0x0220: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.getUnsignedCharType()); + break; + // 16:16 huge pointer to an 8-bit unsigned + case 0x0320: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.getUnsignedCharType()); + break; + // 32-bit pointer to an 8-bit unsigned + case 0x0420: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.getUnsignedCharType()); + break; + // 16:32 pointer to an 8-bit unsigned + case 0x0520: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.getUnsignedCharType()); + break; + // 64-bit pointer to an 8-bit unsigned + case 0x0620: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.getUnsignedCharType()); + break; + // 128-bit near pointer to an 8-bit unsigned (LLVM doc on 0x0700) + case 0x0720: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.getUnsignedCharType()); + break; + + //======================================= + // Real character types + //======================================= + // a real char + case 0x0070: + primitiveDataType = primitiveApplicator.getCharType(); + break; + // 16-bit pointer to a real char + case 0x0170: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.getCharType()); + break; + // 16:16 far pointer to a real char + case 0x0270: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.getCharType()); + break; + // 16:16 huge pointer to a real char + case 0x0370: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.getCharType()); + break; + // 32-bit pointer to a real char + case 0x0470: + primitiveDataType = + primitiveApplicator.get32PointerType(type, primitiveApplicator.getCharType()); + break; + // 16:32 pointer to a real char + case 0x0570: + primitiveDataType = + primitiveApplicator.get1632PointerType(type, primitiveApplicator.getCharType()); + break; + // 64-bit pointer to a real char + case 0x0670: + primitiveDataType = + primitiveApplicator.get64PointerType(type, primitiveApplicator.getCharType()); + break; + // 128-bit near pointer to a real char (LLVM doc on 0x0700) + case 0x0770: + primitiveDataType = + primitiveApplicator.get128PointerType(type, primitiveApplicator.getCharType()); + break; + + //======================================= + // Really a wide character types + //======================================= + // wide char + case 0x0071: + primitiveDataType = primitiveApplicator.getWideCharType(); + break; + // 16-bit pointer to a wide char + case 0x0171: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.getWideCharType()); + break; + // 16:16 far pointer to a wide char + case 0x0271: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.getWideCharType()); + break; + // 16:16 huge pointer to a wide char + case 0x0371: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.getWideCharType()); + break; + // 32-bit pointer to a wide char + case 0x0471: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.getWideCharType()); + break; + // 16:32 pointer to a wide char + case 0x0571: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.getWideCharType()); + break; + // 64-bit pointer to a wide char + case 0x0671: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.getWideCharType()); + break; + // 128-bit near pointer to a wide char (LLVM doc on 0x0700) + case 0x0771: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.getWideCharType()); + break; + + //======================================= + // 16-bit char types + //======================================= + // 16-bit unicode char + case 0x007a: + primitiveDataType = primitiveApplicator.getUnicode16Type(); + break; + // 16-bit pointer to a 16-bit unicode char + case 0x017a: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.getUnicode16Type()); + break; + // 16:16 far pointer to a 16-bit unicode char + case 0x027a: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.getUnicode16Type()); + break; + // 16:16 huge pointer to a 16-bit unicode char + case 0x037a: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.getUnicode16Type()); + break; + // 32-bit pointer to a 16-bit unicode char + case 0x047a: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.getUnicode16Type()); + break; + // 16:32 pointer to a 16-bit unicode char + case 0x057a: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.getUnicode16Type()); + break; + // 64-bit pointer to a 16-bit unicode char + case 0x067a: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.getUnicode16Type()); + break; + // 128-bit near pointer to a 16-bit unicode char (LLVM doc on 0x0700) + case 0x077a: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.getUnicode16Type()); + break; + + //======================================= + // 32-bit unicode char types + //======================================= + // 32-bit unicode char + case 0x007b: + primitiveDataType = primitiveApplicator.getUnicode32Type(); + break; + // 16-bit pointer to a 32-bit unicode char + case 0x017b: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.getUnicode32Type()); + break; + // 16:16 far pointer to a 32-bit unicode char + case 0x027b: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.getUnicode32Type()); + break; + // 16:16 huge pointer to a 32-bit unicode char + case 0x037b: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.getUnicode32Type()); + break; + // 32-bit pointer to a 32-bit unicode char + case 0x047b: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.getUnicode32Type()); + break; + // 16:32 pointer to a 32-bit unicode char + case 0x057b: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.getUnicode32Type()); + break; + // 64-bit pointer to a 32-bit unicode char + case 0x067b: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.getUnicode32Type()); + break; + // 128-bit near pointer to a 32-bit unicode char (LLVM doc on 0x0700) + case 0x077b: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.getUnicode32Type()); + break; + + //======================================= + // 8-bit int types + //======================================= + // 8-bit int + case 0x0068: + primitiveDataType = primitiveApplicator.get8BitIntegerType(); + break; + // 16-bit pointer to an 8-bit int + case 0x0168: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get8BitIntegerType()); + break; + // 16:16 far pointer to an 8-bit int + case 0x0268: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get8BitIntegerType()); + break; + // 16:16 huge pointer to an 8-bit int + case 0x0368: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get8BitIntegerType()); + break; + // 32-bit pointer to an 8-bit int + case 0x0468: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get8BitIntegerType()); + break; + // 16:32 pointer to an 8-bit int + case 0x0568: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get8BitIntegerType()); + break; + // 64-bit pointer to an 8-bit int + case 0x0668: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get8BitIntegerType()); + break; + // 128-bit near pointer to an 8-bit int (LLVM doc on 0x0700) + case 0x0768: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get8BitIntegerType()); + break; + + //======================================= + // 8-bit unsigned int types + //======================================= + // 8-bit unsigned int + case 0x0069: + primitiveDataType = primitiveApplicator.get8BitUnsignedIntegerType(); + break; + // 16-bit pointer to an 8-bit unsigned int + case 0x0169: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get8BitUnsignedIntegerType()); + break; + // 16:16 far pointer to an 8-bit unsigned int + case 0x0269: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get8BitUnsignedIntegerType()); + break; + // 16:16 huge pointer to an 8-bit unsigned int + case 0x0369: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get8BitUnsignedIntegerType()); + break; + // 32-bit pointer to an 8-bit unsigned int + case 0x0469: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get8BitUnsignedIntegerType()); + break; + // 16:32 pointer to an 8-bit unsigned int + case 0x0569: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get8BitUnsignedIntegerType()); + break; + // 64-bit pointer to an 8-bit unsigned int + case 0x0669: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get8BitUnsignedIntegerType()); + break; + // 128-bit near pointer to an 8-bit unsigned int (LLVM doc on 0x0700) + case 0x0769: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get8BitUnsignedIntegerType()); + break; + + //======================================= + // 16-bit short types + //======================================= + // 16-bit signed short + case 0x0011: + primitiveDataType = primitiveApplicator.get16BitShortType(); + break; + // 16-bit pointer to a 16-bit signed short + case 0x0111: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get16BitShortType()); + break; + // 16:16 far pointer to a 16-bit signed short + case 0x0211: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get16BitShortType()); + break; + // 16:16 huge pointer to a 16-bit signed short + case 0x0311: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get16BitShortType()); + break; + // 32-bit pointer to a 16-bit signed short + case 0x0411: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get16BitShortType()); + break; + // 16:32 pointer to a 16-bit signed short + case 0x0511: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get16BitShortType()); + break; + // 64-bit pointer to a 16-bit signed short + case 0x0611: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get16BitShortType()); + break; + // 128-bit near pointer to a 16-bit signed short (LLVM doc on 0x0700) + case 0x0711: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get16BitShortType()); + break; + + //======================================= + // 16-bit unsigned short types + //======================================= + // 16-bit unsigned signed short + case 0x0021: + primitiveDataType = primitiveApplicator.get16BitUnsignedShortType(); + break; + // 16-bit pointer to a 16-bit unsigned signed short + case 0x0121: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get16BitUnsignedShortType()); + break; + // 16:16 far pointer to a 16-bit unsigned signed short + case 0x0221: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get16BitUnsignedShortType()); + break; + // 16:16 huge pointer to a 16-bit unsigned signed short + case 0x0321: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get16BitUnsignedShortType()); + break; + // 32-bit pointer to a 16-bit unsigned signed short + case 0x0421: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get16BitUnsignedShortType()); + break; + // 16:32 pointer to a 16-bit unsigned signed short + case 0x0521: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get16BitUnsignedShortType()); + break; + // 64-bit pointer to a 16-bit unsigned signed short + case 0x0621: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get16BitUnsignedShortType()); + break; + // 128-bit near pointer to a 16-bit unsigned signed short (LLVM doc on 0x0700) + case 0x0721: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get16BitUnsignedShortType()); + break; + + //======================================= + // 16-bit signed int types + //======================================= + // 16-bit signed int + case 0x0072: + primitiveDataType = primitiveApplicator.get16BitIntegerType(); + break; + // 16-bit pointer to a 16-bit signed int + case 0x0172: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get16BitIntegerType()); + break; + // 16:16 far pointer to a 16-bit signed int + case 0x0272: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get16BitIntegerType()); + break; + // 16:16 huge pointer to a 16-bit signed int + case 0x0372: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get16BitIntegerType()); + break; + // 32-bit pointer to a 16-bit signed int + case 0x0472: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get16BitIntegerType()); + break; + // 16:32 pointer to a 16-bit signed int + case 0x0572: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get16BitIntegerType()); + break; + // 64-bit pointer to a 16-bit signed int + case 0x0672: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get16BitIntegerType()); + break; + // 128-bit near pointer to a 16-bit signed int (LLVM doc on 0x0700) + case 0x0772: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get16BitIntegerType()); + break; + + //======================================= + // 16-bit unsigned int types + //======================================= + // 16-bit unsigned int + case 0x0073: + primitiveDataType = primitiveApplicator.get16BitUnsignedIntegerType(); + break; + // 16-bit pointer to a 16-bit unsigned int + case 0x0173: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get16BitUnsignedIntegerType()); + break; + // 16:16 far pointer to a 16-bit unsigned int + case 0x0273: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get16BitUnsignedIntegerType()); + break; + // 16:16 huge pointer to a 16-bit unsigned int + case 0x0373: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get16BitUnsignedIntegerType()); + break; + // 32-bit pointer to a 16-bit unsigned int + case 0x0473: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get16BitUnsignedIntegerType()); + break; + // 16:32 pointer to a 16-bit unsigned int + case 0x0573: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get16BitUnsignedIntegerType()); + break; + // 64-bit pointer to a 16-bit unsigned int + case 0x0673: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get16BitUnsignedIntegerType()); + break; + // 128-bit near pointer to a 16-bit unsigned int (LLVM doc on 0x0700) + case 0x0773: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get16BitUnsignedIntegerType()); + break; + + //======================================= + // 32-bit long types + //======================================= + // 32-bit signed long + case 0x0012: + primitiveDataType = primitiveApplicator.get32BitLongType(); + break; + // 16-bit pointer to a 32-bit signed long + case 0x0112: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitLongType()); + break; + // 16:16 far pointer to a 32-bit signed long + case 0x0212: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitLongType()); + break; + // 16:16 huge pointer to a 32-bit signed long + case 0x0312: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitLongType()); + break; + // 32-bit pointer to a 32-bit signed long + case 0x0412: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitLongType()); + break; + // 16:32 pointer to a 32-bit signed long + case 0x0512: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitLongType()); + break; + // 64-bit pointer to a 32-bit signed long + case 0x0612: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitLongType()); + break; + // 128-bit near pointer to a 32-bit signed long (LLVM doc on 0x0700) + case 0x0712: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitLongType()); + break; + + //======================================= + // 32-bit unsigned long types + //======================================= + // 32-bit unsigned signed long + case 0x0022: + primitiveDataType = primitiveApplicator.get32BitUnsignedLongType(); + break; + // 16-bit pointer to a 32-bit unsigned signed long + case 0x0122: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitUnsignedLongType()); + break; + // 16:16 far pointer to a 32-bit unsigned signed long + case 0x0222: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitUnsignedLongType()); + break; + // 16:16 huge pointer to a 32-bit unsigned signed long + case 0x0322: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitUnsignedLongType()); + break; + // 32-bit pointer to a 32-bit unsigned signed long + case 0x0422: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitUnsignedLongType()); + break; + // 16:32 pointer to a 32-bit unsigned signed long + case 0x0522: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitUnsignedLongType()); + break; + // 64-bit pointer to a 32-bit unsigned signed long + case 0x0622: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitUnsignedLongType()); + break; + // 128-bit near pointer to a 32-bit unsigned signed long (LLVM doc on 0x0700) + case 0x0722: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitUnsignedLongType()); + break; + + //======================================= + // 32-bit signed int types + //======================================= + // 32-bit signed int + case 0x0074: + primitiveDataType = primitiveApplicator.get32BitIntegerType(); + break; + // 16-bit pointer to a 32-bit signed int + case 0x0174: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitIntegerType()); + break; + // 16:16 far pointer to a 32-bit signed int + case 0x0274: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitIntegerType()); + break; + // 16:16 huge pointer to a 32-bit signed int + case 0x0374: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitIntegerType()); + break; + // 32-bit pointer to a 32-bit signed int + case 0x0474: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitIntegerType()); + break; + // 16:32 pointer to a 32-bit signed int + case 0x0574: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitIntegerType()); + break; + // 64-bit pointer to a 32-bit signed int + case 0x0674: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitIntegerType()); + break; + // 128-bit near pointer to a 32-bit signed int (LLVM doc on 0x0700) + case 0x0774: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitIntegerType()); + break; + + //======================================= + // 32-bit unsigned int types + //======================================= + // 32-bit unsigned int + case 0x0075: + primitiveDataType = primitiveApplicator.get32BitUnsignedIntegerType(); + break; + // 16-bit pointer to a 32-bit unsigned int + case 0x0175: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitUnsignedIntegerType()); + break; + // 16:16 far pointer to a 32-bit unsigned int + case 0x0275: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitUnsignedIntegerType()); + break; + // 16:16 huge pointer to a 32-bit unsigned int + case 0x0375: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitUnsignedIntegerType()); + break; + // 32-bit pointer to a 32-bit unsigned int + case 0x0475: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitUnsignedIntegerType()); + break; + // 16:32 pointer to a 32-bit unsigned int + case 0x0575: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitUnsignedIntegerType()); + break; + // 64-bit pointer to a 32-bit unsigned int + case 0x0675: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitUnsignedIntegerType()); + break; + // 128-bit near pointer to a 32-bit unsigned int (LLVM doc on 0x0700) + case 0x0775: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitUnsignedIntegerType()); + break; + + //======================================= + // 64-bit quad types + //======================================= + // 64-bit signed long + case 0x0013: + primitiveDataType = primitiveApplicator.get64BitLongType(); + break; + // 16-bit pointer to a 64-bit signed long + case 0x0113: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get64BitLongType()); + break; + // 16:16 far pointer to a 64-bit signed long + case 0x0213: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get64BitLongType()); + break; + // 16:16 huge pointer to a 64-bit signed long + case 0x0313: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get64BitLongType()); + break; + // 32-bit pointer to a 64-bit signed long + case 0x0413: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get64BitLongType()); + break; + // 16:32 pointer to a 64-bit signed long + case 0x0513: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get64BitLongType()); + break; + // 64-bit pointer to a 64-bit signed long + case 0x0613: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get64BitLongType()); + break; + // 128-bit near pointer to a 64-bit signed long (LLVM doc on 0x0700) + case 0x0713: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get64BitLongType()); + break; + + //======================================= + // 64-bit unsigned quad types + //======================================= + // 64-bit unsigned signed long + case 0x0023: + primitiveDataType = primitiveApplicator.get64BitUnsignedLongType(); + break; + // 16-bit pointer to a 64-bit unsigned signed long + case 0x0123: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get64BitUnsignedLongType()); + break; + // 16:16 far pointer to a 64-bit unsigned signed long + case 0x0223: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get64BitUnsignedLongType()); + break; + // 16:16 huge pointer to a 64-bit unsigned signed long + case 0x0323: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get64BitUnsignedLongType()); + break; + // 32-bit pointer to a 64-bit unsigned signed long + case 0x0423: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get64BitUnsignedLongType()); + break; + // 16:32 pointer to a 64-bit unsigned signed long + case 0x0523: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get64BitUnsignedLongType()); + break; + // 64-bit pointer to a 64-bit unsigned signed long + case 0x0623: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get64BitUnsignedLongType()); + break; + // 128-bit near pointer to a 64-bit unsigned signed long (LLVM doc on 0x0700) + case 0x0723: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get64BitUnsignedLongType()); + break; + + //======================================= + // 64-bit signed int types + //======================================= + // 64-bit signed int + case 0x0076: + primitiveDataType = primitiveApplicator.get64BitIntegerType(); + break; + // 16-bit pointer to a 64-bit signed int + case 0x0176: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get64BitIntegerType()); + break; + // 16:16 far pointer to a 64-bit signed int + case 0x0276: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get64BitIntegerType()); + break; + // 16:16 huge pointer to a 64-bit signed int + case 0x0376: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get64BitIntegerType()); + break; + // 32-bit pointer to a 64-bit signed int + case 0x0476: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get64BitIntegerType()); + break; + // 16:32 pointer to a 64-bit signed int + case 0x0576: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get64BitIntegerType()); + break; + // 64-bit pointer to a 64-bit signed int + case 0x0676: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get64BitIntegerType()); + break; + // 128-bit near pointer to a 64-bit signed int (LLVM doc on 0x0700) + case 0x0776: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get64BitIntegerType()); + break; + + //======================================= + // 64-bit unsigned int types + //======================================= + // 64-bit unsigned int + case 0x0077: + primitiveDataType = primitiveApplicator.get64BitUnsignedIntegerType(); + break; + // 16-bit pointer to a 64-bit unsigned int + case 0x0177: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get64BitUnsignedIntegerType()); + break; + // 16:16 far pointer to a 64-bit unsigned int + case 0x0277: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get64BitUnsignedIntegerType()); + break; + // 16:16 huge pointer to a 64-bit unsigned int + case 0x0377: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get64BitUnsignedIntegerType()); + break; + // 32-bit pointer to a 64-bit unsigned int + case 0x0477: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get64BitUnsignedIntegerType()); + break; + // 16:32 pointer to a 64-bit unsigned int + case 0x0577: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get64BitUnsignedIntegerType()); + break; + // 64-bit pointer to a 64-bit unsigned int + case 0x0677: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get64BitUnsignedIntegerType()); + break; + // 128-bit near pointer to a 64-bit unsigned int (LLVM doc on 0x0700) + case 0x0777: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get64BitUnsignedIntegerType()); + break; + + //======================================= + // 128-bit octet types + //======================================= + // 128-bit signed long + case 0x0014: + primitiveDataType = primitiveApplicator.get128BitLongType(); + break; + // 16-bit pointer to a 128-bit signed long + case 0x0114: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get128BitLongType()); + break; + // 16:16 far pointer to a 128-bit signed long + case 0x0214: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get128BitLongType()); + break; + // 16:16 huge pointer to a 128-bit signed long + case 0x0314: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get128BitLongType()); + break; + // 32-bit pointer to a 128-bit signed long + case 0x0414: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get128BitLongType()); + break; + // 16:32 pointer to a 128-bit signed long + case 0x0514: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get128BitLongType()); + break; + // 64-bit pointer to a 128-bit signed long + case 0x0614: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get128BitLongType()); + break; + // 128-bit near pointer to a 128-bit signed long (LLVM doc on 0x0700) + case 0x0714: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get128BitLongType()); + break; + + //======================================= + // 128-bit unsigned octet types + //======================================= + // 128-bit unsigned signed long + case 0x0024: + primitiveDataType = primitiveApplicator.get128BitUnsignedLongType(); + break; + // 16-bit pointer to a 128-bit unsigned signed long + case 0x0124: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get128BitUnsignedLongType()); + break; + // 16:16 far pointer to a 128-bit unsigned signed long + case 0x0224: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get128BitUnsignedLongType()); + break; + // 16:16 huge pointer to a 128-bit unsigned signed long + case 0x0324: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get128BitUnsignedLongType()); + break; + // 32-bit pointer to a 128-bit unsigned signed long + case 0x0424: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get128BitUnsignedLongType()); + break; + // 16:32 pointer to a 128-bit unsigned signed long + case 0x0524: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get128BitUnsignedLongType()); + break; + // 64-bit pointer to a 128-bit unsigned signed long + case 0x0624: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get128BitUnsignedLongType()); + break; + // 128-bit near pointer to a 128-bit unsigned signed long (LLVM doc on 0x0700) + case 0x0724: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get128BitUnsignedLongType()); + break; + + //======================================= + // 128-bit signed int types + //======================================= + // 128-bit signed int + case 0x0078: + primitiveDataType = primitiveApplicator.get128BitIntegerType(); + break; + // 16-bit pointer to a 128-bit signed int + case 0x0178: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get128BitIntegerType()); + break; + // 16:16 far pointer to a 128-bit signed int + case 0x0278: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get128BitIntegerType()); + break; + // 16:16 huge pointer to a 128-bit signed int + case 0x0378: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get128BitIntegerType()); + break; + // 32-bit pointer to a 128-bit signed int + case 0x0478: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get128BitIntegerType()); + break; + // 16:32 pointer to a 128-bit signed int + case 0x0578: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get128BitIntegerType()); + break; + // 64-bit pointer to a 128-bit signed int + case 0x0678: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get128BitIntegerType()); + break; + // 128-bit near pointer to a 128-bit signed int (LLVM doc on 0x0700) + case 0x0778: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get128BitIntegerType()); + break; + + //======================================= + // 128-bit unsigned int types + //======================================= + // 128-bit unsigned int + case 0x0079: + primitiveDataType = primitiveApplicator.get128BitUnsignedIntegerType(); + break; + // 16-bit pointer to a 128-bit unsigned int + case 0x0179: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get128BitUnsignedIntegerType()); + break; + // 16:16 far pointer to a 128-bit unsigned int + case 0x0279: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get128BitUnsignedIntegerType()); + break; + // 16:16 huge pointer to a 128-bit unsigned int + case 0x0379: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get128BitUnsignedIntegerType()); + break; + // 32-bit pointer to a 128-bit unsigned int + case 0x0479: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get128BitUnsignedIntegerType()); + break; + // 16:32 pointer to a 128-bit unsigned int + case 0x0579: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get128BitUnsignedIntegerType()); + break; + // 64-bit pointer to a 128-bit unsigned int + case 0x0679: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get128BitUnsignedIntegerType()); + break; + // 128-bit near pointer to a 128-bit unsigned int (LLVM doc on 0x0700) + case 0x0779: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get128BitUnsignedIntegerType()); + break; + + //======================================= + // 16-bit real types + //======================================= + // 16-bit real + case 0x0046: + primitiveDataType = primitiveApplicator.get16BitRealType(); + break; + // 16-bit pointer to a 16-bit real + case 0x0146: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get16BitRealType()); + break; + // 16:16 far pointer to a 16-bit real + case 0x0246: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get16BitRealType()); + break; + // 16:16 huge pointer to a 16-bit real + case 0x0346: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get16BitRealType()); + break; + // 32-bit pointer to a 16-bit real + case 0x0446: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get16BitRealType()); + break; + // 16:32 pointer to a 16-bit real + case 0x0546: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get16BitRealType()); + break; + // 64-bit pointer to a 16-bit real + case 0x0646: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get16BitRealType()); + break; + // 128-bit near pointer to a 16-bit real (LLVM doc on 0x0700) + case 0x0746: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get16BitRealType()); + break; + + //======================================= + // 32-bit real types + //======================================= + // 32-bit real + case 0x0040: + primitiveDataType = primitiveApplicator.get32BitRealType(); + break; + // 16-bit pointer to a 32-bit real + case 0x0140: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitRealType()); + break; + // 16:16 far pointer to a 32-bit real + case 0x0240: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitRealType()); + break; + // 16:16 huge pointer to a 32-bit real + case 0x0340: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitRealType()); + break; + // 32-bit pointer to a 32-bit real + case 0x0440: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitRealType()); + break; + // 16:32 pointer to a 32-bit real + case 0x0540: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitRealType()); + break; + // 64-bit pointer to a 32-bit real + case 0x0640: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitRealType()); + break; + // 128-bit near pointer to a 32-bit real (LLVM doc on 0x0700) + case 0x0740: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitRealType()); + break; + + //======================================= + // 32-bit partial-precision real types + //======================================= + // 32-bit partial-precision real + case 0x0045: + primitiveDataType = primitiveApplicator.get32BitPartialPrecisionRealType(); + break; + // 16-bit pointer to a 32-bit partial-precision real + case 0x0145: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitPartialPrecisionRealType()); + break; + // 16:16 far pointer to a 32-bit partial-precision real + case 0x0245: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitPartialPrecisionRealType()); + break; + // 16:16 huge pointer to a 32-bit partial-precision real + case 0x0345: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitPartialPrecisionRealType()); + break; + // 32-bit pointer to a 32-bit partial-precision real + case 0x0445: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitPartialPrecisionRealType()); + break; + // 16:32 pointer to a 32-bit partial-precision real + case 0x0545: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitPartialPrecisionRealType()); + break; + // 64-bit pointer to a 32-bit partial-precision real + case 0x0645: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitPartialPrecisionRealType()); + break; + // 128-bit near pointer to a 32-bit partial-precision real (LLVM doc on 0x0700) + case 0x0745: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitPartialPrecisionRealType()); + break; + + //======================================= + // 48-bit real types + //======================================= + // 48-bit real + case 0x0044: + primitiveDataType = primitiveApplicator.get48BitRealType(); + break; + // 16-bit pointer to a 48-bit real + case 0x0144: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get48BitRealType()); + break; + // 16:16 far pointer to a 48-bit real + case 0x0244: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get48BitRealType()); + break; + // 16:16 huge pointer to a 48-bit real + case 0x0344: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get48BitRealType()); + break; + // 32-bit pointer to a 48-bit real + case 0x0444: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get48BitRealType()); + break; + // 16:32 pointer to a 48-bit real + case 0x0544: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get48BitRealType()); + break; + // 64-bit pointer to a 48-bit real + case 0x0644: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get48BitRealType()); + break; + // 128-bit near pointer to a 48-bit real (LLVM doc on 0x0700) + case 0x0744: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get48BitRealType()); + break; + + //======================================= + // 64-bit real types + //======================================= + // 64-bit real + case 0x0041: + primitiveDataType = primitiveApplicator.get64BitRealType(); + break; + // 16-bit pointer to a 64-bit real + case 0x0141: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get64BitRealType()); + break; + // 16:16 far pointer to a 64-bit real + case 0x0241: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get64BitRealType()); + break; + // 16:16 huge pointer to a 64-bit real + case 0x0341: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get64BitRealType()); + break; + // 32-bit pointer to a 64-bit real + case 0x0441: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get64BitRealType()); + break; + // 16:32 pointer to a 64-bit real + case 0x0541: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get64BitRealType()); + break; + // 64-bit pointer to a 64-bit real + case 0x0641: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get64BitRealType()); + break; + // 128-bit near pointer to a 64-bit real (LLVM doc on 0x0700) + case 0x0741: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get64BitRealType()); + break; + + //======================================= + // 80-bit real types + //======================================= + // 80-bit real + case 0x0042: + primitiveDataType = primitiveApplicator.get80BitRealType(); + break; + // 16-bit pointer to an 80-bit real + case 0x0142: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get80BitRealType()); + break; + // 16:16 far pointer to an 80-bit real + case 0x0242: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get80BitRealType()); + break; + // 16:16 huge pointer to an 80-bit real + case 0x0342: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get80BitRealType()); + break; + // 32-bit pointer to an 80-bit real + case 0x0442: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get80BitRealType()); + break; + // 16:32 pointer to an 80-bit real + case 0x0542: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get80BitRealType()); + break; + // 64-bit pointer to an 80-bit real + case 0x0642: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get80BitRealType()); + break; + // 128-bit near pointer to an 80-bit real (LLVM doc on 0x0700) + case 0x0742: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get80BitRealType()); + break; + + //======================================= + // 128-bit real types + //======================================= + // 128-bit real + case 0x0043: + primitiveDataType = primitiveApplicator.get128BitRealType(); + break; + // 16-bit pointer to a 128-bit real + case 0x0143: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get128BitRealType()); + break; + // 16:16 far pointer to a 128-bit real + case 0x0243: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get128BitRealType()); + break; + // 16:16 huge pointer to a 128-bit real + case 0x0343: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get128BitRealType()); + break; + // 32-bit pointer to a 128-bit real + case 0x0443: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get128BitRealType()); + break; + // 16:32 pointer to a 128-bit real + case 0x0543: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get128BitRealType()); + break; + // 64-bit pointer to a 128-bit real + case 0x0643: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get128BitRealType()); + break; + // 128-bit near pointer to a 128-bit real (LLVM doc on 0x0700) + case 0x0743: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get128BitRealType()); + break; + + //======================================= + // 32-bit complex types + //======================================= + // 32-bit complex + case 0x0050: + primitiveDataType = primitiveApplicator.get32BitComplexType(); + break; + // 16-bit pointer to a 32-bit complex + case 0x0150: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitComplexType()); + break; + // 16:16 far pointer to a 32-bit complex + case 0x0250: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitComplexType()); + break; + // 16:16 huge pointer to a 32-bit complex + case 0x0350: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitComplexType()); + break; + // 32-bit pointer to an 32-bit complex + case 0x0450: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitComplexType()); + break; + // 16:32 pointer to an 32-bit complex + case 0x0550: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitComplexType()); + break; + // 64-bit pointer to an 32-bit complex + case 0x0650: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitComplexType()); + break; + // 128-bit near pointer to an 32-bit complex (LLVM doc on 0x0700) + case 0x0750: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitComplexType()); + break; + + //======================================= + // 64-bit complex types + //======================================= + // 64-bit complex + case 0x0051: + primitiveDataType = primitiveApplicator.get64BitComplexType(); + break; + // 16-bit pointer to a 64-bit complex + case 0x0151: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get64BitComplexType()); + break; + // 16:16 far pointer to a 64-bit complex + case 0x0251: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get64BitComplexType()); + break; + // 16:16 huge pointer to a 64-bit complex + case 0x0351: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get64BitComplexType()); + break; + // 32-bit pointer to a 64-bit complex + case 0x0451: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get64BitComplexType()); + break; + // 16:32 pointer to a 64-bit complex + case 0x0551: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get64BitComplexType()); + break; + // 64-bit pointer to a 64-bit complex + case 0x0651: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get64BitComplexType()); + break; + // 128-bit near pointer to a 64-bit complex (LLVM doc on 0x0700) + case 0x0751: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get64BitComplexType()); + break; + + //======================================= + // 80-bit complex types + //======================================= + // 80-bit complex + case 0x0052: + primitiveDataType = primitiveApplicator.get80BitComplexType(); + break; + // 16-bit pointer to an 80-bit complex + case 0x0152: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get80BitComplexType()); + break; + // 16:16 far pointer to an 80-bit complex + case 0x0252: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get80BitComplexType()); + break; + // 16:16 huge pointer to an 80-bit complex + case 0x0352: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get80BitComplexType()); + break; + // 32-bit pointer to an 80-bit complex + case 0x0452: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get80BitComplexType()); + break; + // 16:32 pointer to an 80-bit complex + case 0x0552: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get80BitComplexType()); + break; + // 64-bit pointer to an 80-bit complex + case 0x0652: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get80BitComplexType()); + break; + // 128-bit near pointer to an 80-bit complex (LLVM doc on 0x0700) + case 0x0752: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get80BitComplexType()); + break; + + //======================================= + // 128-bit complex types + //======================================= + // 128-bit complex + case 0x0053: + primitiveDataType = primitiveApplicator.get128BitComplexType(); + break; + // 16-bit pointer to a 128-bit complex + case 0x0153: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get128BitComplexType()); + break; + // 16:16 far pointer to a 128-bit complex + case 0x0253: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get128BitComplexType()); + break; + // 16:16 huge pointer to a 128-bit complex + case 0x0353: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get128BitComplexType()); + break; + // 32-bit pointer to a 128-bit complex + case 0x0453: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get128BitComplexType()); + break; + // 16:32 pointer to a 128-bit complex + case 0x0553: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get128BitComplexType()); + break; + // 64-bit pointer to a 128-bit complex + case 0x0653: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get128BitComplexType()); + break; + // 128-bit near pointer to a 128-bit complex (LLVM doc on 0x0700) + case 0x0753: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get128BitComplexType()); + break; + + //======================================= + // 48-bit complex types + //======================================= + // 48-bit complex + case 0x0054: + primitiveDataType = primitiveApplicator.get48BitComplexType(); + break; + // 16-bit pointer to a 48-bit complex + case 0x0154: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get48BitComplexType()); + break; + // 16:16 far pointer to a 48-bit complex + case 0x0254: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get48BitComplexType()); + break; + // 16:16 huge pointer to a 48-bit complex + case 0x0354: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get48BitComplexType()); + break; + // 32-bit pointer to a 48-bit complex + case 0x0454: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get48BitComplexType()); + break; + // 16:32 pointer to a 48-bit complex + case 0x0554: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get48BitComplexType()); + break; + // 64-bit pointer to a 48-bit complex + case 0x0654: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get48BitComplexType()); + break; + // 128-bit near pointer to a 48-bit complex (LLVM doc on 0x0700) + case 0x0754: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get48BitComplexType()); + break; + + //======================================= + // 32-bit partial-precision complex types + //======================================= + // 32-bit partial-precision complex + case 0x0055: + primitiveDataType = primitiveApplicator.get32BitPartialPrecisionComplexType(); + break; + // 16-bit pointer to a 32-bit partial-precision complex + case 0x0155: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitPartialPrecisionComplexType()); + break; + // 16:16 far pointer to a 32-bit partial-precision complex + case 0x0255: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitPartialPrecisionComplexType()); + break; + // 16:16 huge pointer to a 32-bit partial-precision complex + case 0x0355: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitPartialPrecisionComplexType()); + break; + // 32-bit pointer to a 32-bit partial-precision complex + case 0x0455: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitPartialPrecisionComplexType()); + break; + // 16:32 pointer to a 32-bit partial-precision complex + case 0x0555: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitPartialPrecisionComplexType()); + break; + // 64-bit pointer to a 32-bit partial-precision complex + case 0x0655: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitPartialPrecisionComplexType()); + break; + // 128-bit near pointer to a 32-bit partial-precision complex (LLVM doc on 0x0700) + case 0x0755: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitPartialPrecisionComplexType()); + break; + + //======================================= + // 16-bit complex types + //======================================= + // 16-bit complex + case 0x0056: + primitiveDataType = primitiveApplicator.get16BitComplexType(); + break; + // 16-bit pointer to a 16-bit complex + case 0x0156: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get16BitComplexType()); + break; + // 16:16 far pointer to a 16-bit complex + case 0x0256: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get16BitComplexType()); + break; + // 16:16 huge pointer to a 16-bit complex + case 0x0356: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get16BitComplexType()); + break; + // 32-bit pointer to a 16-bit complex + case 0x0456: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get16BitComplexType()); + break; + // 16:32 pointer to a 16-bit complex + case 0x0556: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get16BitComplexType()); + break; + // 64-bit pointer to a 16-bit complex + case 0x0656: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get16BitComplexType()); + break; + // 128-bit near pointer to a 16-bit complex (LLVM doc on 0x0700) + case 0x0756: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get16BitComplexType()); + break; + + //======================================= + // 8-bit boolean types + //======================================= + // 8-bit boolean + case 0x0030: + primitiveDataType = primitiveApplicator.get8BitBooleanType(); + break; + // 16-bit pointer to an 8-bit boolean + case 0x0130: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get8BitBooleanType()); + break; + // 16:16 far pointer to an 8-bit boolean + case 0x0230: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get8BitBooleanType()); + break; + // 16:16 huge pointer to an 8-bit boolean + case 0x0330: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get8BitBooleanType()); + break; + // 32-bit pointer to an 8-bit boolean + case 0x0430: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get8BitBooleanType()); + break; + // 16:32 pointer to an 8-bit boolean + case 0x0530: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get8BitBooleanType()); + break; + // 64-bit pointer to an 8-bit boolean + case 0x0630: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get8BitBooleanType()); + break; + // 128-bit near pointer to an 8-bit boolean (LLVM doc on 0x0700) + case 0x0730: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get8BitBooleanType()); + break; + + //======================================= + // 16-bit boolean types + //======================================= + // 16-bit boolean + case 0x0031: + primitiveDataType = primitiveApplicator.get16BitBooleanType(); + break; + // 16-bit pointer to a 16-bit boolean + case 0x0131: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get16BitBooleanType()); + break; + // 16:16 far pointer to a 16-bit boolean + case 0x0231: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get16BitBooleanType()); + break; + // 16:16 huge pointer to a 16-bit boolean + case 0x0331: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get16BitBooleanType()); + break; + // 32-bit pointer to a 16-bit boolean + case 0x0431: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get16BitBooleanType()); + break; + // 16:32 pointer to a 16-bit boolean + case 0x0531: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get16BitBooleanType()); + break; + // 64-bit pointer to a 16-bit boolean + case 0x0631: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get16BitBooleanType()); + break; + // 128-bit near pointer to a 16-bit boolean (LLVM doc on 0x0700) + case 0x0731: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get16BitBooleanType()); + break; + + //======================================= + // 32-bit boolean types + //======================================= + // 32-bit boolean + case 0x0032: + primitiveDataType = primitiveApplicator.get32BitBooleanType(); + break; + // 16-bit pointer to a 32-bit boolean + case 0x0132: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get32BitBooleanType()); + break; + // 16:16 far pointer to a 32-bit boolean + case 0x0232: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get32BitBooleanType()); + break; + // 16:16 huge pointer to a 32-bit boolean + case 0x0332: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get32BitBooleanType()); + break; + // 32-bit pointer to a 32-bit boolean + case 0x0432: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get32BitBooleanType()); + break; + // 16:32 pointer to a 32-bit boolean + case 0x0532: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get32BitBooleanType()); + break; + // 64-bit pointer to a 32-bit boolean + case 0x0632: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get32BitBooleanType()); + break; + // 128-bit near pointer to a 32-bit boolean (LLVM doc on 0x0700) + case 0x0732: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get32BitBooleanType()); + break; + + //======================================= + // 64-bit boolean types + //======================================= + // 64-bit boolean + case 0x0033: + primitiveDataType = primitiveApplicator.get64BitBooleanType(); + break; + // 16-bit pointer to a 64-bit boolean + case 0x0133: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get64BitBooleanType()); + break; + // 16:16 far pointer to a 64-bit boolean + case 0x0233: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get64BitBooleanType()); + break; + // 16:16 huge pointer to a 64-bit boolean + case 0x0333: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get64BitBooleanType()); + break; + // 32-bit pointer to a 64-bit boolean + case 0x0433: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get64BitBooleanType()); + break; + // 16:32 pointer to a 64-bit boolean + case 0x0533: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get64BitBooleanType()); + break; + // 64-bit pointer to a 64-bit boolean + case 0x0633: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get64BitBooleanType()); + break; + // 128-bit near pointer to a 64-bit boolean (LLVM doc on 0x0700) + case 0x0733: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get64BitBooleanType()); + break; + + //======================================= + // 128-bit boolean types + //======================================= + // 128-bit boolean + case 0x0034: + primitiveDataType = primitiveApplicator.get128BitBooleanType(); + break; + // 16-bit pointer to a 128-bit boolean + case 0x0134: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.get128BitBooleanType()); + break; + // 16:16 far pointer to a 128-bit boolean + case 0x0234: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.get128BitBooleanType()); + break; + // 16:16 huge pointer to a 128-bit boolean + case 0x0334: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.get128BitBooleanType()); + break; + // 32-bit pointer to a 128-bit boolean + case 0x0434: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.get128BitBooleanType()); + break; + // 16:32 pointer to a 128-bit boolean + case 0x0534: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.get128BitBooleanType()); + break; + // 64-bit pointer to a 128-bit boolean + case 0x0634: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.get128BitBooleanType()); + break; + // 128-bit near pointer to a 128-bit boolean (LLVM doc on 0x0700) + case 0x0734: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.get128BitBooleanType()); + break; + + //======================================= + // Internal type with pointers + //======================================= + // CV Internal type for created near pointers + case 0x01f0: + primitiveDataType = primitiveApplicator.get16NearPointerType(type, + primitiveApplicator.createTypedefNamedSizedType("CVInternal", 1)); + break; + // CV Internal type for created far pointers + case 0x02f0: + primitiveDataType = primitiveApplicator.get1616FarPointerType(type, + primitiveApplicator.createTypedefNamedSizedType("CVInternal", 1)); + break; + // CV Internal type for created huge pointers + case 0x03f0: + primitiveDataType = primitiveApplicator.get1616HugePointerType(type, + primitiveApplicator.createTypedefNamedSizedType("CVInternal", 1)); + break; + // CV Internal type for created near 32-bit pointers + case 0x04f0: + primitiveDataType = primitiveApplicator.get32PointerType(type, + primitiveApplicator.createTypedefNamedSizedType("CVInternal", 1)); + break; + // CV Internal type for created far 32-bit pointers + case 0x05f0: + primitiveDataType = primitiveApplicator.get1632PointerType(type, + primitiveApplicator.createTypedefNamedSizedType("CVInternal", 1)); + break; + // CV Internal type for created near 64-bit pointers + case 0x06f0: + primitiveDataType = primitiveApplicator.get64PointerType(type, + primitiveApplicator.createTypedefNamedSizedType("CVInternal", 1)); + break; + // CV Internal type for created near 128-bit near pointers (LLVM doc on 0x0700) + case 0x07f0: + primitiveDataType = primitiveApplicator.get128PointerType(type, + primitiveApplicator.createTypedefNamedSizedType("CVInternal", 1)); + break; + + default: + // Note: 0x0400 seems to have been used as a this pointer type. + primitiveDataType = primitiveApplicator.createUnmappedPdbType(type); + break; + + } + + return primitiveDataType; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java new file mode 100644 index 0000000000..5d59900bb0 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java @@ -0,0 +1,90 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +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.*; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractProcedureMsType} types. + */ +public class ProcedureTypeApplier extends AbstractFunctionTypeApplier { + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractProcedureMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + ProcedureTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for the applicator that applies {@link AbstractProcedureMsType}, + * transforming it into a Ghidra {@link DataType}. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractProcedureMsType} to processes. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public ProcedureTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + + @Override + protected CallingConvention getCallingConvention() { + return ((AbstractProcedureMsType) msType).getCallingConvention(); + } + + @Override + protected boolean hasThisPointer() { + return false; + } + + @Override + protected RecordNumber getReturnRecordNumber() { + return ((AbstractProcedureMsType) msType).getReturnRecordNumber(); + } + + @Override + protected RecordNumber getArgListRecordNumber() { + return ((AbstractProcedureMsType) msType).getArgListRecordNumber(); + } + + @Override + public void apply() throws PdbException, CancelledException { + applyFunction(getCallingConvention(), hasThisPointer()); + +// AbstractProcedureMsType procType = (AbstractProcedureMsType) msType; +// applyFunction(procType.getCallingConvention(), false, procType.getReturnTypeIndex(), +// procType.getArgListTypeIndex()); +// DataType definition = applyFunction(procType.getCallingConvention(), false, +// procType.getReturnTypeIndex(), procType.getArgListTypeIndex()); +// ghDataTypeDB = applicator.resolve(definition); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java new file mode 100644 index 0000000000..4805f4f0f3 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java @@ -0,0 +1,99 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.List; + +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.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.program.model.symbol.Symbol; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractPublicMsSymbol} symbols. + */ +public class PublicSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractPublicMsSymbol symbol; + private Address symbolAddress = null; + private Address existingSymbolAddress = null; + + public PublicSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractPublicMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractPublicMsSymbol) abstractSymbol; + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing. + } + + @Override + public void apply() throws CancelledException, PdbException { + + symbolAddress = applicator.reladdr(symbol); + if (!Address.NO_ADDRESS.equals(symbolAddress)) { + + if (getName().startsWith("?")) { // mangled... should be unique + List existingSymbols = + applicator.getProgram().getSymbolTable().getGlobalSymbols(getName()); + if (existingSymbols.size() == 1) { + existingSymbolAddress = existingSymbols.get(0).getAddress(); + applicator.putRemapAddressByAddress(symbolAddress, existingSymbolAddress); + } + else if (existingSymbols.size() == 0) { + String name = symbol.getName(); + if (!applicator.createSymbol(symbolAddress, name, true)) { + applicator.appendLogMsg( + "Unable to create symbol " + name + " at " + symbolAddress); + } + } + else { + applicator.appendLogMsg( + "Unexpected multiple mangled symbols of same name: " + getName()); + } + } + } + else { + String message = "Could not apply symbol at NO_ADDRESS: " + symbol.getName(); + Msg.info(this, message); + PdbLog.message(message); + } + } + + Address getAddress() { + return symbolAddress; + } + + Address getAddressRemappedThroughPublicSymbol() { + return (existingSymbolAddress != null) ? existingSymbolAddress : symbolAddress; + } + + String getName() { + return symbol.getName(); + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java new file mode 100644 index 0000000000..038b6b090c --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java @@ -0,0 +1,71 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractReferenceMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractReferenceMsSymbol} symbols. + */ +public class ReferenceSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractReferenceMsSymbol symbol; + + public ReferenceSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractReferenceMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractReferenceMsSymbol) abstractSymbol; + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing. + } + + @Override + public void apply() throws CancelledException, PdbException { + // Potential recursive call via applicator.procSym(). + AbstractMsSymbolIterator refIter = getInitializedReferencedSymbolGroup().iterator(); + applicator.procSym(refIter); + } + + SymbolGroup getInitializedReferencedSymbolGroup() { + SymbolGroup refSymbolGroup = getReferencedSymbolGroup(); + AbstractMsSymbolIterator refIter = refSymbolGroup.iterator(); + refIter.initGetByOffset(getOffsetInReferencedSymbolGroup()); + return refSymbolGroup; + } + + SymbolGroup getReferencedSymbolGroup() { + int refModuleNumber = symbol.getModuleIndex(); + return applicator.getSymbolGroupForModule(refModuleNumber); + } + + long getOffsetInReferencedSymbolGroup() { + // Adjusting offset to the offset we use for parsing the complete record. + return symbol.getOffsetActualSymbolInDollarDollarSymbols() - 4; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java new file mode 100644 index 0000000000..a11e642686 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java @@ -0,0 +1,156 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.Objects; + +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.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractRegisterRelativeAddressMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.data.DataType; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.SourceType; +import ghidra.util.Msg; +import ghidra.util.exception.*; + +/** + * Applier for {@link AbstractRegisterRelativeAddressMsSymbol} symbols. + */ +public class RegisterRelativeSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractRegisterRelativeAddressMsSymbol symbol; + + public RegisterRelativeSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractRegisterRelativeAddressMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractRegisterRelativeAddressMsSymbol) abstractSymbol; + } + + @Override + public void apply() throws PdbException, CancelledException { + String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; + Msg.info(this, message); + PdbLog.message(message); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) + throws PdbException, CancelledException { + if (!applicator.getPdbApplicatorOptions().applyFunctionVariables()) { + return; + } + if (applyToApplier instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; + createFunctionVariable(functionSymbolApplier); + } + } + + private boolean createFunctionVariable(FunctionSymbolApplier applier) { + Objects.requireNonNull(applier, "FunctionSymbolApplier cannot be null"); + Function function = applier.getFunction(); + + if (function == null) { + applicator.appendLogMsg("Could not create stack variable for non-existent function."); + return false; + } + //Variable[] allVariables = function.getAllVariables(); + + String registerName = symbol.getRegisterNameString(); + Register register = applicator.getRegister(registerName); + Register sp = applicator.getProgram().getCompilerSpec().getStackPointer(); + if (register != sp) { + // have seen fbp here. + // TODO; can we do something more generic below that does not rely on stack frame? + // would like to do RSP + X, or RBP + X, or RDX + X. + return false; + } + + Integer registerChange = applier.getRegisterPrologChange(register); + + StackFrame stackFrame = function.getStackFrame(); + + int baseParamOffset = applier.getBaseParamOffset(); + long frameSize = applier.getCurrentFrameSize(); +// long relativeOffset = symbol.getOffset() - applier.getCurrentFrameSize(); + if (registerChange == null) { + registerChange = 0; + } + long relativeOffset = symbol.getOffset() + registerChange; +// long relativeOffset = symbol.getOffset() + x; +// if (relativeOffset > Integer.MAX_VALUE) { +// applicator.appendLogMsg("Offset too large for our applier."); +// //return false; +// } + int offset = (int) (relativeOffset & 0xffffffffL); + + AbstractMsTypeApplier dataTypeApplier = + applicator.getTypeApplier(symbol.getTypeRecordNumber()); + DataType dt = dataTypeApplier.getDataType(); + if (dt != null) { +// Variable m16 = stackFrame.getVariableContaining(-16); +// Variable m8 = stackFrame.getVariableContaining(-8); +// Variable x0 = stackFrame.getVariableContaining(0); +// Variable x8 = stackFrame.getVariableContaining(8); +// Variable x16 = stackFrame.getVariableContaining(16); +// Variable x24 = stackFrame.getVariableContaining(24); +// Variable x32 = stackFrame.getVariableContaining(32); +// Variable x40 = stackFrame.getVariableContaining(40); +// Variable x48 = stackFrame.getVariableContaining(48); +// Variable x56 = stackFrame.getVariableContaining(56); + Variable variable = stackFrame.getVariableContaining(offset); + try { + if (variable == null || variable.getStackOffset() != offset) { + if (variable != null) { + stackFrame.clearVariable(variable.getStackOffset()); + } + try { + variable = stackFrame.createVariable(symbol.getName(), offset, dt, + SourceType.IMPORTED); + } + catch (DuplicateNameException e) { + variable = stackFrame.createVariable( + symbol.getName() + "@" + Integer.toHexString(offset), offset, dt, + SourceType.IMPORTED); + } + } + else { + variable.setDataType(dt, false, true, SourceType.ANALYSIS); + try { + variable.setName(symbol.getName(), SourceType.IMPORTED); + } + catch (DuplicateNameException e) { + variable.setName(symbol.getName() + "@" + Integer.toHexString(offset), + SourceType.IMPORTED); + } + } + } + catch (Exception e) { + applicator.appendLogMsg("Unable to create stack variable " + symbol.getName() + + " at offset " + offset + " in " + function.getName()); + return false; + } + } + return true; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java new file mode 100644 index 0000000000..7c873bb350 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java @@ -0,0 +1,135 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.*; + +import ghidra.app.cmd.comments.SetCommentCmd; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.SeparatedCodeFromCompilerSupportMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.CodeUnit; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link SeparatedCodeFromCompilerSupportMsSymbol} symbol. + */ +// TODO: Need to evaluate relationship to function symbols. +// TODO: Need to create anonymous name for this as a function? +public class SeparatedCodeSymbolApplier extends AbstractMsSymbolApplier { + + private SeparatedCodeFromCompilerSupportMsSymbol symbol; + + private String craftedName; + + private Address specifiedAddress; + private BlockCommentsManager comments; + + private int symbolBlockNestingLevel; + private Address currentBlockAddress; + + private List allAppliers = new ArrayList<>(); + + private static AbstractMsSymbolIterator validateSymbol(AbstractMsSymbolIterator iter) { + if (!(iter.peek() instanceof SeparatedCodeFromCompilerSupportMsSymbol)) { + throw new IllegalArgumentException("Not a SeparatedCodeFromCompilerSupportMsSymbol"); + } + return iter; + } + + public SeparatedCodeSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) + throws CancelledException, NoSuchElementException { + super(applicator, validateSymbol(iter)); + + symbol = (SeparatedCodeFromCompilerSupportMsSymbol) iter.next(); + + specifiedAddress = applicator.reladdr(symbol); + + // Make up name. TODO: decide if need better anonymous name + craftedName = String.format("CompilerSeparatedCode%s", specifiedAddress); + + symbolBlockNestingLevel = 0; + + comments = new BlockCommentsManager(); + currentBlockAddress = null; + + manageBlockNesting(this); + + while (notDone()) { + applicator.checkCanceled(); + AbstractMsSymbolApplier applier = applicator.getSymbolApplier(iter); + if (!(applier instanceof EndSymbolApplier)) { + Msg.info(this, "Unexpected applier in " + getClass().getSimpleName() + ": " + + applier.getClass().getSimpleName()); + } + allAppliers.add(applier); + applier.manageBlockNesting(this); + } + } + + @Override + public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + beginBlock(specifiedAddress); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing. + } + + @Override + public void apply() throws PdbException, CancelledException { + // DO NOTHING FOR NOW. TODO: should we have a configuration option? + // Note: these comments can be noise in the decompiler an code browser + setComments(false); + } + + private void setComments(boolean enabled) { + if (enabled) { + String existingComment = applicator.getProgram().getListing().getComment( + CodeUnit.PRE_COMMENT, specifiedAddress); + String p = "*************************************************************\n"; + String newComment = + String.format(p + "* Separated code (from the compiler): %s - %s *\n" + p, + specifiedAddress.toString(), + specifiedAddress.add(symbol.getBlockLength() - 1).toString()); + String comment = + (existingComment == null) ? newComment : existingComment + "\n" + newComment; + SetCommentCmd.createComment(applicator.getProgram(), specifiedAddress, comment, + CodeUnit.PRE_COMMENT); + } + } + + private boolean notDone() { + return (symbolBlockNestingLevel > 0) && iter.hasNext(); + } + + public int endBlock() { + if (--symbolBlockNestingLevel < 0) { + applicator.appendLogMsg("Block Nesting went negative at " + specifiedAddress); + } + return symbolBlockNestingLevel; + } + + private int beginBlock(Address startAddress) { + currentBlockAddress = startAddress; + ++symbolBlockNestingLevel; + return symbolBlockNestingLevel; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierParser.java new file mode 100644 index 0000000000..34008f3304 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierParser.java @@ -0,0 +1,659 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.NoSuchElementException; + +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.util.exception.CancelledException; + +public class SymbolApplierParser { + + private PdbApplicator applicator; + + SymbolApplierParser(PdbApplicator applicator) { + this.applicator = applicator; + } + + // TODO: 20191120... Do we need a SymbolApplier cache for Symbols like we have the TypeApplier + // cache (by index) for Types/Items? Would we use a record number (index) from within + // the AbstractMsSymbol (do one for AbstractMsType as well)? Symbols are different in that + // we are using SymbolGroup as a member instead of MsType. + + AbstractMsSymbolApplier getSymbolApplier(AbstractMsSymbolIterator iter) + throws CancelledException, NoSuchElementException { + + AbstractMsSymbol symbol = iter.peek(); + if (symbol == null) { + applicator.appendLogMsg("PDB Warning: No AbstractMsSymbol"); + return null; + } + AbstractMsSymbolApplier applier = null; + + switch (symbol.getPdbId()) { +// // 0x0000 block +// case CompileFlagsMsSymbol.PDB_ID: +// symbol = new CompileFlagsMsSymbol(pdb, reader); +// break; +// case Register16MsSymbol.PDB_ID: +// symbol = new Register16MsSymbol(pdb, reader); +// break; +// case Constant16MsSymbol.PDB_ID: +// symbol = new Constant16MsSymbol(pdb, reader); +// break; + case UserDefinedType16MsSymbol.PDB_ID: + applier = new TypedefSymbolApplier(applicator, iter); + break; +// case StartSearchMsSymbol.PDB_ID: +// symbol = new StartSearchMsSymbol(pdb, reader); +// break; + case EndMsSymbol.PDB_ID: + applier = new EndSymbolApplier(applicator, iter); + break; +// case SkipMsSymbol.PDB_ID: +// symbol = new SkipMsSymbol(pdb, reader); +// break; +// case CvReservedMsSymbol.PDB_ID: +// symbol = new CvReservedMsSymbol(pdb, reader); +// break; +// case ObjectNameStMsSymbol.PDB_ID: +// symbol = new ObjectNameStMsSymbol(pdb, reader); +// break; +// case EndArgumentsListMsSymbol.PDB_ID: +// symbol = new EndArgumentsListMsSymbol(pdb, reader); +// break; + case CobolUserDefinedType16MsSymbol.PDB_ID: + applier = new TypedefSymbolApplier(applicator, iter); + break; +// case ManyRegisterVariable16MsSymbol.PDB_ID: +// symbol = new ManyRegisterVariable16MsSymbol(pdb, reader); +// break; +// case ReturnDescriptionMsSymbol.PDB_ID: +// symbol = new ReturnDescriptionMsSymbol(pdb, reader); +// break; +// case EntryThisMsSymbol.PDB_ID: +// symbol = new EntryThisMsSymbol(pdb, reader); +// break; +// +// // 0x0100 block +// case BasePointerRelative16MsSymbol.PDB_ID: +// symbol = new BasePointerRelative16MsSymbol(pdb, reader); +// break; + case LocalData16MsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case GlobalData16MsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case Public16MsSymbol.PDB_ID: + applier = new PublicSymbolApplier(applicator, iter); + break; + case LocalProcedureStart16MsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case GlobalProcedureStart16MsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case Thunk16MsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case Block16MsSymbol.PDB_ID: + applier = new BlockSymbolApplier(applicator, iter); + break; + case With16MsSymbol.PDB_ID: + applier = new WithSymbolApplier(applicator, iter); + break; + case Label16MsSymbol.PDB_ID: + applier = new LabelSymbolApplier(applicator, iter); + break; +// case ChangeExecutionModel16MsSymbol.PDB_ID: +// symbol = new ChangeExecutionModel16MsSymbol(pdb, reader); +// break; +// case VirtualFunctionTable16MsSymbol.PDB_ID: +// symbol = new VirtualFunctionTable16MsSymbol(pdb, reader); +// break; + case RegisterRelativeAddress16MsSymbol.PDB_ID: + applier = new RegisterRelativeSymbolApplier(applicator, iter); + break; +// +// // 0x0200 block +// case BasePointerRelative3216MsSymbol.PDB_ID: +// symbol = new BasePointerRelative3216MsSymbol(pdb, reader); +// break; + case LocalData3216MsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case GlobalData3216MsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case Public3216MsSymbol.PDB_ID: + applier = new PublicSymbolApplier(applicator, iter); + break; + case LocalProcedureStart3216MsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case GlobalProcedureStart3216MsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case Thunk32StMsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case Block32StMsSymbol.PDB_ID: + applier = new BlockSymbolApplier(applicator, iter); + break; + case With32StMsSymbol.PDB_ID: + applier = new WithSymbolApplier(applicator, iter); + break; + case Label32StMsSymbol.PDB_ID: + applier = new LabelSymbolApplier(applicator, iter); + break; +// case ChangeExecutionModel32MsSymbol.PDB_ID: +// symbol = new ChangeExecutionModel32MsSymbol(pdb, reader); +// break; +// case VirtualFunctionTable3216MsSymbol.PDB_ID: +// symbol = new VirtualFunctionTable3216MsSymbol(pdb, reader); +// break; + case RegisterRelativeAddress3216MsSymbol.PDB_ID: + applier = new RegisterRelativeSymbolApplier(applicator, iter); + break; +// case LocalThreadStorage3216MsSymbol.PDB_ID: +// symbol = new LocalThreadStorage3216MsSymbol(pdb, reader); +// break; +// case GlobalThreadStorage3216MsSymbol.PDB_ID: +// symbol = new GlobalThreadStorage3216MsSymbol(pdb, reader); +// break; +// case StaticLinkForMipsExceptionHandlingMsSymbol.PDB_ID: +// symbol = new StaticLinkForMipsExceptionHandlingMsSymbol(pdb, reader); +// break; +// +// // 0x0300 block +// case LocalProcedureStartMips16MsSymbol.PDB_ID: +// symbol = new LocalProcedureStartMips16MsSymbol(pdb, reader); +// break; +// case GlobalProcedureStartMips16MsSymbol.PDB_ID: +// symbol = new GlobalProcedureStartMips16MsSymbol(pdb, reader); +// break; +// +// // 0x0400 block + case ProcedureReferenceStMsSymbol.PDB_ID: + applier = new ReferenceSymbolApplier(applicator, iter); + break; + case DataReferenceStMsSymbol.PDB_ID: + applier = new ReferenceSymbolApplier(applicator, iter); + break; +// case AlignMsSymbol.PDB_ID: +// symbol = new AlignMsSymbol(pdb, reader); +// break; + case LocalProcedureReferenceStMsSymbol.PDB_ID: + applier = new ReferenceSymbolApplier(applicator, iter); + break; +// case OemDefinedMsSymbol.PDB_ID: +// symbol = new OemDefinedMsSymbol(pdb, reader); +// break; +// +// // 0x1000 block +// case RegisterStMsSymbol.PDB_ID: +// symbol = new RegisterStMsSymbol(pdb, reader); +// break; +// case ConstantStMsSymbol.PDB_ID: +// symbol = new ConstantStMsSymbol(pdb, reader); +// break; + case UserDefinedTypeStMsSymbol.PDB_ID: + applier = new TypedefSymbolApplier(applicator, iter); + break; + case CobolUserDefinedTypeStMsSymbol.PDB_ID: + applier = new TypedefSymbolApplier(applicator, iter); + break; +// case ManyRegisterVariableStMsSymbol.PDB_ID: +// symbol = new ManyRegisterVariableStMsSymbol(pdb, reader); +// break; +// case BasePointerRelative32StMsSymbol.PDB_ID: +// symbol = new BasePointerRelative32StMsSymbol(pdb, reader); +// break; + case LocalData32StMsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case GlobalData32StMsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case Public32StMsSymbol.PDB_ID: + applier = new PublicSymbolApplier(applicator, iter); + break; + case LocalProcedureStart32StMsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case GlobalProcedureStart32StMsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; +// case VirtualFunctionTable32MsSymbol.PDB_ID: +// symbol = new VirtualFunctionTable32MsSymbol(pdb, reader); +// break; + case RegisterRelativeAddress32StMsSymbol.PDB_ID: + applier = new RegisterRelativeSymbolApplier(applicator, iter); + break; +// case LocalThreadStorage32StMsSymbol.PDB_ID: +// symbol = new LocalThreadStorage32StMsSymbol(pdb, reader); +// break; +// case GlobalThreadStorage32StMsSymbol.PDB_ID: +// symbol = new GlobalThreadStorage32StMsSymbol(pdb, reader); +// break; +// case LocalProcedureStartMipsStMsSymbol.PDB_ID: +// symbol = new LocalProcedureStartMipsStMsSymbol(pdb, reader); +// break; +// case GlobalProcedureStartMipsStMsSymbol.PDB_ID: +// symbol = new GlobalProcedureStartMipsStMsSymbol(pdb, reader); +// break; + case ExtraFrameAndProcedureInformationMsSymbol.PDB_ID: + applier = new FrameAndProcedureInformationSymbolApplier(applicator, iter); + break; +// case Compile2StMsSymbol.PDB_ID: +// symbol = new Compile2StMsSymbol(pdb, reader); +// break; +// case ManyRegisterVariable2StMsSymbol.PDB_ID: +// symbol = new ManyRegisterVariable2StMsSymbol(pdb, reader); +// break; +// case LocalProcedureStartIa64StMsSymbol.PDB_ID: +// symbol = new LocalProcedureStartIa64StMsSymbol(pdb, reader); +// break; +// case GlobalProcedureStartIa64StMsSymbol.PDB_ID: +// symbol = new GlobalProcedureStartIa64StMsSymbol(pdb, reader); +// break; +// case LocalSlotIndexFieldedLILStMsSymbol.PDB_ID: +// symbol = new LocalSlotIndexFieldedLILStMsSymbol(pdb, reader); +// break; +// case ParameterSlotIndexFieldedLILStMsSymbol.PDB_ID: +// symbol = new ParameterSlotIndexFieldedLILStMsSymbol(pdb, reader); +// break; +// case AnnotationMsSymbol.PDB_ID: +// symbol = new AnnotationMsSymbol(pdb, reader); +// break; +// case GlobalManagedProcedureStMsSymbol.PDB_ID: +// symbol = new GlobalManagedProcedureStMsSymbol(pdb, reader); +// break; +// case LocalManagedProcedureStMsSymbol.PDB_ID: +// symbol = new LocalManagedProcedureStMsSymbol(pdb, reader); +// break; +// case Reserved1MsSymbol.PDB_ID: +// symbol = new Reserved1MsSymbol(pdb, reader); +// break; +// case Reserved2MsSymbol.PDB_ID: +// symbol = new Reserved2MsSymbol(pdb, reader); +// break; +// case Reserved3MsSymbol.PDB_ID: +// symbol = new Reserved3MsSymbol(pdb, reader); +// break; +// case Reserved4MsSymbol.PDB_ID: +// symbol = new Reserved4MsSymbol(pdb, reader); +// break; + case LocalManagedDataStMsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case GlobalManagedDataStMsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; +// case ManLocOrParamReltoVFPStMsSymbol.PDB_ID: +// symbol = new ManLocOrParamReltoVFPStMsSymbol(pdb, reader); +// break; +// case ManagedLocalOrParameterSIRStMsSymbol.PDB_ID: +// symbol = new ManagedLocalOrParameterSIRStMsSymbol(pdb, reader); +// break; +// case ManagedSymbolWithSlotIndexFieldStMsSymbol.PDB_ID: +// symbol = new ManagedSymbolWithSlotIndexFieldStMsSymbol(pdb, reader); +// break; +// case ManagedLocalOrParameterSIMRStMsSymbol.PDB_ID: +// symbol = new ManagedLocalOrParameterSIMRStMsSymbol(pdb, reader); +// break; +// case ManLocOrParamReltoAMPStMsSymbol.PDB_ID: +// symbol = new ManLocOrParamReltoAMPStMsSymbol(pdb, reader); +// break; +// case ManagedLocalOrParameterSIMR2StMsSymbol.PDB_ID: +// symbol = new ManagedLocalOrParameterSIMR2StMsSymbol(pdb, reader); +// break; +// case IndexForTypeReferencedByNameFromMetadataMsSymbol.PDB_ID: +// symbol = new IndexForTypeReferencedByNameFromMetadataMsSymbol(pdb, reader); +// break; +// case UsingNamespaceStMsSymbol.PDB_ID: +// symbol = new UsingNamespaceStMsSymbol(pdb, reader); +// break; +// +// // 0x1100 block +// case ObjectNameMsSymbol.PDB_ID: +// symbol = new ObjectNameMsSymbol(pdb, reader); +// break; + case Thunk32MsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case Block32MsSymbol.PDB_ID: + applier = new BlockSymbolApplier(applicator, iter); + break; + case With32MsSymbol.PDB_ID: + applier = new WithSymbolApplier(applicator, iter); + break; + case Label32MsSymbol.PDB_ID: + applier = new LabelSymbolApplier(applicator, iter); + break; +// case RegisterMsSymbol.PDB_ID: +// symbol = new RegisterMsSymbol(pdb, reader); +// break; +// case ConstantMsSymbol.PDB_ID: +// symbol = new ConstantMsSymbol(pdb, reader); +// break; + case UserDefinedTypeMsSymbol.PDB_ID: + applier = new TypedefSymbolApplier(applicator, iter); + break; + case CobolUserDefinedTypeMsSymbol.PDB_ID: + applier = new TypedefSymbolApplier(applicator, iter); + break; +// case ManyRegisterVariableMsSymbol.PDB_ID: +// symbol = new ManyRegisterVariableMsSymbol(pdb, reader); +// break; +// case BasePointerRelative32MsSymbol.PDB_ID: +// symbol = new BasePointerRelative32MsSymbol(pdb, reader); +// break; + case LocalData32MsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case GlobalData32MsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case Public32MsSymbol.PDB_ID: + applier = new PublicSymbolApplier(applicator, iter); + break; + case LocalProcedureStart32MsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case GlobalProcedureStart32MsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case RegisterRelativeAddress32MsSymbol.PDB_ID: + applier = new RegisterRelativeSymbolApplier(applicator, iter); + break; +// case LocalThreadStorage32MsSymbol.PDB_ID: +// symbol = new LocalThreadStorage32MsSymbol(pdb, reader); +// break; +// case GlobalThreadStorage32MsSymbol.PDB_ID: +// symbol = new GlobalThreadStorage32MsSymbol(pdb, reader); +// break; +// case LocalProcedureStartMipsMsSymbol.PDB_ID: +// symbol = new LocalProcedureStartMipsMsSymbol(pdb, reader); +// break; +// case GlobalProcedureStartMipsMsSymbol.PDB_ID: +// symbol = new GlobalProcedureStartMipsMsSymbol(pdb, reader); +// break; +// case Compile2MsSymbol.PDB_ID: +// symbol = new Compile2MsSymbol(pdb, reader); +// break; +// case ManyRegisterVariable2MsSymbol.PDB_ID: +// symbol = new ManyRegisterVariable2MsSymbol(pdb, reader); +// break; +// case LocalProcedureStartIa64MsSymbol.PDB_ID: +// symbol = new LocalProcedureStartIa64MsSymbol(pdb, reader); +// break; +// case GlobalProcedureStartIa64MsSymbol.PDB_ID: +// symbol = new GlobalProcedureStartIa64MsSymbol(pdb, reader); +// break; +// case LocalSlotIndexFieldedLILMsSymbol.PDB_ID: +// symbol = new LocalSlotIndexFieldedLILMsSymbol(pdb, reader); +// break; +// case ParameterSlotIndexFieldedLILMsSymbol.PDB_ID: +// symbol = new ParameterSlotIndexFieldedLILMsSymbol(pdb, reader); +// break; + case LocalManagedDataMsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; + case GlobalManagedDataMsSymbol.PDB_ID: + applier = new DataSymbolApplier(applicator, iter); + break; +// case ManLocOrParamReltoVFPMsSymbol.PDB_ID: +// symbol = new ManLocOrParamReltoVFPMsSymbol(pdb, reader); +// break; +// case ManagedLocalOrParameterSIRMsSymbol.PDB_ID: +// symbol = new ManagedLocalOrParameterSIRMsSymbol(pdb, reader); +// break; +// case ManagedSymbolWithSlotIndexFieldMsSymbol.PDB_ID: +// symbol = new ManagedSymbolWithSlotIndexFieldMsSymbol(pdb, reader); +// break; +// case ManagedLocalOrParameterSIMRMsSymbol.PDB_ID: +// symbol = new ManagedLocalOrParameterSIMRMsSymbol(pdb, reader); +// break; +// case ManLocOrParamReltoAMPMsSymbol.PDB_ID: +// symbol = new ManLocOrParamReltoAMPMsSymbol(pdb, reader); +// break; +// case ManagedLocalOrParameterSIMR2MsSymbol.PDB_ID: +// symbol = new ManagedLocalOrParameterSIMR2MsSymbol(pdb, reader); +// break; +// case UsingNamespaceMsSymbol.PDB_ID: +// symbol = new UsingNamespaceMsSymbol(pdb, reader); +// break; + case ProcedureReferenceMsSymbol.PDB_ID: + applier = new ReferenceSymbolApplier(applicator, iter); + break; + case DataReferenceMsSymbol.PDB_ID: + applier = new ReferenceSymbolApplier(applicator, iter); + break; + case LocalProcedureReferenceMsSymbol.PDB_ID: + applier = new ReferenceSymbolApplier(applicator, iter); + break; + case AnnotationReferenceMsSymbol.PDB_ID: + applier = new ReferenceSymbolApplier(applicator, iter); + break; + case TokenReferenceToManagedProcedureMsSymbol.PDB_ID: + applier = new ReferenceSymbolApplier(applicator, iter); + break; +// case GlobalManagedProcedureMsSymbol.PDB_ID: +// symbol = new GlobalManagedProcedureMsSymbol(pdb, reader); +// break; +// case LocalManagedProcedureMsSymbol.PDB_ID: +// symbol = new LocalManagedProcedureMsSymbol(pdb, reader); +// break; + case TrampolineMsSymbol.PDB_ID: + applier = new TrampolineSymbolApplier(applicator, iter); + break; +// case ManagedConstantMsSymbol.PDB_ID: +// symbol = new ManagedConstantMsSymbol(pdb, reader); +// break; +// case AttribLocOrParamReltoVFPMsSymbol.PDB_ID: +// symbol = new AttribLocOrParamReltoVFPMsSymbol(pdb, reader); +// break; +// case AttributedLocalOrParameterSIRMsSymbol.PDB_ID: +// symbol = new AttributedLocalOrParameterSIRMsSymbol(pdb, reader); +// break; +// case AttribLocOrParamReltoAMPMsSymbol.PDB_ID: +// symbol = new AttribLocOrParamReltoAMPMsSymbol(pdb, reader); +// break; +// case AttributedLocalOrParameterSIMRMsSymbol.PDB_ID: +// symbol = new AttributedLocalOrParameterSIMRMsSymbol(pdb, reader); +// break; + case SeparatedCodeFromCompilerSupportMsSymbol.PDB_ID: + applier = new SeparatedCodeSymbolApplier(applicator, iter); + break; + case LocalSymbolInOptimizedCode2005MsSymbol.PDB_ID: + applier = new LocalOptimizedSymbolApplier(applicator, iter); + break; +// case DefinedSingleAddressRange2005MsSymbol.PDB_ID: +// symbol = new DefinedSingleAddressRange2005MsSymbol(pdb, reader); +// break; +// case DefinedMultipleAddressRanges2005MsSymbol.PDB_ID: +// symbol = new DefinedMultipleAddressRanges2005MsSymbol(pdb, reader); +// break; + case PeCoffSectionMsSymbol.PDB_ID: + applier = new PeCoffSectionSymbolApplier(applicator, iter); + break; + case PeCoffGroupMsSymbol.PDB_ID: + applier = new PeCoffGroupSymbolApplier(applicator, iter); + break; +// case ExportMsSymbol.PDB_ID: +// symbol = new ExportMsSymbol(pdb, reader); +// break; +// case IndirectCallSiteInfoMsSymbol.PDB_ID: +// symbol = new IndirectCallSiteInfoMsSymbol(pdb, reader); +// break; +// case FrameSecurityCookieMsSymbol.PDB_ID: +// symbol = new FrameSecurityCookieMsSymbol(pdb, reader); +// break; +// case DiscardedByLinkMsSymbol.PDB_ID: +// symbol = new DiscardedByLinkMsSymbol(pdb, reader); +// break; +// case Compile3MsSymbol.PDB_ID: +// symbol = new Compile3MsSymbol(pdb, reader); +// break; +// case EnvironmentBlockMsSymbol.PDB_ID: +// symbol = new EnvironmentBlockMsSymbol(pdb, reader); +// break; + case LocalSymbolInOptimizedCodeMsSymbol.PDB_ID: + applier = new LocalOptimizedSymbolApplier(applicator, iter); + break; + case DefinedSingleAddressRangeMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; + case SubfieldDARMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; + case EnregisteredSymbolDARMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; + case FramePointerRelativeDARMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; + case EnregisteredFieldOfSymbolDARMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; + case FramePointerRelativeFullScopeDARMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; + case EnregisteredSymbolRelativeDARMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; + case LocalProcedure32IdMsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case GlobalProcedure32IdMsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; +// case LocalProcedureMipsIdMsSymbol.PDB_ID: +// symbol = new LocalProcedureMipsIdMsSymbol(pdb, reader); +// break; +// case GlobalProcedureMipsIdMsSymbol.PDB_ID: +// symbol = new GlobalProcedureMipsIdMsSymbol(pdb, reader); +// break; +// case LocalProcedureIa64IdMsSymbol.PDB_ID: +// symbol = new LocalProcedureIa64IdMsSymbol(pdb, reader); +// break; +// case GlobalProcedureIa64IdMsSymbol.PDB_ID: +// symbol = new GlobalProcedureIa64IdMsSymbol(pdb, reader); +// break; +// case BuildInformationMsSymbol.PDB_ID: +// symbol = new BuildInformationMsSymbol(pdb, reader); +// break; +// case InlinedFunctionCallsiteMsSymbol.PDB_ID: +// symbol = new InlinedFunctionCallsiteMsSymbol(pdb, reader); +// break; +// case InlinedFunctionEndMsSymbol.PDB_ID: +// symbol = new InlinedFunctionEndMsSymbol(pdb, reader); +// break; +// case ProcedureIdEndMsSymbol.PDB_ID: +// symbol = new ProcedureIdEndMsSymbol(pdb, reader); +// break; + case HighLevelShaderLanguageRegDimDARMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; +// case GlobalDataHLSLMsSymbol.PDB_ID: +// symbol = new GlobalDataHLSLMsSymbol(pdb, reader); +// break; +// case LocalDataHLSLMsSymbol.PDB_ID: +// symbol = new LocalDataHLSLMsSymbol(pdb, reader); +// break; +// case FileStaticMsSymbol.PDB_ID: +// symbol = new FileStaticMsSymbol(pdb, reader); +// break; +// case LocalDeferredProcedureCallGroupSharedMsSymbol.PDB_ID: +// symbol = new LocalDeferredProcedureCallGroupSharedMsSymbol(pdb, reader); +// break; + case LocalProcedureStart32DeferredProcedureCallMsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case LocalProcedure32DeferredProcedureCallIdMsSymbol.PDB_ID: + applier = new FunctionSymbolApplier(applicator, iter); + break; + case DeferredProcedureCallPointerTagRegDimDARMsSymbol.PDB_ID: + applier = new DefinedSingleAddressRangeSymbolApplier(applicator, iter); + break; +// case DeferredProcedureCallPointerTagToSymbolRecordMapMsSymbol.PDB_ID: +// symbol = new DeferredProcedureCallPointerTagToSymbolRecordMapMsSymbol(pdb, reader); +// break; +// case ArmSwitchTableMsSymbol.PDB_ID: +// symbol = new ArmSwitchTableMsSymbol(pdb, reader); +// break; +// case CalleesMsSymbol.PDB_ID: +// symbol = new CalleesMsSymbol(pdb, reader); +// break; +// case CallersMsSymbol.PDB_ID: +// symbol = new CallersMsSymbol(pdb, reader); +// break; +// case ProfileGuidedOptimizationDataMsSymbol.PDB_ID: +// symbol = new ProfileGuidedOptimizationDataMsSymbol(pdb, reader); +// break; +// case InlinedFunctionCallsiteExtendedMsSymbol.PDB_ID: +// symbol = new InlinedFunctionCallsiteExtendedMsSymbol(pdb, reader); +// break; +// case HeapAllocationSiteMsSymbol.PDB_ID: +// symbol = new HeapAllocationSiteMsSymbol(pdb, reader); +// break; +// case ModuleTypeReferenceMsSymbol.PDB_ID: +// symbol = new ModuleTypeReferenceMsSymbol(pdb, reader); +// break; +// case MiniPdbReferenceMsSymbol.PDB_ID: +// symbol = new MiniPdbReferenceMsSymbol(pdb, reader); +// break; +// case MapToMiniPdbMsSymbol.PDB_ID: +// symbol = new MapToMiniPdbMsSymbol(pdb, reader); +// break; +// case GlobalDataHLSL32MsSymbol.PDB_ID: +// symbol = new GlobalDataHLSL32MsSymbol(pdb, reader); +// break; +// case LocalDataHLSL32MsSymbol.PDB_ID: +// symbol = new LocalDataHLSL32MsSymbol(pdb, reader); +// break; +// case GlobalDataHLSL32ExtMsSymbol.PDB_ID: +// symbol = new GlobalDataHLSL32ExtMsSymbol(pdb, reader); +// break; +// case LocalDataHLSL32ExtMsSymbol.PDB_ID: +// symbol = new LocalDataHLSL32ExtMsSymbol(pdb, reader); +// break; +// case UnknownX1166MsSymbol.PDB_ID: +// // We have recently seen 1167 and 1168, which implies that 1166 must exist. +// symbol = new UnknownX1166MsSymbol(pdb, reader); +// break; +// case UnknownX1167MsSymbol.PDB_ID: +// // We have not investigated this type yet, but have seen it in VS2017 output. +// symbol = new UnknownX1167MsSymbol(pdb, reader); +// break; +// case UnknownX1168MsSymbol.PDB_ID: +// // We have not investigated this type yet, but have seen it in VS2017 output. +// symbol = new UnknownX1168MsSymbol(pdb, reader); +// break; + default: + // This should never happen (unless we missed something + // or MSFT has added new in a version we do not handle. + applicator.getPdbApplicatorMetrics().witnessCannotApplySymbolType(symbol); + applier = new NoSymbolApplier(applicator, iter); + break; + } + return applier; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java new file mode 100644 index 0000000000..70dae55db4 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java @@ -0,0 +1,236 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.io.IOException; +import java.io.Writer; +import java.util.*; + +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; + +/** + * This class represents a particular group of Symbols that came from the same PDB stream. This + * wraps the internal structure and offers mechanisms for accessing records. It does not map + * directly to an MSFT structure. + */ +public class SymbolGroup { + + private Map symbolsByOffset; + private int moduleNumber; + private List offsets; + private Map indexByOffset; + + /** + * Constructor. The starting offset is set to zero. + * @param symbolsByOffset the Map used to initialize the constructor. + * @param moduleNumber The Module number corresponding to the initializing Map + * (0 for public/global Map). + */ + public SymbolGroup(Map symbolsByOffset, int moduleNumber) { + this(symbolsByOffset, moduleNumber, 0); + } + + /** + * Constructor. + * @param symbolsByOffset the Map used to initialize the constructor. + * @param moduleNumber The Module number corresponding to the initializing Map + * (0 for public/global Map). + * @param offset the offset location to start. + */ + public SymbolGroup(Map symbolsByOffset, int moduleNumber, long offset) { + this.symbolsByOffset = symbolsByOffset; + this.moduleNumber = moduleNumber; + initOffsets(); + } + + /** + * Returns the list of symbols. These may not be in the order that they were seen. + * @return the list of symbols. + */ + public List getSymbols() { + return new ArrayList<>(symbolsByOffset.values()); + } + + /** + * Returns the module number. + * @return the module number. + */ + public int getModuleNumber() { + return moduleNumber; + + } + + /** + * Returns the number of symbols. + * @return the number of symbols. + */ + public int size() { + return symbolsByOffset.size(); + } + + /** + * Returns the list of symbol offsets in the order they were seen. + * @return the list of symbol offsets. + */ + public List getOrderedOffsets() { + return new ArrayList<>(symbolsByOffset.keySet()); + } + + /** + * Returns the set of symbol offsets. + * @return the set of symbol offsets. + */ + public Set getOffsets() { + return symbolsByOffset.keySet(); + } + + /** + * Returns the list of symbols in the order they were seen. + * @return the list of symbols. + */ + public List getOrderedSymbols() { + List symbols = new ArrayList<>(); + for (long offset : offsets) { + symbols.add(symbolsByOffset.get(offset)); + } + return symbols; + } + + /** + * Initialized the offsets list used for requesting the symbols in sequence. + */ + private void initOffsets() { + offsets = new ArrayList<>(); + indexByOffset = new HashMap<>(); + int index = 0; + for (Map.Entry entry : symbolsByOffset.entrySet()) { + offsets.add(index, entry.getKey()); + indexByOffset.put(entry.getKey(), index++); + } + } + + /** + * Debug method for dumping the symbol group + * @param writer {@link Writer} to which to dump the information. + * @throws IOException Upon IOException writing to the {@link Writer}. + */ + protected void dump(Writer writer) throws IOException { + writer.write("SymbolGroup-------------------------------------------------"); + for (Map.Entry entry : symbolsByOffset.entrySet()) { + StringBuilder builder = new StringBuilder(); + builder.append("\n------------------------------------------------------------\n"); + builder.append(String.format("Offset: 0X%08X\n", entry.getKey())); + builder.append(entry.getValue()); + writer.write(builder.toString()); + } + writer.write("\nEnd SymbolGroup---------------------------------------------\n"); + } + + AbstractMsSymbolIterator iterator() { + return new AbstractMsSymbolIterator(); + } + + //============================================================================================== + class AbstractMsSymbolIterator implements Iterator { + + private int currentIndex; + private long currentOffset; + + public AbstractMsSymbolIterator() { + currentIndex = 0; + currentOffset = 0L; + } + + @Override + public boolean hasNext() { + if (currentIndex == offsets.size()) { + return false; + } + return true; + } + + /** + * Peeks at and returns the next symbol without incrementing to the next. If none are left, then throws NoSuchElementException and + * reinitializes the state for a new iteration. + * @see #initGet() + * @return the next symbol + * @throws NoSuchElementException if there are no more elements + */ + public AbstractMsSymbol peek() throws NoSuchElementException { + if (currentIndex == offsets.size()) { + throw new NoSuchElementException("none left"); + } + long temporaryOffset = offsets.get(currentIndex); + AbstractMsSymbol symbol = symbolsByOffset.get(temporaryOffset); + if (symbol == null) { + throw new NoSuchElementException("No symbol"); + } + return symbol; + } + + @Override + public AbstractMsSymbol next() { + if (currentIndex == offsets.size()) { + throw new NoSuchElementException("none left"); + } + currentOffset = offsets.get(currentIndex++); + return symbolsByOffset.get(currentOffset); + } + + /** + * Returns the next symbol. If none are left, then throws NoSuchElementException and + * reinitializes the state for a new iteration. + * @see #initGet() + * @return the next symbol + * @throws NoSuchElementException if there are no more elements + */ + public long getCurrentOffset() { + return currentOffset; + } + + /** + * Initialized the mechanism for requesting the symbols in sequence. + * @see #hasNext() + */ + public void initGet() { + currentIndex = 0; + } + + /** + * Initialized the mechanism for requesting the symbols in sequence. + * @param offset the offset to which to initialize the mechanism. + * @see #hasNext() + */ + public void initGetByOffset(long offset) { + int index = indexByOffset.get(offset); + if (index < 0) { + index = 0; + } + currentIndex = index; + currentOffset = offset; + } + + // TODO: might not need this + /** + * Returns the module number. + * @return the module number. + */ + public int getModuleNumber() { + return moduleNumber; + } + + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java new file mode 100644 index 0000000000..e267864a89 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java @@ -0,0 +1,98 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import ghidra.app.cmd.disassemble.DisassembleCommand; +import ghidra.app.cmd.function.CreateFunctionCmd; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.TrampolineMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.listing.Function; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link TrampolineMsSymbol} symbols. + */ +public class TrampolineSymbolApplier extends AbstractMsSymbolApplier { + + private TrampolineMsSymbol symbol; + + public TrampolineSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof TrampolineMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (TrampolineMsSymbol) abstractSymbol; + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing. + } + + @Override + public void apply() throws CancelledException, PdbException { + // We know the size of this trampoline, so use it to restrict the disassembly. + Address symbolAddress = applicator.reladdr(symbol); + Address targetAddress = + applicator.reladdr(symbol.getSegmentTarget(), symbol.getOffsetTarget()); + + Function target = createNewFunction(targetAddress, 1); + Function thunk = createNewFunction(symbolAddress, symbol.getSizeOfThunk()); + if (target != null && thunk != null) { + thunk.setThunkedFunction(target); + } +// int thunkModule = findModuleNumberBySectionOffsetContribution(symbol.getSectionThunk(), +// symbol.getOffsetThunk()); +// int targetModule = findModuleNumberBySectionOffsetContribution(symbol.getSectionTarget(), +// symbol.getOffsetTarget()); + + } + + // TODO? If we wanted to be able to apply this symbol to a different address, we should + // review code in FunctionSymbolApplier. Note, however, that there are two addresses + // that need to be dealt with here, and each could have a different address with a different + // delta from the specified address. + + private Function createNewFunction(Address startAddress, long size) { + + AddressSet addressSet = new AddressSet(startAddress, startAddress.add(size)); + + if (applicator.getProgram().getListing().getInstructionAt(startAddress) == null) { + DisassembleCommand cmd = new DisassembleCommand(addressSet, null, true); // TODO: false? + cmd.applyTo(applicator.getProgram(), applicator.getCancelOnlyWrappingMonitor()); + } + + // Only create function if it does not already exist. + Function function = applicator.getProgram().getListing().getFunctionAt(startAddress); + if (function != null) { + return function; + } + CreateFunctionCmd funCmd = new CreateFunctionCmd(startAddress); + if (!funCmd.applyTo(applicator.getProgram(), applicator.getCancelOnlyWrappingMonitor())) { + applicator.appendLogMsg("Failed to apply function at address " + + startAddress.toString() + "; attempting to use possible existing function"); + } + return funCmd.getFunction(); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierParser.java new file mode 100644 index 0000000000..e06b1a49a5 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierParser.java @@ -0,0 +1,519 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.HashMap; +import java.util.Map; + +import ghidra.app.util.bin.format.pdb2.pdbreader.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; + +public class TypeApplierParser { + + private PdbApplicator applicator; + private Map appliersByRecordNumber; + + TypeApplierParser(PdbApplicator applicator) { + this.applicator = applicator; + appliersByRecordNumber = new HashMap<>(); + } + + //============================================================================================== + AbstractMsTypeApplier getApplierSpec(RecordNumber recordNumber, + Class expected) throws PdbException { + AbstractMsTypeApplier applier = getTypeApplier(recordNumber); + if (!expected.isInstance(applier)) { + throw new PdbException(applier.getClass().getSimpleName() + " seen where " + + expected.getSimpleName() + " expected for record number " + recordNumber); + } + return applier; + } + + AbstractMsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber, + Class expected) throws PdbException { + AbstractMsTypeApplier applier = getTypeApplier(recordNumber); + if (!expected.isInstance(applier)) { + if (!(applier instanceof PrimitiveTypeApplier && + ((PrimitiveTypeApplier) applier).isNoType())) { + throw new PdbException(applier.getClass().getSimpleName() + " seen where " + + expected.getSimpleName() + " expected for record number " + recordNumber); + } + } + return applier; + } + + AbstractMsTypeApplier getTypeApplier(RecordNumber recordNumber) { + AbstractMsTypeApplier applier = appliersByRecordNumber.get(recordNumber); + if (applier == null) { + applier = getTypeApplier(applicator.getPdb().getTypeRecord(recordNumber)); + appliersByRecordNumber.put(recordNumber, applier); + } + return applier; + } + + //============================================================================================== + AbstractMsTypeApplier getTypeApplier(AbstractMsType type) { + if (type == null) { + applicator.appendLogMsg("PDB Warning: No AbstractMsType for getTypeApplier"); + return null; + } + AbstractMsTypeApplier applier = null; + try { + switch (type.getPdbId()) { + case -1: + applier = new PrimitiveTypeApplier(applicator, type); + break; + + // 0x0000 block + case Modifier16MsType.PDB_ID: + applier = new ModifierTypeApplier(applicator, type); + break; + case Pointer16MsType.PDB_ID: + applier = new PointerTypeApplier(applicator, type); + break; + case Array16MsType.PDB_ID: + applier = new ArrayTypeApplier(applicator, type); + break; + case Class16MsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case Structure16MsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case Union16MsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case Enum16MsType.PDB_ID: + applier = new EnumTypeApplier(applicator, type); + break; + case Procedure16MsType.PDB_ID: + applier = new ProcedureTypeApplier(applicator, type); + break; + case MemberFunction16MsType.PDB_ID: + applier = new MemberFunctionTypeApplier(applicator, type); + break; + case VtShapeMsType.PDB_ID: + applier = new VtShapeTypeApplier(applicator, type); + break; +// case Cobol016MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case Cobol1MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case BasicArray16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case LabelMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case NullMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case NotTranMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArray16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case VirtualFunctionTablePath16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case PrecompiledType16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case EndPrecompiledTypeMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case OemDefinableString16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case TypeServerStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + + // 0x0200 block +// case Skip16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case ArgumentsList16MsType.PDB_ID: + applier = new ArgumentsListTypeApplier(applicator, type); + break; +// case DefaultArguments16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case ListMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case FieldList16MsType.PDB_ID: + applier = new FieldListTypeApplier(applicator, type); + break; +// case DerivedClassList16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case Bitfield16MsType.PDB_ID: + applier = new BitfieldTypeApplier(applicator, type); + break; +// case MethodList16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayConstBoundsUpper16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayConstBoundsLowerUpper16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayVarBoundsUpper16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayVarBoundsLowerUpper16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case ReferencedSymbolMsType.PDB_ID: + // Not evaluated/implemented yet. + break; + + // 0x400 block + case BaseClass16MsType.PDB_ID: + applier = new BaseClassTypeApplier(applicator, type); + break; + case VirtualBaseClass16MsType.PDB_ID: + applier = new BaseClassTypeApplier(applicator, type); + break; + case IndirectVirtualBaseClass16MsType.PDB_ID: + applier = new BaseClassTypeApplier(applicator, type); + break; + case EnumerateStMsType.PDB_ID: + applier = new EnumerateTypeApplier(applicator, type); + break; +// case FriendFunction16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case Index16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case Member16MsType.PDB_ID: + applier = new MemberTypeApplier(applicator, type); + break; +// case StaticMember16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case OverloadedMethod16MsType.PDB_ID: + // See note in "default" case regarding NoTypeApplier + applier = new NoTypeApplier(applicator, type); + break; + case NestedType16MsType.PDB_ID: + applier = new NestedTypeApplier(applicator, type); + break; + case VirtualFunctionTablePointer16MsType.PDB_ID: + applier = new VirtualFunctionTablePointerTypeApplier(applicator, type); + break; +// case FriendClass16MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case OneMethod16MsType.PDB_ID: + // See note in "default" case regarding NoTypeApplier + applier = new NoTypeApplier(applicator, type); + break; + case VirtualFunctionTablePointerWithOffset16MsType.PDB_ID: + applier = new VirtualFunctionTablePointerTypeApplier(applicator, type); + break; + + // 0x1000 block + case ModifierMsType.PDB_ID: + applier = new ModifierTypeApplier(applicator, type); + break; + case PointerMsType.PDB_ID: + applier = new PointerTypeApplier(applicator, type); + break; + case ArrayStMsType.PDB_ID: + applier = new ArrayTypeApplier(applicator, type); + break; + case ClassStMsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case StructureStMsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case UnionStMsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case EnumStMsType.PDB_ID: + applier = new EnumTypeApplier(applicator, type); + break; + case ProcedureMsType.PDB_ID: + applier = new ProcedureTypeApplier(applicator, type); + break; + case MemberFunctionMsType.PDB_ID: + applier = new MemberFunctionTypeApplier(applicator, type); + break; +// case Cobol0MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case BasicArrayMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case VirtualFunctionTablePathMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case PrecompiledTypeStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case OemDefinableStringMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case AliasStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case OemDefinableString2MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// + // 0x1200 block +// case SkipMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case ArgumentsListMsType.PDB_ID: + applier = new ArgumentsListTypeApplier(applicator, type); + break; +// case DefaultArgumentsStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case FieldListMsType.PDB_ID: + applier = new FieldListTypeApplier(applicator, type); + break; +// case DerivedClassListMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case BitfieldMsType.PDB_ID: + applier = new BitfieldTypeApplier(applicator, type); + break; +// case MethodListMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayConstBoundsUpperMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayConstBoundsLowerUpperMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayVarBoundsUpperMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DimensionedArrayVarBoundsLowerUpperMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + + // 0x1400 block + case BaseClassMsType.PDB_ID: + applier = new BaseClassTypeApplier(applicator, type); + break; + case VirtualBaseClassMsType.PDB_ID: + applier = new BaseClassTypeApplier(applicator, type); + break; + case IndirectVirtualBaseClassMsType.PDB_ID: + applier = new BaseClassTypeApplier(applicator, type); + break; +// case FriendFunctionStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case IndexMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case MemberStMsType.PDB_ID: + applier = new MemberTypeApplier(applicator, type); + break; +// case StaticMemberStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case OverloadedMethodStMsType.PDB_ID: + // See note in "default" case regarding NoTypeApplier + applier = new NoTypeApplier(applicator, type); + break; + case NestedTypeStMsType.PDB_ID: + applier = new NestedTypeApplier(applicator, type); + break; + case VirtualFunctionTablePointerMsType.PDB_ID: + applier = new VirtualFunctionTablePointerTypeApplier(applicator, type); + break; +// case FriendClassMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case OneMethodStMsType.PDB_ID: + // See note in "default" case regarding NoTypeApplier + applier = new NoTypeApplier(applicator, type); + break; + case VirtualFunctionTablePointerWithOffsetMsType.PDB_ID: + applier = new VirtualFunctionTablePointerTypeApplier(applicator, type); + break; + case NestedTypeExtStMsType.PDB_ID: + applier = new NestedTypeApplier(applicator, type); + break; +// case MemberModifyStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case ManagedStMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + + // 0x1500 block +// case TypeServerMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case EnumerateMsType.PDB_ID: + applier = new EnumerateTypeApplier(applicator, type); + break; + case ArrayMsType.PDB_ID: + applier = new ArrayTypeApplier(applicator, type); + break; + case ClassMsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case StructureMsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case UnionMsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; + case EnumMsType.PDB_ID: + applier = new EnumTypeApplier(applicator, type); + break; +// case DimensionedArrayMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case PrecompiledTypeMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case AliasMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case DefaultArgumentsMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case FriendFunctionMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case MemberMsType.PDB_ID: + applier = new MemberTypeApplier(applicator, type); + break; +// case StaticMemberMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case OverloadedMethodMsType.PDB_ID: + // See note in "default" case regarding NoTypeApplier + applier = new NoTypeApplier(applicator, type); + break; + case NestedTypeMsType.PDB_ID: + applier = new NestedTypeApplier(applicator, type); + break; + case OneMethodMsType.PDB_ID: + // See note in "default" case regarding NoTypeApplier + applier = new NoTypeApplier(applicator, type); + break; + case NestedTypeExtMsType.PDB_ID: + applier = new NestedTypeApplier(applicator, type); + break; +// case MemberModifyMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case ManagedMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case TypeServer2MsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case StridedArrayMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case HighLevelShaderLanguageMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case ModifierExMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case InterfaceMsType.PDB_ID: + applier = new CompositeTypeApplier(applicator, type); + break; +// case BaseInterfaceMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case VectorMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case MatrixMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case VirtualFunctionTableMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + + // 0x1600 block +// case FunctionIdMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case MemberFunctionIdMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case BuildInfoMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case SubstringListMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; +// case StringIdMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; + case UserDefinedTypeSourceAndLineMsType.PDB_ID: + applier = new UdtSourceLineTypeApplier(applicator, type); + break; + case UserDefinedTypeModuleSourceAndLineMsType.PDB_ID: + applier = new UdtSourceLineTypeApplier(applicator, type); + break; + + // If all of the above are enabled, this should never happen (unless we missed + // something or MSFT has added new in a version we do not handle. + default: + applier = new NoTypeApplier(applicator, type); + // Only adding to this cannotApplyTypes list here, and not in other + // places (above) where we might currently be using a NoTypeApplier. + // Using a NoTypeApplier in other places (above) might just be a placeholder + // until we craft the specific ways in which we would like to "apply" the + // data type information. + applicator.getPdbApplicatorMetrics().witnessCannotApplyDataType(type); + break; + } + } + catch (IllegalArgumentException e) { + try { + applier = new NoTypeApplier(applicator, type); + } + catch (IllegalArgumentException e2) { + // We did a null check above on type, so this state should not happen. + } + RecordNumber recNum = type.getRecordNumber(); + String msg = (recNum == null) ? "record" : recNum.toString(); + String message = "GhidraException on " + msg + " with PdbId " + type.getPdbId() + ": " + + e.getMessage(); + applicator.appendLogMsg(message); + PdbLog.message(message); + } + return applier; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java new file mode 100644 index 0000000000..5472e23c8b --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java @@ -0,0 +1,125 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +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.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractUserDefinedTypeMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.data.*; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractUserDefinedTypeMsSymbol} symbols. + */ +public class TypedefSymbolApplier extends AbstractMsSymbolApplier { + + DataType resolvedDataType = null; + AbstractUserDefinedTypeMsSymbol udtSymbol; + + public TypedefSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractUserDefinedTypeMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + udtSymbol = (AbstractUserDefinedTypeMsSymbol) abstractSymbol; + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing + } + + @Override + public void apply() throws PdbException, CancelledException { + resolvedDataType = applyUserDefinedTypeMsSymbol(udtSymbol); + } + + /** + * Returns the name. + * @return Name. + */ + public String getName() { + return udtSymbol.getName(); + } + + /** + * Returns the type record number. + * @return Type record number. + */ + public RecordNumber getTypeRecordNumber() { + return udtSymbol.getTypeRecordNumber(); + } + + public DataType getResolvedDataType() throws PdbException { + if (resolvedDataType == null) { + throw new PdbException("Data type not resolved"); + } + return resolvedDataType; + } + + // Typedefs + private DataType applyUserDefinedTypeMsSymbol(AbstractUserDefinedTypeMsSymbol symbol) { + + String name = symbol.getName(); + + AbstractMsTypeApplier applier = applicator.getTypeApplier(symbol.getTypeRecordNumber()); + // TODO:... NOT SURE IF WILL ALWAYS BE A DATATYPE OR WILL BE A VARIABLE OR ???? + if (applier == null) { + return null; + } + DataType dataType = applier.getDataType(); + if (dataType == null) { + return null; + } + + // This code (for Composites and Enums) circumvents a collision on the names with the + // compromise that we do not store the TypeDefDataType into the DataTypeManager. + // Another issue is that we likely already have the DataType in the DataTypeManager, + // but the TypeDefDataType also wants to create it... we would need a mechanism to + // create a TypeDefDataType which uses an existing underlying DataType. + // Note, too, that we do not compare name with dataType.getName() as the latter does not + // contain namespace information. + if (applier instanceof CompositeTypeApplier) { + CompositeTypeApplier compositeApplier = (CompositeTypeApplier) applier; + String compositeName = compositeApplier.getName(); + if (name.equals(compositeName)) { + return dataType; + } + } + else if (applier instanceof EnumTypeApplier) { + EnumTypeApplier enumApplier = (EnumTypeApplier) applier; + String enumName = enumApplier.getMsType().getName(); + if (name.equals(enumName)) { + return dataType; + } + } + + SymbolPath symbolPath = new SymbolPath(name); + CategoryPath categoryPath = + applicator.getTypedefsCategory(iter.getModuleNumber(), symbolPath); + DataType typedef = new TypedefDataType(categoryPath.getParent(), categoryPath.getName(), + dataType, applicator.getDataTypeManager()); + + return applicator.resolve(typedef); + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java new file mode 100644 index 0000000000..39a58761f9 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java @@ -0,0 +1,112 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +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.*; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, and + * {@link AbstractIndirectVirtualBaseClassMsType} types. + */ +public class UdtSourceLineTypeApplier extends AbstractMsTypeApplier { + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof UserDefinedTypeSourceAndLineMsType) && + !(type instanceof UserDefinedTypeModuleSourceAndLineMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + UdtSourceLineTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for base class applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, or + * {@link AbstractIndirectVirtualBaseClassMsType} to processes. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public UdtSourceLineTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + // The MsTypes for which we are working do not have a size in and of themselves, but the + // classes/structures to which they refer have a size, even if zero. + // For here, we are only reporting what "we" have, not what the underlying sizes are. + // ...and a value of zero is our "don't know" and "not represented" value. + @Override + public BigInteger getSize() { + return BigInteger.ZERO; + } + + /** + * Returns the offset of the Base Class within the inheriting class. + * @return the offset. + */ + public int getLineNumber() { + if (msType instanceof UserDefinedTypeSourceAndLineMsType) { + return ((UserDefinedTypeSourceAndLineMsType) msType).getLineNumber(); + } + return ((UserDefinedTypeModuleSourceAndLineMsType) msType).getLineNumber(); + } + + /** + * Returns the source file name. + * @return the source file name. null if problem recovering name. + */ + public String getSourceFileName() { + if (msType instanceof UserDefinedTypeSourceAndLineMsType) { + return ((UserDefinedTypeSourceAndLineMsType) msType).getSourceFileName(); + } + return ((UserDefinedTypeModuleSourceAndLineMsType) msType).getSourceFileName(); + } + + /** + * Returns the record number of the UDT. + * @return the record number of the UDT. + */ + public RecordNumber getUdtRecordNumber() { + if (msType instanceof UserDefinedTypeSourceAndLineMsType) { + return ((UserDefinedTypeSourceAndLineMsType) msType).getUdtRecordNumber(); + } + return ((UserDefinedTypeModuleSourceAndLineMsType) msType).getUdtRecordNumber(); + } + + @Override + public void apply() throws PdbException, CancelledException { + String filename = getSourceFileName(); + int lineNumber = getLineNumber(); + RecordNumber udtRecordNumber = getUdtRecordNumber(); + AbstractMsTypeApplier typeApplier = applicator.getTypeApplier(udtRecordNumber); + + // do nothing at the moment. + applicator.putRecordNumberByFileName(udtRecordNumber, filename); + if (msType instanceof UserDefinedTypeModuleSourceAndLineMsType) { + int moduleNumber = + ((UserDefinedTypeModuleSourceAndLineMsType) msType).getModuleNumber(); + applicator.putRecordNumberByModuleNumber(udtRecordNumber, moduleNumber); + } + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VbtManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VbtManager.java new file mode 100644 index 0000000000..3ba310a56e --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VbtManager.java @@ -0,0 +1,129 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.HashMap; +import java.util.Map; + +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.util.Msg; + +/** + * Manages virtual base table lookup for PDB classes. + */ +public class VbtManager { + + DataTypeManager dtm; + PointerDataType fallbackVbptr; + Map vbtByAddress; + + /** + * Virtual Base Table Lookup Manager + * @param dtm TODO + */ + VbtManager(DataTypeManager dtm) { + this.dtm = dtm; + vbtByAddress = new HashMap<>(); + fallbackVbptr = new PointerDataType(new IntegerDataType(dtm)); + } + + PointerDataType getFallbackVbptr() { + return fallbackVbptr; + } + + /** + * Returns the offset from the virtual base table entry + * @param address Address of virtual base table + * @param ordinal index into table + * @return the offset + * @throws PdbException if no table exists for address or no entry exists for ordinal + */ + long getOffset(Address address, int ordinal) throws PdbException { + VirtualBaseTable table = vbtByAddress.get(address); + if (table == null) { + table = createVirtualBaseTable(address); + } + VirtualBaseTableEntry entry = table.getEntry(ordinal); + if (entry == null) { + throw new PdbException( + "Virtual Base Table Entry does not exist for ordinal: " + ordinal); + } + return entry.getOffset(); + } + + VirtualBaseTable createVirtualBaseTable(Address address) { + VirtualBaseTable vbt = vbtByAddress.get(address); + if (vbt != null) { + String message = + "PDB: warning virtual base table already exists for address: " + address; + PdbLog.message(message); + Msg.info(this, message); + } + else { + vbt = new VirtualBaseTable(); + vbtByAddress.put(address, vbt); + } + return vbt; + } + + static class VirtualBaseTableEntry { + long offset; + + VirtualBaseTableEntry(long offset) { + this.offset = offset; + } + + long getOffset() { + return offset; + } + } + + static class VirtualBaseTable { + int maxSeen = -1; + Map entryByOrdinal = new HashMap<>(); + + /** + * Returns the entry from the table for the ordinal + * @param ordinal the ordinal into the table for the entry to retrieve + * @return the table entry + * @throws PdbException upon issue retrieving the entry + */ + VirtualBaseTableEntry getEntry(int ordinal) throws PdbException { + return entryByOrdinal.get(ordinal); + } + + long getOffset(int ordinal) throws PdbException { + VirtualBaseTableEntry entry = getEntry(ordinal); + if (entry == null) { + throw new PdbException("No entry in Virtual Base Table for ordinal: " + ordinal); + } + return entry.getOffset(); + } + + void addEntry(int ordinal, VirtualBaseTableEntry entry) { + entryByOrdinal.put(ordinal, entry); + maxSeen = Integer.max(maxSeen, ordinal); + } + + int getMaxOrdinal() { + return maxSeen; + } + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java new file mode 100644 index 0000000000..19f4c3ccda --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java @@ -0,0 +1,104 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; + +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.*; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractVirtualFunctionTablePointerMsType} and + * {@link AbstractVirtualFunctionTablePointerWithOffsetMsType} types. + */ +public class VirtualFunctionTablePointerTypeApplier extends AbstractMsTypeApplier { + + DataType vtShape = null; + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractVirtualFunctionTablePointerMsType) && + !(type instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + VirtualFunctionTablePointerTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for enum type applier, for transforming a enum into a + * Ghidra DataType. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link AbstractVirtualFunctionTablePointerMsType} or + * {@link AbstractVirtualFunctionTablePointerWithOffsetMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public VirtualFunctionTablePointerTypeApplier(PdbApplicator applicator, AbstractMsType msType) throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + return BigInteger.valueOf(applicator.getDataOrganization().getPointerSize()); + } + + /** + * Returns the offset of the Virtual Function Table Pointer. + * @return Name of the nested type. + */ + public int getOffset() { + if (msType instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType) { + return ((AbstractVirtualFunctionTablePointerWithOffsetMsType) msType).getOffset(); + } + return 0; + } + + /** + * Returns the name to use. + * @return Name of the pointer type. + */ + public String getMemberName() { + return "VFTablePtr" + getOffset(); + } + + @Override + public void apply() throws PdbException, CancelledException { + if (msType instanceof AbstractVirtualFunctionTablePointerMsType) { + dataType = applyPointer( + ((AbstractVirtualFunctionTablePointerMsType) msType).getPointerTypeRecordNumber()); + } + else { + dataType = applyPointer( + ((AbstractVirtualFunctionTablePointerWithOffsetMsType) msType).getPointerTypeRecordNumber()); + } + } + +// private DataType applyPointer(int pointerTypeIndex) throws PdbException { + private DataType applyPointer(RecordNumber pointerTypeRecordNumber) { + AbstractMsTypeApplier rawApplier = applicator.getTypeApplier(pointerTypeRecordNumber); + if (rawApplier instanceof PointerTypeApplier) { + return rawApplier.getDataType(); + } + applicator.appendLogMsg("cannot process " + rawApplier.getClass().getSimpleName() + "for " + + getClass().getSimpleName()); + return null; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java new file mode 100644 index 0000000000..ed541e9dfa --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java @@ -0,0 +1,110 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.format.pdb.DefaultCompositeMember; +import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.program.model.data.*; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link VtShapeMsType} types. + */ +public class VtShapeTypeApplier extends AbstractMsTypeApplier { + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof VtShapeMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + VtShapeTypeApplier.class.getSimpleName()); + } + return type; + } + + /** + * Constructor for vtshape type applier. + * @param applicator {@link PdbApplicator} for which this class is working. + * @param msType {@link VtShapeMsType} to process. + * @throws IllegalArgumentException Upon invalid arguments. + */ + public VtShapeTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { + super(applicator, validateType(msType)); + } + + @Override + public BigInteger getSize() { + return BigInteger.valueOf(applicator.getDataOrganization().getPointerSize() * + ((VtShapeMsType) msType).getCount()); + } + + /** + * Returns the name. + * @return the name. + */ + public String getName() { + return "vtshape_" + index; + } + + @Override + public void apply() throws PdbException, CancelledException { + dataType = createVtShape((VtShapeMsType) msType); + } + + // TODO: We are creating a structure for the vtshape. Is there anything different we would + // like to do instead? + private DataType createVtShape(VtShapeMsType msShape) throws CancelledException { + List list = msShape.getDescriptorList(); + // TODO: what are correct/appropriate CategoryPath and name + StructureDataType shape = new StructureDataType(applicator.getAnonymousTypesCategory(), + "vtshape" + index, 0, applicator.getDataTypeManager()); + List members = new ArrayList<>(); + int offset = 0; + for (VtShapeDescriptorMsProperty descriptor : list) { + switch (descriptor) { + case NEAR: + case FAR: + case THIN: + case OUTER: + case META: + case NEAR32: + case FAR32: + Pointer pointer = new PointerDataType(applicator.getDataTypeManager()); + Default2PdbMember member = + new Default2PdbMember(applicator, "", pointer, offset); + offset += pointer.getLength(); + members.add(member); + break; + case UNUSED: + offset += applicator.getDataOrganization().getPointerSize(); + break; + } + } + int size = applicator.getDataOrganization().getPointerSize() * msShape.getCount(); + if (!DefaultCompositeMember.applyDataTypeMembers(shape, false, size, members, + msg -> Msg.warn(this, msg), applicator.getCancelOnlyWrappingMonitor())) { + CompositeTypeApplier.clearComponents(shape); + } + return shape; // not resolved + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java new file mode 100644 index 0000000000..d8d00577f8 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java @@ -0,0 +1,69 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +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.symbol.AbstractMsSymbol; +import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractWithMsSymbol; +import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; +import ghidra.program.model.address.Address; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; + +/** + * Applier for {@link AbstractWithMsSymbol} symbols. This is not fully implemented + * because we do not know its usage or have examples, but we have implemented + * the block management portion. + */ +public class WithSymbolApplier extends AbstractMsSymbolApplier { + + private AbstractWithMsSymbol symbol; + + public WithSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + super(applicator, iter); + AbstractMsSymbol abstractSymbol = iter.next(); + if (!(abstractSymbol instanceof AbstractWithMsSymbol)) { + throw new AssertException( + "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); + } + symbol = (AbstractWithMsSymbol) abstractSymbol; + } + + @Override + public void apply() throws PdbException, CancelledException { + // TODO: We do not know if this can be applied to a program or not. We have no examples. + String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; + Msg.info(this, message); + PdbLog.message(message); + } + + @Override + public void applyTo(AbstractMsSymbolApplier applyToApplier) { + // Do nothing + } + + @Override + public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + if (applierParam instanceof FunctionSymbolApplier) { + FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; + Address address = applicator.reladdr(symbol); + // TODO: not sure if getExpression() is correct, but there is no "name." + functionSymbolApplier.beginBlock(address, symbol.getExpression(), symbol.getLength()); + } + } +} diff --git a/Ghidra/Features/PDB/src/main/java/pdb/PdbSymbolServerPlugin.java b/Ghidra/Features/PDB/src/main/java/pdb/PdbSymbolServerPlugin.java index 022a2854e8..0c3e13f657 100644 --- a/Ghidra/Features/PDB/src/main/java/pdb/PdbSymbolServerPlugin.java +++ b/Ghidra/Features/PDB/src/main/java/pdb/PdbSymbolServerPlugin.java @@ -33,6 +33,7 @@ import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.services.DataTypeManagerService; import ghidra.app.util.bin.format.pdb.*; import ghidra.app.util.bin.format.pdb.PdbParser.PdbFileType; +import ghidra.app.util.pdb.PdbProgramAttributes; import ghidra.framework.Application; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java new file mode 100644 index 0000000000..7789e04139 --- /dev/null +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java @@ -0,0 +1,180 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.*; + +import ghidra.app.util.bin.format.pdb.*; +import ghidra.program.database.ProgramBuilder; +import ghidra.program.database.ProgramDB; +import ghidra.program.database.data.DataTypeManagerDB; +import ghidra.program.model.data.*; +import ghidra.test.AbstractGhidraHeadedIntegrationTest; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Tests for the {@link DataTypeConflictHandler conflict handler} stuff. + * + * + */ +public class ConflictHandlerTest2 extends AbstractGhidraHeadedIntegrationTest { + private ProgramDB program; + private DataTypeManagerDB dtm; + private int transactionID; + + public ConflictHandlerTest2() { + super(); + } + + private void startTransaction() { + transactionID = program.startTransaction("Test"); + } + + private void endTransaction() { + program.endTransaction(transactionID, true); + } + + @Before + public void setUp() throws Exception { + program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._X64, this); + dtm = program.getDataTypeManager(); + startTransaction(); + } + + @After + public void tearDown() throws Exception { + endTransaction(); + program.release(this); + } + + @Test + public void testDataTypeConflicts() { + DataTypeConflictHandler handler = + DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER; + + // First set + Composite testStruct1 = createComposite(dtm, "outer"); + Pointer pointer1 = new PointerDataType(testStruct1, -1, dtm); + + FunctionDefinitionDataType fn1 = + new FunctionDefinitionDataType(CategoryPath.ROOT, "fn1", dtm); + fn1.setReturnType(pointer1); + fn1.setGenericCallingConvention(GenericCallingConvention.cdecl); + fn1.setArguments(new ParameterDefinition[0]); + + Composite internalStruct1 = createComposite(dtm, "inner"); + Pointer internalPointer1 = new PointerDataType(internalStruct1, -1, dtm); + + fillComposite(testStruct1, TaskMonitor.DUMMY, internalPointer1); + fillComposite(internalStruct1, TaskMonitor.DUMMY, null); + + // Second set + Composite testStruct2 = createComposite(dtm, "outer"); + Pointer pointer2 = new PointerDataType(testStruct2, -1, dtm); + + FunctionDefinitionDataType fn2 = + new FunctionDefinitionDataType(CategoryPath.ROOT, "fn2", dtm); + fn2.setReturnType(pointer2); + fn2.setGenericCallingConvention(GenericCallingConvention.cdecl); + fn2.setArguments(new ParameterDefinition[0]); + + Composite internalStruct2 = createComposite(dtm, "inner"); + Pointer internalPointer2 = new PointerDataType(internalStruct2, -1, dtm); + + fillComposite(testStruct2, TaskMonitor.DUMMY, internalPointer2); +// fillComposite(internalStruct2, monitor, null); // Without this line, we get a conflict + + // Resolve + DataType t1 = dtm.resolve(testStruct1, handler); + DataType f1 = dtm.resolve(fn1, handler); + + DataType t2 = dtm.resolve(testStruct2, handler); + DataType f2 = dtm.resolve(fn2, handler); + + System.out.println(t1.toString()); + System.out.println(f1.toString()); + System.out.println(t2.toString()); + System.out.println(f2.toString()); + } + + private static Composite createComposite(DataTypeManager dtm, String name) { + Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm); + return composite; + } + + private static void fillComposite(Composite composite, TaskMonitor monitor, DataType extra) { + List members = new ArrayList<>(); + DefaultTestPdbMember member; + int size = 8; + DataType intxy = IntegerDataType.dataType; + member = new DefaultTestPdbMember("x", intxy, 0); + members.add(member); + member = new DefaultTestPdbMember("y", intxy, 4); + members.add(member); + if (extra != null) { + member = new DefaultTestPdbMember("z", extra, 8); + members.add(member); + size += extra.getLength(); + } + try { + if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, size, members, + msg -> Msg.warn(ConflictHandlerTest2.class, msg), monitor)) { + ((Structure) composite).deleteAll(); + } + } + catch (Exception e) { + Msg.info(null, "Research exception thrown"); + } + } + + private static class DefaultTestPdbMember extends PdbMember { + + private DataType dataType; + + /** + * Default PDB member construction + * @param name member field name. + * @param dataType for the field. + * @param offset member's byte offset within the root composite. + */ + DefaultTestPdbMember(String name, DataType dataType, int offset) { + super(name, dataType.getName(), offset, null); + this.dataType = dataType; + } + + @Override + public String getDataTypeName() { + return dataType.getName(); + } + + @Override + protected WrappedDataType getDataType() throws CancelledException { + if (dataType instanceof ArrayDataType) { + int size = 1; // mocking for now + if (size == 0) { + return new WrappedDataType(dataType, true, false); + } + } + return new WrappedDataType(dataType, false, false); + } + + } +} diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java new file mode 100644 index 0000000000..5fefcebdac --- /dev/null +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java @@ -0,0 +1,8685 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +import static org.junit.Assert.assertEquals; + +import java.util.*; + +import org.junit.Ignore; +import org.junit.Test; + +import generic.test.AbstractGenericTest; +import ghidra.app.plugin.core.checksums.MyTestMemory; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressIterator; +import ghidra.program.model.data.*; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.util.LittleEndianDataConverter; +import ghidra.util.Msg; +import ghidra.util.exception.AssertException; +import ghidra.util.task.TaskMonitor; + +/** + * Unit tests for the {@link CppCompositeType}. + */ +public class CppCompositeTypeTest extends AbstractGenericTest { + + private static DataTypeManager dtm32; + private static DataTypeManager dtm64; + private static Memory memory32; + private static Memory memory64; + private static Map addressByMangledName32; + private static Map addressByMangledName64; + private static DataType vbptr32; + private static DataType vbptr64; + private static PdbVbtManager pdbVbtManager32; + private static PdbVbtManager pdbVbtManager64; + private static VbtManager vbtManager32; + private static VbtManager vbtManager64; + // Note: Currently all test have expected results based on up the COMPLEX layout. + private static CompositeLayoutMode layoutOptions = + CompositeLayoutMode.COMPLEX; + + static { + BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl(); + bitFieldPacking.setUseMSConvention(true); + + // DataOrganization based on x86-64.cspec + DataOrganizationImpl dataOrg32 = DataOrganizationImpl.getDefaultOrganization(null); + dataOrg32.setBigEndian(false); + dataOrg32.setAbsoluteMaxAlignment(0); + dataOrg32.setMachineAlignment(2); + dataOrg32.setDefaultPointerAlignment(4); + dataOrg32.setPointerSize(4); + + dataOrg32.setSizeAlignment(4, 4); + + dataOrg32.setBitFieldPacking(bitFieldPacking); + + dtm32 = new TestDummyDataTypeManager() { + HashMap dataTypeMap = new HashMap<>(); + + @Override + public DataOrganization getDataOrganization() { + return dataOrg32; + } + + @Override + public DataType addDataType(DataType dataType, DataTypeConflictHandler handler) { + // handler ignored - tests should not induce conflicts + String pathname = dataType.getPathName(); + DataType myDt = dataTypeMap.get(pathname); + if (myDt != null) { + return myDt; + } + DataType dt = dataType.clone(this); + dataTypeMap.put(pathname, dt); + return dt; + } + + @Override + public DataType findDataType(String dataTypePath) { + return dataTypeMap.get(dataTypePath); + } + + @Override + public DataType getDataType(CategoryPath path, String name) { + return super.getDataType(new DataTypePath(path, name).getPath()); + } + + @Override + public DataType getDataType(String dataTypePath) { + return dataTypeMap.get(dataTypePath); + } + }; + // DataOrganization based on x86-64.cspec + DataOrganizationImpl dataOrg64 = DataOrganizationImpl.getDefaultOrganization(null); + dataOrg64.setBigEndian(false); + dataOrg64.setAbsoluteMaxAlignment(0); + dataOrg64.setMachineAlignment(2); + dataOrg64.setDefaultPointerAlignment(8); + dataOrg64.setPointerSize(8); + + dataOrg64.setSizeAlignment(8, 8); + + dataOrg64.setBitFieldPacking(bitFieldPacking); + + dtm64 = new TestDummyDataTypeManager() { + HashMap dataTypeMap = new HashMap<>(); + + @Override + public DataOrganization getDataOrganization() { + return dataOrg64; + } + + @Override + public DataType addDataType(DataType dataType, DataTypeConflictHandler handler) { + // handler ignored - tests should not induce conflicts + String pathname = dataType.getPathName(); + DataType myDt = dataTypeMap.get(pathname); + if (myDt != null) { + return myDt; + } + DataType dt = dataType.clone(this); + dataTypeMap.put(pathname, dt); + return dt; + } + + @Override + public DataType findDataType(String dataTypePath) { + return dataTypeMap.get(dataTypePath); + } + + @Override + public DataType getDataType(CategoryPath path, String name) { + return super.getDataType(new DataTypePath(path, name).getPath()); + } + + @Override + public DataType getDataType(String dataTypePath) { + return dataTypeMap.get(dataTypePath); + } + }; + vbptr32 = new PointerDataType(new IntegerDataType(dtm32)); + vbptr64 = new PointerDataType(new IntegerDataType(dtm64)); + System.out.println("vbptr32 size: " + vbptr32.getLength()); + System.out.println("vbptr64 size: " + vbptr64.getLength()); + + createVbTables(); + + pdbVbtManager32 = new PdbVbtManager(dtm32, memory32, addressByMangledName32); + pdbVbtManager64 = new PdbVbtManager(dtm64, memory64, addressByMangledName64); + vbtManager32 = new VbtManager(dtm32); + vbtManager64 = new VbtManager(dtm64); + } + + private static void addBytesForIntegers(int[] ints, byte[] bytes, int startOffset) { + int maxOffset = startOffset + 4 * ints.length; + int index = 0; + for (int offset = startOffset; offset < maxOffset; offset += 4) { + LittleEndianDataConverter.INSTANCE.getBytes(ints[index++], bytes, offset); + } + } + + static class MemoryPreparer { + private int nextOffset = 0; + private List intArrays = new ArrayList<>(); + private List offsets = new ArrayList<>(); + private List
    addresses = new ArrayList<>(); + private MyTestMemory memory = null; + + void addIntegers(int[] integers) { + offsets.add(nextOffset); + intArrays.add(integers); + nextOffset += 4 * integers.length; + } + + List getOffsets() { + return offsets; + } + + void finalizeMemory() { + byte[] bytes = new byte[nextOffset]; + for (int index = 0; index < offsets.size(); index++) { + addBytesForIntegers(intArrays.get(index), bytes, offsets.get(index)); + } + memory = new CppCompositeTestMemory(bytes); + AddressIterator iter = memory.getAddresses(true); + if (!iter.hasNext()) { + return; + } + Address address = iter.next(); + for (int index = 0; index < offsets.size(); index++) { + addresses.add(address.add(offsets.get(index))); + } + } + + Memory getMemory() { + return memory; + } + + List
    getAddresses() { + return addresses; + } + + private static class CppCompositeTestMemory extends MyTestMemory { + public CppCompositeTestMemory(byte[] bytes) { + super(bytes); + } + + @Override + public int getInt(Address addr) throws MemoryAccessException { + byte bytes[] = new byte[4]; + int num = getBytes(addr, bytes, 0, 4); + assertEquals(num, 4); + return LittleEndianDataConverter.INSTANCE.getInt(bytes); + } + + @Override + public long getLong(Address addr) throws MemoryAccessException { + byte bytes[] = new byte[8]; + int num = getBytes(addr, bytes, 0, 8); + assertEquals(num, 8); + return LittleEndianDataConverter.INSTANCE.getLong(bytes); + } + } + } + + static void createVbTables() { + MemoryPreparer preparer32 = new MemoryPreparer(); + MemoryPreparer preparer64 = new MemoryPreparer(); + List vbtSymbols = new ArrayList<>(); + + vbtSymbols.add("??_8G@@7B@"); + preparer32.addIntegers(new int[] { 0, 8 }); + preparer64.addIntegers(new int[] { 0, 16 }); + + vbtSymbols.add("??_8H@@7B@"); + preparer32.addIntegers(new int[] { 0, 8 }); + preparer64.addIntegers(new int[] { 0, 16 }); + + vbtSymbols.add("??_8GG1@@7B@"); + preparer32.addIntegers(new int[] { 0, 8 }); + preparer64.addIntegers(new int[] { 0, 16 }); + + vbtSymbols.add("??_8GG2@@7B@"); + preparer32.addIntegers(new int[] { 0, 8 }); + preparer64.addIntegers(new int[] { 0, 16 }); + + vbtSymbols.add("??_8GG3@@7B@"); + preparer32.addIntegers(new int[] { 0, 8 }); + preparer64.addIntegers(new int[] { 0, 16 }); + +// vbtSymbols.add("??_8GG4@@7B@"); +// preparer32.addIntegers(new int[] { 0, 8}); +// preparer64.addIntegers(new int[] { 0, 16}); + + vbtSymbols.add("??_8I@@7BG@@@"); + preparer32.addIntegers(new int[] { 0, 20 }); + preparer64.addIntegers(new int[] { 0, 40 }); + + vbtSymbols.add("??_8I@@7BH@@@"); + preparer32.addIntegers(new int[] { 0, 12 }); + preparer64.addIntegers(new int[] { 0, 20 }); + +// vbtSymbols.add("??_8GX1@@7B@"); +// preparer32.addIntegers(new int[] { 0, 4 }); +// preparer64.addIntegers(new int[] { 0, 8}); + +// vbtSymbols.add("??_8HX1@@7B@"); +// preparer32.addIntegers(new int[] { 0, 4 }); +// preparer64.addIntegers(new int[] { 0, 8}); + +// vbtSymbols.add("??_8IX1@@7BGX1@@@"); +// preparer32.addIntegers(new int[] { 0, 12 }); +// preparer64.addIntegers(new int[] { 0, 24}); + +// vbtSymbols.add("??_8IX1@@7BHX1@@@"); +// preparer32.addIntegers(new int[] { 0, 8 }); +// preparer64.addIntegers(new int[] { 0, 16}); + + vbtSymbols.add("??_8G1@@7B@"); + preparer32.addIntegers(new int[] { 0, 8, 12 }); + preparer64.addIntegers(new int[] { 0, 16, 20 }); + + vbtSymbols.add("??_8H1@@7B@"); + preparer32.addIntegers(new int[] { 0, 8, 12 }); + preparer64.addIntegers(new int[] { 0, 16, 20 }); + + vbtSymbols.add("??_8I1@@7BG1@@@"); + preparer32.addIntegers(new int[] { 0, 20, 24 }); + preparer64.addIntegers(new int[] { 0, 40, 44 }); + + vbtSymbols.add("??_8I1@@7BH@@@"); + preparer32.addIntegers(new int[] { 0, 12 }); + preparer64.addIntegers(new int[] { 0, 24 }); + + vbtSymbols.add("??_8I2@@7BG@@@"); + preparer32.addIntegers(new int[] { 0, 20, 24 }); + preparer64.addIntegers(new int[] { 0, 40, 44 }); + + vbtSymbols.add("??_8I2@@7BH1@@@"); + preparer32.addIntegers(new int[] { 0, 16, 12 }); + preparer64.addIntegers(new int[] { 0, 28, 24 }); + + vbtSymbols.add("??_8I3@@7BG1@@@"); + preparer32.addIntegers(new int[] { 0, 20, 24 }); + preparer64.addIntegers(new int[] { 0, 40, 44 }); + + vbtSymbols.add("??_8I3@@7BH1@@@"); + preparer32.addIntegers(new int[] { 0, 16, 12 }); + preparer64.addIntegers(new int[] { 0, 28, 24 }); + + vbtSymbols.add("??_8I4@@7B@"); + preparer32.addIntegers(new int[] { 0, 12, 16 }); + preparer64.addIntegers(new int[] { 0, 24, 28 }); + + vbtSymbols.add("??_8I5@@7B@"); + preparer32.addIntegers(new int[] { 0, 16, 12 }); + preparer64.addIntegers(new int[] { 0, 28, 24 }); + + vbtSymbols.add("??_8J1@@7BG1@@@"); + preparer32.addIntegers(new int[] { 0, 44, 48 }); + preparer64.addIntegers(new int[] { 0, 88, 92 }); + + vbtSymbols.add("??_8J1@@7BH@@@"); + preparer32.addIntegers(new int[] { 0, 36 }); + preparer64.addIntegers(new int[] { 0, 72 }); + + vbtSymbols.add("??_8J1@@7BG@@@"); + preparer32.addIntegers(new int[] { 0, 24, 28 }); + preparer64.addIntegers(new int[] { 0, 48, 52 }); + + vbtSymbols.add("??_8J1@@7BH1@@@"); + preparer32.addIntegers(new int[] { 0, 20, 16 }); + preparer64.addIntegers(new int[] { 0, 36, 32 }); + + vbtSymbols.add("??_8J2@@7BG@@@"); + preparer32.addIntegers(new int[] { 0, 44, 48 }); + preparer64.addIntegers(new int[] { 0, 88, 92 }); + + vbtSymbols.add("??_8J2@@7BH1@@@"); + preparer32.addIntegers(new int[] { 0, 40, 36 }); + preparer64.addIntegers(new int[] { 0, 76, 72 }); + + vbtSymbols.add("??_8J2@@7BG1@@@"); + preparer32.addIntegers(new int[] { 0, 24, 28 }); + preparer64.addIntegers(new int[] { 0, 48, 52 }); + + vbtSymbols.add("??_8J2@@7BH@@@"); + preparer32.addIntegers(new int[] { 0, 16 }); + preparer64.addIntegers(new int[] { 0, 32 }); + + vbtSymbols.add("??_8J3@@7BG@@@"); + preparer32.addIntegers(new int[] { 0, 52, 56 }); + preparer64.addIntegers(new int[] { 0, 96, 100 }); + + vbtSymbols.add("??_8J3@@7BH1@@@"); + preparer32.addIntegers(new int[] { 0, 48, 44 }); + preparer64.addIntegers(new int[] { 0, 84, 80 }); + + vbtSymbols.add("??_8J3@@7BG1@@@"); + preparer32.addIntegers(new int[] { 0, 32, 36 }); + preparer64.addIntegers(new int[] { 0, 56, 60 }); + + vbtSymbols.add("??_8J3@@7BH@@@"); + preparer32.addIntegers(new int[] { 0, 24 }); + preparer64.addIntegers(new int[] { 0, 40 }); + + vbtSymbols.add("??_8J4@@7BG1@@@"); + preparer32.addIntegers(new int[] { 0, 60, 64, 68, 72, 76, 84 }); + preparer64.addIntegers(new int[] { 0, 112, 116, 120, 124, 128, 144 }); + + vbtSymbols.add("??_8J4@@7BH1@@@"); + preparer32.addIntegers(new int[] { 0, 56, 52 }); + preparer64.addIntegers(new int[] { 0, 100, 96 }); + + vbtSymbols.add("??_8J4@@7BGG1@@@"); + preparer32.addIntegers(new int[] { 0, 48 }); + preparer64.addIntegers(new int[] { 0, 80 }); + + vbtSymbols.add("??_8J4@@7BG@@@"); + preparer32.addIntegers(new int[] { 0, 32 }); + preparer64.addIntegers(new int[] { 0, 56 }); + + vbtSymbols.add("??_8J4@@7BH@@@"); + preparer32.addIntegers(new int[] { 0, 24 }); + preparer64.addIntegers(new int[] { 0, 40 }); + + vbtSymbols.add("??_8J4@@7BGG2@@@"); + preparer32.addIntegers(new int[] { 0, -4 }); + preparer64.addIntegers(new int[] { 0, -4 }); + + vbtSymbols.add("??_8J4@@7BGG3@@@"); + preparer32.addIntegers(new int[] { 0, -12 }); + preparer64.addIntegers(new int[] { 0, -20 }); + + vbtSymbols.add("??_8J5@@7BG1@@@"); + preparer32.addIntegers(new int[] { 0, 80, 84, 60, 64, 72, 88 }); + preparer64.addIntegers(new int[] { 0, 152, 156, 112, 120, 136, 160 }); + + vbtSymbols.add("??_8J5@@7BH1@@@"); + preparer32.addIntegers(new int[] { 0, 76, 72 }); + preparer64.addIntegers(new int[] { 0, 140, 136 }); + + vbtSymbols.add("??_8J5@@7BGG1@@@"); + preparer32.addIntegers(new int[] { 0, 68 }); + preparer64.addIntegers(new int[] { 0, 120 }); + + vbtSymbols.add("??_8J5@@7BG@@@"); + preparer32.addIntegers(new int[] { 0, 52 }); + preparer64.addIntegers(new int[] { 0, 96 }); + + vbtSymbols.add("??_8J5@@7BH@@@"); + preparer32.addIntegers(new int[] { 0, 44 }); + preparer64.addIntegers(new int[] { 0, 80 }); + + vbtSymbols.add("??_8J5@@7BGG2@@@"); + preparer32.addIntegers(new int[] { 0, -4 }); + preparer64.addIntegers(new int[] { 0, -8 }); + + vbtSymbols.add("??_8J5@@7BGG3@@@"); + preparer32.addIntegers(new int[] { 0, -12 }); + preparer64.addIntegers(new int[] { 0, -24 }); + + vbtSymbols.add("??_8J6@@7B@"); + preparer32.addIntegers(new int[] { -8, 8, 8, 16, 20 }); + preparer64.addIntegers(new int[] { -8, 16, 16, 32, 40 }); + + vbtSymbols.add("??_8J6@@7BGG4@@@"); + preparer32.addIntegers(new int[] { 0, 0 }); + preparer64.addIntegers(new int[] { 0, 0 }); + + vbtSymbols.add("??_8J6@@7BGG3@@@"); + preparer32.addIntegers(new int[] { 0, -4 }); + preparer64.addIntegers(new int[] { 0, -8 }); + + preparer32.finalizeMemory(); + preparer64.finalizeMemory(); + + memory32 = preparer32.getMemory(); + memory64 = preparer64.getMemory(); + + List
    addresses32 = preparer32.getAddresses(); + List
    addresses64 = preparer64.getAddresses(); + + addressByMangledName32 = new HashMap<>(); + addressByMangledName64 = new HashMap<>(); + + if (vbtSymbols.size() != addresses32.size() || vbtSymbols.size() != addresses64.size()) { + throw new AssertException("Fatal: list sizes do not match"); + } + for (int index = 0; index < vbtSymbols.size(); index++) { + addressByMangledName32.put(vbtSymbols.get(index), addresses32.get(index)); + addressByMangledName64.put(vbtSymbols.get(index), addresses64.get(index)); + } + } + + private static String convertCommentsToSpeculative(String original) { + return original.replace("(Virtual Base", "((Speculative Placement) Virtual Base"); + } + + private static CppCompositeType createStruct32(String name, int size) { + Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm32); + String mangledName = createMangledName(name, CppCompositeType.Type.STRUCT); + return CppCompositeType.createCppStructType(composite, name, mangledName, size); + } + + private static CppCompositeType createStruct64(String name, int size) { + Composite composite = new StructureDataType(CategoryPath.ROOT, name, 0, dtm64); + String mangledName = createMangledName(name, CppCompositeType.Type.STRUCT); + return CppCompositeType.createCppStructType(composite, name, mangledName, 0); + } + + private static String createMangledName(String className, CppCompositeType.Type type) { + StringBuilder builder = new StringBuilder(); + builder.append(".?A"); + switch (type) { + case UNION: + builder.append('T'); + break; + case STRUCT: + builder.append('U'); + break; + case CLASS: + builder.append('V'); + break; + default: + Msg.error(null, "Cannot handle type during testing" + type); + assert false; + } + builder.append(className); + builder.append("@@"); + return builder.toString(); + } + + private final static DataType u1 = Undefined1DataType.dataType; + //private final static DataType u2 = Undefined2DataType.dataType; + private final static DataType u4 = Undefined4DataType.dataType; + //private final static DataType u8 = Undefined8DataType.dataType; + + // Note: the problem with using the following static variables is that the process of + // processing any one requires the parents already be processed (the dependency issue) + // We could use the static version for parents in the create_struct32() methods. +// private static CppCompositeType A; +// private static CppCompositeType C; +// private static CppCompositeType CC1; +// private static CppCompositeType CC2; +// private static CppCompositeType CC3; +// private static CppCompositeType D; +// private static CppCompositeType E; +// private static CppCompositeType F; +// private static CppCompositeType G; +// private static CppCompositeType H; +// private static CppCompositeType G1; +// private static CppCompositeType H1; +// private static CppCompositeType GG1; +// private static CppCompositeType GG2; +// private static CppCompositeType GG3; +// private static CppCompositeType GG4; +// private static CppCompositeType I; +// private static CppCompositeType I1; +// private static CppCompositeType I2; +// private static CppCompositeType I3; +// private static CppCompositeType I4; +// private static CppCompositeType I5; +// private static CppCompositeType J1; +// private static CppCompositeType J2; +// private static CppCompositeType J3; +// private static CppCompositeType J4; +// private static CppCompositeType J5; +// private static CppCompositeType J6; +// static { +// A = createA_struct32(); +// C = createC_struct32(); +// CC1 = createCC1_struct32(); +// CC2 = createCC2_struct32(); +// CC3 = createCC3_struct32(); +// D = createD_struct32(C); +// E = createE_struct32(); +// F = createF_struct32(C, E); +// G = createG_struct32(C); +// H = createH_struct32(C); +// G1 = createG1_struct32(C, E); +// H1 = createH1_struct32(E, C); +// GG1 = createGG1_struct32(CC1); +// GG2 = createGG2_struct32(CC2); +// GG3 = createGG3_struct32(CC2); +// GG4 = createGG4_struct32(CC3); +// I = createI_struct32(G, H, C); +// I1 = createI1_struct32(G1, H, C, E); +// I2 = createI2_struct32(G, H1, C, E); +// I3 = createI3_struct32(G1, H1, E, C); +// I4 = createI4_struct32(G1, E, C); +// I5 = createI5_struct32(G1, E, C); // check this and I4...TODO +// J1 = createJ1_struct32(I1, I2, E, C); +// J2 = createJ2_struct32(I2, I1, C, E); +// J3 = createJ3_struct32(I2, I1, A, C, E); +// J4 = createJ4_struct32(I3, GG1, I, A, GG2, GG3, C, E, CC1, CC2); +// J5 = createJ5_struct32(I3, GG1, I, A, GG2, GG3, C, E, CC1, CC2); +// J6 = createJ6_struct32(A, GG4, GG3, CC2, CC3); +// } + + //============================================================================================== + /* + * struct A { + * char c; + * int i; + * }; + */ + static CppCompositeType createA_syntactic_struct32(VbtManager vbtManager) { + CppCompositeType A_struct = createStruct32("A", 0); + A_struct.addMember("c", u1, false, 0); + A_struct.addMember("i", u4, false, 0); + return A_struct; + } + + static CppCompositeType createA_struct32(VbtManager vbtManager) { + CppCompositeType A_struct = createStruct32("A", 8); + A_struct.addMember("c", u1, false, 0); + A_struct.addMember("i", u4, false, 4); + return A_struct; + } + + //============================================================================================== + /* + * struct A { + * char c; + * int i; + * }; + */ + static CppCompositeType createA_struct64(VbtManager vbtManager) { + CppCompositeType A_struct = createStruct64("A", 8); + A_struct.addMember("c", u1, false, 0); + A_struct.addMember("i", u4, false, 4); + return A_struct; + } + + //============================================================================================== + /* + * struct C { + * int c1; + * void cf(); + * }; + */ + static CppCompositeType createC_syntactic_struct32(VbtManager vbtManager) { + CppCompositeType C_struct = createStruct32("C", 0); + C_struct.addMember("c1", u4, false, 0); + return C_struct; + } + + static CppCompositeType createC_struct32(VbtManager vbtManager) { + CppCompositeType C_struct = createStruct32("C", 4); + C_struct.addMember("c1", u4, false, 0); + return C_struct; + } + + //============================================================================================== + /* + * struct C { + * int c1; + * void cf(); + * }; + */ + static CppCompositeType createC_struct64(VbtManager vbtManager) { + CppCompositeType C_struct = createStruct64("C", 4); + C_struct.addMember("c1", u4, false, 0); + return C_struct; + } + + //============================================================================================== + /* + * struct CC1 { + * int cc11; + * void cc1f(); + * }; + */ + static CppCompositeType createCC1_syntactic_struct32(VbtManager vbtManager) { + CppCompositeType CC1_struct = createStruct32("CC1", 0); + CC1_struct.addMember("cc11", u4, false, 0); + return CC1_struct; + } + + static CppCompositeType createCC1_struct32(VbtManager vbtManager) { + CppCompositeType CC1_struct = createStruct32("CC1", 4); + CC1_struct.addMember("cc11", u4, false, 0); + return CC1_struct; + } + + //============================================================================================== + /* + * struct CC1 { + * int cc11; + * void cc1f(); + * }; + */ + static CppCompositeType createCC1_struct64(VbtManager vbtManager) { + CppCompositeType CC1_struct = createStruct64("CC1", 4); + CC1_struct.addMember("cc11", u4, false, 0); + return CC1_struct; + } + + //============================================================================================== + /* + * struct CC2 { + * int cc21; + * void cc2f(); + * }; + */ + static CppCompositeType createCC2_syntactic_struct32(VbtManager vbtManager) { + CppCompositeType CC2_struct = createStruct32("CC2", 0); + CC2_struct.addMember("cc21", u4, false, 0); + return CC2_struct; + } + + static CppCompositeType createCC2_struct32(VbtManager vbtManager) { + CppCompositeType CC2_struct = createStruct32("CC2", 4); + CC2_struct.addMember("cc21", u4, false, 0); + return CC2_struct; + } + + //============================================================================================== + /* + * struct CC2 { + * int cc21; + * void cc2f(); + * }; + */ + static CppCompositeType createCC2_struct64(VbtManager vbtManager) { + CppCompositeType CC2_struct = createStruct64("CC2", 4); + CC2_struct.addMember("cc21", u4, false, 0); + return CC2_struct; + } + + //============================================================================================== + /* + * struct CC3 { + * void cc3f(); + * }; + */ + static CppCompositeType createCC3_struct32(VbtManager vbtManager) { + CppCompositeType CC3_struct = createStruct32("CC3", 0); //TODO size 1 or 0? + return CC3_struct; + } + + //============================================================================================== + /* + * struct CC3 { + * void cc3f(); + * }; + */ + static CppCompositeType createCC3_struct64(VbtManager vbtManager) { + CppCompositeType CC3_struct = createStruct64("CC3", 0); //TODO size 1 or 0? + return CC3_struct; + } + + //============================================================================================== + /* + * struct D : C { + * int d1; + * void df(); + * }; + */ + static CppCompositeType createD_struct32(VbtManager vbtManager) { + return createD_struct32(vbtManager, null); + } + + static CppCompositeType createD_struct32(VbtManager vbtManager, CppCompositeType C_struct) { + CppCompositeType D_struct = createStruct32("D", 8); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + D_struct.addDirectBaseClass(C_struct, 0); + D_struct.addMember("d1", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return D_struct; + } + + //============================================================================================== + /* + * struct D : C { + * int d1; + * void df(); + * }; + */ + static CppCompositeType createD_struct64(VbtManager vbtManager) { + return createD_struct64(vbtManager, null); + } + + static CppCompositeType createD_struct64(VbtManager vbtManager, CppCompositeType C_struct) { + CppCompositeType D_struct = createStruct64("D", 8); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + D_struct.addDirectBaseClass(C_struct, 0); + D_struct.addMember("d1", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return D_struct; + } + + //============================================================================================== + /* + * struct E { + * int e1; + * void ef(); + * }; + */ + static CppCompositeType createE_syntactic_struct32(VbtManager vbtManager) { + CppCompositeType E_struct = createStruct32("E", 0); + E_struct.addMember("e1", u4, false, 0); + return E_struct; + } + + static CppCompositeType createE_struct32(VbtManager vbtManager) { + CppCompositeType E_struct = createStruct32("E", 4); + E_struct.addMember("e1", u4, false, 0); + return E_struct; + } + + //============================================================================================== + /* + * struct E { + * int e1; + * void ef(); + * }; + */ + static CppCompositeType createE_struct64(VbtManager vbtManager) { + CppCompositeType E_struct = createStruct64("E", 4); + E_struct.addMember("e1", u4, false, 0); + return E_struct; + } + + //============================================================================================== + /* + * struct F : C, E { + * int f1; + * void ff(); + * }; + */ + static CppCompositeType createF_struct32(VbtManager vbtManager) { + return createF_struct32(vbtManager, null, null); + } + + static CppCompositeType createF_struct32(VbtManager vbtManager, CppCompositeType C_struct, + CppCompositeType E_struct) { + CppCompositeType F_struct = createStruct32("F", 12); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + F_struct.addDirectBaseClass(C_struct, 0); + F_struct.addDirectBaseClass(E_struct, 4); + F_struct.addMember("f1", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return F_struct; + } + + //============================================================================================== + /* + * struct F : C, E { + * int f1; + * void ff(); + * }; + */ + static CppCompositeType createF_struct64(VbtManager vbtManager) { + return createF_struct64(vbtManager, null, null); + } + + static CppCompositeType createF_struct64(VbtManager vbtManager, CppCompositeType C_struct, + CppCompositeType E_struct) { + CppCompositeType F_struct = createStruct64("F", 12); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + F_struct.addDirectBaseClass(C_struct, 0); + F_struct.addDirectBaseClass(E_struct, 4); + F_struct.addMember("f1", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return F_struct; + } + + //============================================================================================== + /* + * struct G : virtual C { + * int g1; + * void gf(); + * }; + */ + static CppCompositeType createG_syntactic_struct32(VbtManager vbtManager) { + return createG_syntactic_struct32(vbtManager, null); + } + + static CppCompositeType createG_syntactic_struct32(VbtManager vbtManager, + CppCompositeType C_struct) { + CppCompositeType G_struct = createStruct32("G", 0); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + } + G_struct.addVirtualSyntacticBaseClass(C_struct); + G_struct.addMember("g1", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return G_struct; + } + + static CppCompositeType createG_struct32(VbtManager vbtManager) { + return createG_struct32(vbtManager, null); + } + + static CppCompositeType createG_struct32(VbtManager vbtManager, CppCompositeType C_struct) { + CppCompositeType G_struct = createStruct32("G", 12); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + G_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + G_struct.addMember("g1", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return G_struct; + } + + //============================================================================================== + /* + * struct G : virtual C { + * int g1; + * void gf(); + * }; + */ + static CppCompositeType createG_struct64(VbtManager vbtManager) { + return createG_struct64(vbtManager, null); + } + + static CppCompositeType createG_struct64(VbtManager vbtManager, CppCompositeType C_struct) { + CppCompositeType G_struct = createStruct64("G", 20); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + G_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + G_struct.addMember("g1", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return G_struct; + } + + //============================================================================================== + /* + * struct H : virtual C { + * int h1; + * void hf(); + * }; + */ + static CppCompositeType createH_syntactic_struct32(VbtManager vbtManager) { + return createH_syntactic_struct32(vbtManager, null); + } + + static CppCompositeType createH_syntactic_struct32(VbtManager vbtManager, + CppCompositeType C_struct) { + CppCompositeType H_struct = createStruct32("H", 0); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + } + H_struct.addVirtualSyntacticBaseClass(C_struct); + H_struct.addMember("h1", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return H_struct; + } + + static CppCompositeType createH_struct32(VbtManager vbtManager) { + return createH_struct32(vbtManager, null); + } + + static CppCompositeType createH_struct32(VbtManager vbtManager, CppCompositeType C_struct) { + CppCompositeType H_struct = createStruct32("H", 12); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + H_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + H_struct.addMember("h1", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return H_struct; + } + + //============================================================================================== + /* + * struct H : virtual C { + * int h1; + * void hf(); + * }; + */ + static CppCompositeType createH_struct64(VbtManager vbtManager) { + return createH_struct64(vbtManager, null); + } + + static CppCompositeType createH_struct64(VbtManager vbtManager, CppCompositeType C_struct) { + CppCompositeType H_struct = createStruct64("H", 20); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + H_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + H_struct.addMember("h1", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return H_struct; + } + + //============================================================================================== + /* + * struct G1 : virtual C, virtual E { + * int g11; + * void g1f(); + * }; + */ + static CppCompositeType createG1_syntactic_struct32(VbtManager vbtManager) { + return createG1_syntactic_struct32(vbtManager, null, null); + } + + static CppCompositeType createG1_syntactic_struct32(VbtManager vbtManager, + CppCompositeType C_struct, CppCompositeType E_struct) { + CppCompositeType G1_struct = createStruct32("G1", 0); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + } + G1_struct.addVirtualSyntacticBaseClass(C_struct); + G1_struct.addVirtualSyntacticBaseClass(E_struct); + G1_struct.addMember("g11", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return G1_struct; + } + + static CppCompositeType createG1_struct32(VbtManager vbtManager) { + return createG1_struct32(vbtManager, null, null); + } + + static CppCompositeType createG1_struct32(VbtManager vbtManager, CppCompositeType C_struct, + CppCompositeType E_struct) { + CppCompositeType G1_struct = createStruct32("G1", 16); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + G1_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + G1_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + G1_struct.addMember("g11", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return G1_struct; + } + + //============================================================================================== + /* + * struct G1 : virtual C, virtual E { + * int g11; + * void g1f(); + * }; + */ + static CppCompositeType createG1_struct64(VbtManager vbtManager) { + return createG1_struct64(vbtManager, null, null); + } + + static CppCompositeType createG1_struct64(VbtManager vbtManager, CppCompositeType C_struct, + CppCompositeType E_struct) { + CppCompositeType G1_struct = createStruct64("G1", 24); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + G1_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + G1_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + G1_struct.addMember("g11", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return G1_struct; + } + + //============================================================================================== + /* + * struct H1 : virtual E, virtual C { //order reversed from G1 + * int h11; + * void h1f(); + * }; + */ + static CppCompositeType createH1_syntactic_struct32(VbtManager vbtManager) { + return createH1_syntactic_struct32(vbtManager, null, null); + } + + static CppCompositeType createH1_syntactic_struct32(VbtManager vbtManager, + CppCompositeType E_struct, CppCompositeType C_struct) { + CppCompositeType H1_struct = createStruct32("H1", 0); + try { + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + } + H1_struct.addVirtualSyntacticBaseClass(E_struct); + H1_struct.addVirtualSyntacticBaseClass(C_struct); + H1_struct.addMember("h11", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return H1_struct; + } + + static CppCompositeType createH1_struct32(VbtManager vbtManager) { + return createH1_struct32(vbtManager, null, null); + } + + static CppCompositeType createH1_struct32(VbtManager vbtManager, CppCompositeType E_struct, + CppCompositeType C_struct) { + CppCompositeType H1_struct = createStruct32("H1", 16); + try { + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + H1_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr32, 1); + H1_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 2); + H1_struct.addMember("h11", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return H1_struct; + } + + //============================================================================================== + /* + * struct H1 : virtual E, virtual C { //order reversed from G1 + * int h11; + * void h1f(); + * }; + */ + static CppCompositeType createH1_struct64(VbtManager vbtManager) { + return createH1_struct64(vbtManager, null, null); + } + + static CppCompositeType createH1_struct64(VbtManager vbtManager, CppCompositeType E_struct, + CppCompositeType C_struct) { + CppCompositeType H1_struct = createStruct64("H1", 24); + try { + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + H1_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr64, 1); + H1_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 2); + H1_struct.addMember("h11", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return H1_struct; + } + + //============================================================================================== + /* + * struct GG1 : virtual CC1 { + * int gg11; + * void gg1f(); + * }; + */ + static CppCompositeType createGG1_syntactic_struct32(VbtManager vbtManager) { + return createGG1_syntactic_struct32(vbtManager, null); + } + + static CppCompositeType createGG1_syntactic_struct32(VbtManager vbtManager, + CppCompositeType CC1_struct) { + CppCompositeType GG1_struct = createStruct32("GG1", 0); + try { + if (CC1_struct == null) { + CC1_struct = createCC1_struct32(vbtManager); + } + GG1_struct.addVirtualSyntacticBaseClass(CC1_struct); + GG1_struct.addMember("gg11", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG1_struct; + } + + static CppCompositeType createGG1_struct32(VbtManager vbtManager) { + return createGG1_struct32(vbtManager, null); + } + + static CppCompositeType createGG1_struct32(VbtManager vbtManager, CppCompositeType CC1_struct) { + CppCompositeType GG1_struct = createStruct32("GG1", 12); + try { + if (CC1_struct == null) { + CC1_struct = createCC1_struct32(vbtManager); + CC1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + GG1_struct.addDirectVirtualBaseClass(CC1_struct, 0, vbptr32, 1); + GG1_struct.addMember("gg11", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG1_struct; + } + + //============================================================================================== + /* + * struct GG1 : virtual CC1 { + * int gg11; + * void gg1f(); + * }; + */ + static CppCompositeType createGG1_struct64(VbtManager vbtManager) { + return createGG1_struct64(vbtManager, null); + } + + static CppCompositeType createGG1_struct64(VbtManager vbtManager, CppCompositeType CC1_struct) { + CppCompositeType GG1_struct = createStruct64("GG1", 20); + try { + if (CC1_struct == null) { + CC1_struct = createCC1_struct64(vbtManager); + CC1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + GG1_struct.addDirectVirtualBaseClass(CC1_struct, 0, vbptr64, 1); + GG1_struct.addMember("gg11", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG1_struct; + } + + //============================================================================================== + /* + * struct GG2 : virtual CC2 { + * int gg21; + * void gg2f(); + * }; + */ + static CppCompositeType createGG2_syntactic_struct32(VbtManager vbtManager) { + return createGG2_syntactic_struct32(vbtManager, null); + } + + static CppCompositeType createGG2_syntactic_struct32(VbtManager vbtManager, + CppCompositeType CC2_struct) { + CppCompositeType GG2_struct = createStruct32("GG2", 0); + try { + if (CC2_struct == null) { + CC2_struct = createCC2_struct32(vbtManager); + } + GG2_struct.addVirtualSyntacticBaseClass(CC2_struct); + GG2_struct.addMember("gg21", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG2_struct; + } + + static CppCompositeType createGG2_struct32(VbtManager vbtManager) { + return createGG2_struct32(vbtManager, null); + } + + static CppCompositeType createGG2_struct32(VbtManager vbtManager, CppCompositeType CC2_struct) { + CppCompositeType GG2_struct = createStruct32("GG2", 12); + try { + if (CC2_struct == null) { + CC2_struct = createCC2_struct32(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + GG2_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbptr32, 1); + GG2_struct.addMember("gg21", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG2_struct; + } + + //============================================================================================== + /* + * struct GG2 : virtual CC2 { + * int gg21; + * void gg2f(); + * }; + */ + static CppCompositeType createGG2_struct64(VbtManager vbtManager) { + return createGG2_struct64(vbtManager, null); + } + + static CppCompositeType createGG2_struct64(VbtManager vbtManager, CppCompositeType CC2_struct) { + CppCompositeType GG2_struct = createStruct64("GG2", 20); + try { + if (CC2_struct == null) { + CC2_struct = createCC2_struct64(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + GG2_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbptr64, 1); + GG2_struct.addMember("gg21", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG2_struct; + } + + //============================================================================================== + /* + * struct GG3 : virtual CC2 { + * int gg31; + * void gg3f(); + * }; + */ + static CppCompositeType createGG3_syntactic_struct32(VbtManager vbtManager) { + return createGG3_syntactic_struct32(vbtManager, null); + } + + static CppCompositeType createGG3_syntactic_struct32(VbtManager vbtManager, + CppCompositeType CC2_struct) { + CppCompositeType GG3_struct = createStruct32("GG3", 0); + try { + if (CC2_struct == null) { + CC2_struct = createCC2_struct32(vbtManager); + } + GG3_struct.addVirtualSyntacticBaseClass(CC2_struct); + GG3_struct.addMember("gg31", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG3_struct; + } + + static CppCompositeType createGG3_struct32(VbtManager vbtManager) { + return createGG3_struct32(vbtManager, null); + } + + static CppCompositeType createGG3_struct32(VbtManager vbtManager, CppCompositeType CC2_struct) { + CppCompositeType GG3_struct = createStruct32("GG3", 12); + try { + if (CC2_struct == null) { + CC2_struct = createCC2_struct32(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + GG3_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbptr32, 1); + GG3_struct.addMember("gg31", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG3_struct; + } + + //============================================================================================== + /* + * struct GG3 : virtual CC2 { + * int gg31; + * void gg3f(); + * }; + */ + static CppCompositeType createGG3_struct64(VbtManager vbtManager) { + return createGG3_struct64(vbtManager, null); + } + + static CppCompositeType createGG3_struct64(VbtManager vbtManager, CppCompositeType CC2_struct) { + CppCompositeType GG3_struct = createStruct64("GG3", 20); + try { + if (CC2_struct == null) { + CC2_struct = createCC2_struct64(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + GG3_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbptr64, 1); + GG3_struct.addMember("gg31", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG3_struct; + } + + //============================================================================================== + /* + * struct GG4 : virtual CC3 { + * int gg41; + * void gg5f(); + * }; + */ + static CppCompositeType createGG4_struct32(VbtManager vbtManager) { + return createGG4_struct32(vbtManager, null); + } + + static CppCompositeType createGG4_struct32(VbtManager vbtManager, CppCompositeType CC3_struct) { + CppCompositeType GG4_struct = createStruct32("GG4", 8); + try { + if (CC3_struct == null) { + CC3_struct = createCC3_struct32(vbtManager); + CC3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + GG4_struct.addDirectVirtualBaseClass(CC3_struct, 0, vbptr32, 1); + GG4_struct.addMember("gg41", u4, false, 4); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG4_struct; + } + + //============================================================================================== + /* + * struct GG4 : virtual CC3 { + * int gg41; + * void gg5f(); + * }; + */ + static CppCompositeType createGG4_struct64(VbtManager vbtManager) { + return createGG4_struct64(vbtManager, null); + } + + static CppCompositeType createGG4_struct64(VbtManager vbtManager, CppCompositeType CC3_struct) { + CppCompositeType GG4_struct = createStruct64("GG4", 16); + try { + if (CC3_struct == null) { + CC3_struct = createCC3_struct64(vbtManager); + CC3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + GG4_struct.addDirectVirtualBaseClass(CC3_struct, 0, vbptr64, 1); + GG4_struct.addMember("gg41", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return GG4_struct; + } + + //============================================================================================== + /* + * struct I : G, H { + * int i1; + * void _if(); + * }; + */ + static CppCompositeType createI_syntactic_struct32(VbtManager vbtManager) { + return createI_syntactic_struct32(vbtManager, null, null, null); + } + + static CppCompositeType createI_syntactic_struct32(VbtManager vbtManager, + CppCompositeType G_struct, CppCompositeType H_struct, CppCompositeType C_struct) { + CppCompositeType I_struct = createStruct32("I", 0); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + } + // Could be problem if only one of G or H is null: won't have same C. + if (G_struct == null) { + G_struct = createG_struct32(vbtManager, C_struct); + } + if (H_struct == null) { + H_struct = createH_struct32(vbtManager, C_struct); + } + I_struct.addDirectSyntacticBaseClass(G_struct); + I_struct.addDirectSyntacticBaseClass(H_struct); + I_struct.addMember("i1", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I_struct; + } + + static CppCompositeType createI_struct32(VbtManager vbtManager) { + return createI_struct32(vbtManager, null, null, null); + } + + static CppCompositeType createI_struct32(VbtManager vbtManager, CppCompositeType G_struct, + CppCompositeType H_struct, CppCompositeType C_struct) { + CppCompositeType I_struct = createStruct32("I", 24); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + // Could be problem if only one of G or H is null: won't have same C. + if (G_struct == null) { + G_struct = createG_struct32(vbtManager, C_struct); + G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (H_struct == null) { + H_struct = createH_struct32(vbtManager, C_struct); + H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + I_struct.addDirectBaseClass(G_struct, 0); + I_struct.addDirectBaseClass(H_struct, 8); + I_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + I_struct.addMember("i1", u4, false, 16); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I_struct; + } + + //============================================================================================== + /* + * struct I : G, H { + * int i1; + * void _if(); + * }; + */ + static CppCompositeType createI_struct64(VbtManager vbtManager) { + return createI_struct64(vbtManager, null, null, null); + } + + static CppCompositeType createI_struct64(VbtManager vbtManager, CppCompositeType G_struct, + CppCompositeType H_struct, CppCompositeType C_struct) { + CppCompositeType I_struct = createStruct64("I", 44); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + // Could be problem if only one of G or H is null: won't have same C. + if (G_struct == null) { + G_struct = createG_struct64(vbtManager, C_struct); + G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (H_struct == null) { + H_struct = createH_struct64(vbtManager, C_struct); + H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + I_struct.addDirectBaseClass(G_struct, 0); + I_struct.addDirectBaseClass(H_struct, 16); + I_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + I_struct.addMember("i1", u4, false, 32); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I_struct; + } + + //============================================================================================== + /* + * struct I1 : G1, H { + * int i11; + * void _i1f(); + * }; + */ + static CppCompositeType createI1_struct32(VbtManager vbtManager) { + return createI1_struct32(vbtManager, null, null, null, null); + } + + static CppCompositeType createI1_struct32(VbtManager vbtManager, CppCompositeType G1_struct, + CppCompositeType H_struct, CppCompositeType C_struct, CppCompositeType E_struct) { + CppCompositeType I1_struct = createStruct32("I1", 28); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (G1_struct == null) { + G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (H_struct == null) { + H_struct = createH_struct32(vbtManager, C_struct); + H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + I1_struct.addDirectBaseClass(G1_struct, 0); + I1_struct.addDirectBaseClass(H_struct, 8); + I1_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + I1_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + I1_struct.addMember("i11", u4, false, 16); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I1_struct; + } + + //============================================================================================== + /* + * struct I1 : G1, H { + * int i11; + * void _i1f(); + * }; + */ + static CppCompositeType createI1_struct64(VbtManager vbtManager) { + return createI1_struct64(vbtManager, null, null, null, null); + } + + static CppCompositeType createI1_struct64(VbtManager vbtManager, CppCompositeType G1_struct, + CppCompositeType H_struct, CppCompositeType C_struct, CppCompositeType E_struct) { + CppCompositeType I1_struct = createStruct64("I1", 48); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (G1_struct == null) { + G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (H_struct == null) { + H_struct = createH_struct64(vbtManager, C_struct); + H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + I1_struct.addDirectBaseClass(G1_struct, 0); + I1_struct.addDirectBaseClass(H_struct, 16); + I1_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + I1_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + I1_struct.addMember("i11", u4, false, 32); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I1_struct; + } + + //============================================================================================== + /* + * struct I2 : G, H1 { + * int i21; + * void _i2f(); + * }; + */ + static CppCompositeType createI2_struct32(VbtManager vbtManager) { + return createI2_struct32(vbtManager, null, null, null, null); + } + + static CppCompositeType createI2_struct32(VbtManager vbtManager, CppCompositeType G_struct, + CppCompositeType H1_struct, CppCompositeType C_struct, CppCompositeType E_struct) { + CppCompositeType I2_struct = createStruct32("I2", 28); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (G_struct == null) { + G_struct = createG_struct32(vbtManager, C_struct); + G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (H1_struct == null) { + H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); + H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + I2_struct.addDirectBaseClass(G_struct, 0); + I2_struct.addDirectBaseClass(H1_struct, 8); + I2_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + I2_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + I2_struct.addMember("i21", u4, false, 16); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I2_struct; + } + + //============================================================================================== + /* + * struct I2 : G, H1 { + * int i21; + * void _i2f(); + * }; + */ + static CppCompositeType createI2_struct64(VbtManager vbtManager) { + return createI2_struct64(vbtManager, null, null, null, null); + } + + static CppCompositeType createI2_struct64(VbtManager vbtManager, CppCompositeType G_struct, + CppCompositeType H1_struct, CppCompositeType C_struct, CppCompositeType E_struct) { + CppCompositeType I2_struct = createStruct64("I2", 48); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (G_struct == null) { + G_struct = createG_struct64(vbtManager, C_struct); + G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (H1_struct == null) { + H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); + H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + I2_struct.addDirectBaseClass(G_struct, 0); + I2_struct.addDirectBaseClass(H1_struct, 16); + I2_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + I2_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + I2_struct.addMember("i21", u4, false, 32); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I2_struct; + } + + //============================================================================================== + /* + * struct I3 : G1, H1 { + * int i31; + * void _i3f(); + * }; + */ + static CppCompositeType createI3_syntactic_struct32(VbtManager vbtManager) { + return createI3_syntactic_struct32(vbtManager, null, null, null, null); + } + + static CppCompositeType createI3_syntactic_struct32(VbtManager vbtManager, + CppCompositeType G1_struct, CppCompositeType H1_struct, CppCompositeType E_struct, + CppCompositeType C_struct) { + CppCompositeType I3_struct = createStruct32("I3", 8); + try { + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + } + if (G1_struct == null) { + G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + } + if (H1_struct == null) { + H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); + } + I3_struct.addDirectSyntacticBaseClass(G1_struct); + I3_struct.addDirectSyntacticBaseClass(H1_struct); + I3_struct.addMember("i31", u4, false, 0); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I3_struct; + } + + static CppCompositeType createI3_struct32(VbtManager vbtManager) { + return createI3_struct32(vbtManager, null, null, null, null); + } + + static CppCompositeType createI3_struct32(VbtManager vbtManager, CppCompositeType G1_struct, + CppCompositeType H1_struct, CppCompositeType E_struct, CppCompositeType C_struct) { + CppCompositeType I3_struct = createStruct32("I3", 28); + try { + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (G1_struct == null) { + G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (H1_struct == null) { + H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); + H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + I3_struct.addDirectBaseClass(G1_struct, 0); + I3_struct.addDirectBaseClass(H1_struct, 8); + I3_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + I3_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + I3_struct.addMember("i31", u4, false, 16); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I3_struct; + } + + //============================================================================================== + /* + * struct I3 : G1, H1 { + * int i31; + * void _i3f(); + * }; + */ + static CppCompositeType createI3_struct64(VbtManager vbtManager) { + return createI3_struct64(vbtManager, null, null, null, null); + } + + static CppCompositeType createI3_struct64(VbtManager vbtManager, CppCompositeType G1_struct, + CppCompositeType H1_struct, CppCompositeType E_struct, CppCompositeType C_struct) { + CppCompositeType I3_struct = createStruct64("I3", 48); + try { + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (G1_struct == null) { + G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (H1_struct == null) { + H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); + H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + I3_struct.addDirectBaseClass(G1_struct, 0); + I3_struct.addDirectBaseClass(H1_struct, 16); + I3_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + I3_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + I3_struct.addMember("i31", u4, false, 32); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I3_struct; + } + + //============================================================================================== + /* + * struct I4 : G1, virtual E, virtual C { + * int i41; + * void _i4f(); + * }; + */ + static CppCompositeType createI4_struct32(VbtManager vbtManager) { + return createI4_struct32(vbtManager, null, null, null); + } + + static CppCompositeType createI4_struct32(VbtManager vbtManager, CppCompositeType G1_struct, + CppCompositeType E_struct, CppCompositeType C_struct) { + CppCompositeType I4_struct = createStruct32("I4", 20); + try { + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (G1_struct == null) { + G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + I4_struct.addDirectBaseClass(G1_struct, 0); + I4_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + I4_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + I4_struct.addMember("i41", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I4_struct; + } + + //============================================================================================== + /* + * struct I4 : G1, virtual E, virtual C { + * int i41; + * void _i4f(); + * }; + */ + static CppCompositeType createI4_struct64(VbtManager vbtManager) { + return createI4_struct64(vbtManager, null, null, null); + } + + static CppCompositeType createI4_struct64(VbtManager vbtManager, CppCompositeType G1_struct, + CppCompositeType E_struct, CppCompositeType C_struct) { + CppCompositeType I4_struct = createStruct64("I4", 32); + try { + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (G1_struct == null) { + G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + I4_struct.addDirectBaseClass(G1_struct, 0); + I4_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + I4_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + I4_struct.addMember("i41", u4, false, 16); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I4_struct; + } + + //============================================================================================== + /* + * struct I5 : virtual E, virtual C, G1 { + * int i51; + * void _i5f(); + * }; + */ + static CppCompositeType createI5_struct32(VbtManager vbtManager) { + return createI5_struct32(vbtManager, null, null, null); + } + + static CppCompositeType createI5_struct32(VbtManager vbtManager, CppCompositeType G1_struct, + CppCompositeType E_struct, CppCompositeType C_struct) { + CppCompositeType I5_struct = createStruct32("I5", 20); + try { + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (G1_struct == null) { + G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + I5_struct.addDirectBaseClass(G1_struct, 0); + I5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); // check this and I4...TODO + I5_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + I5_struct.addMember("i51", u4, false, 8); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I5_struct; + } + + //============================================================================================== + /* + * struct I5 : virtual E, virtual C, G1 { + * int i51; + * void _i5f(); + * }; + */ + static CppCompositeType createI5_struct64(VbtManager vbtManager) { + return createI5_struct64(null, null, null, vbtManager); + } + + static CppCompositeType createI5_struct64(CppCompositeType G1_struct, CppCompositeType E_struct, + CppCompositeType C_struct, VbtManager vbtManager) { + CppCompositeType I5_struct = createStruct64("I5", 32); + try { + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (G1_struct == null) { + G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + I5_struct.addDirectBaseClass(G1_struct, 0); + I5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); // check this and I4...TODO + I5_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + I5_struct.addMember("i51", u4, false, 16); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return I5_struct; + } + + //============================================================================================== + /* + * struct J1 : I1, I2 { + * int j11; + * void j1f(); + * }; + */ + static CppCompositeType createJ1_struct32(VbtManager vbtManager) { + return createJ1_struct32(vbtManager, null, null, null, null); + } + + static CppCompositeType createJ1_struct32(VbtManager vbtManager, CppCompositeType I1_struct, + CppCompositeType I2_struct, CppCompositeType E_struct, CppCompositeType C_struct) { + CppCompositeType J1_struct = createStruct32("J1", 52); + try { + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I1_struct == null) { + CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); + I1_struct = createI1_struct32(vbtManager, G1_struct, H_struct, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I2_struct == null) { + CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); + CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); + I2_struct = createI2_struct32(vbtManager, G_struct, H1_struct, C_struct, E_struct); + G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + J1_struct.addDirectBaseClass(I1_struct, 0); + J1_struct.addDirectBaseClass(I2_struct, 20); + J1_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + J1_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + J1_struct.addMember("j11", u4, false, 40); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J1_struct; + } + + //============================================================================================== + /* + * struct J1 : I1, I2 { + * int j11; + * void j1f(); + * }; + */ + static CppCompositeType createJ1_struct64(VbtManager vbtManager) { + return createJ1_struct64(null, null, null, null, vbtManager); + } + + static CppCompositeType createJ1_struct64(CppCompositeType I1_struct, + CppCompositeType I2_struct, CppCompositeType E_struct, CppCompositeType C_struct, + VbtManager vbtManager) { + CppCompositeType J1_struct = createStruct64("J1", 96); + try { + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I1_struct == null) { + CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); + I1_struct = createI1_struct64(vbtManager, G1_struct, H_struct, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I2_struct == null) { + CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); + CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); + I2_struct = createI2_struct64(vbtManager, G_struct, H1_struct, C_struct, E_struct); + G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + J1_struct.addDirectBaseClass(I1_struct, 0); + J1_struct.addDirectBaseClass(I2_struct, 40); + J1_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + J1_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + J1_struct.addMember("j11", u4, false, 80); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J1_struct; + } + + //============================================================================================== + /* + * struct J2 : I2, I1 { + * int j21; + * void j2f(); + * }; + */ + static CppCompositeType createJ2_struct32(VbtManager vbtManager) { + return createJ2_struct32(vbtManager, null, null, null, null); + } + + static CppCompositeType createJ2_struct32(VbtManager vbtManager, CppCompositeType I2_struct, + CppCompositeType I1_struct, CppCompositeType C_struct, CppCompositeType E_struct) { + CppCompositeType J2_struct = createStruct32("J2", 52); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I2_struct == null) { + CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); + CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); + I2_struct = createI2_struct32(vbtManager, G_struct, H1_struct, C_struct, E_struct); + G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I1_struct == null) { + CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); + I1_struct = createI1_struct32(vbtManager, G1_struct, H_struct, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + J2_struct.addDirectBaseClass(I2_struct, 0); + J2_struct.addDirectBaseClass(I1_struct, 20); + J2_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + J2_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + J2_struct.addMember("j21", u4, false, 40); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J2_struct; + } + + //============================================================================================== + /* + * struct J2 : I2, I1 { + * int j21; + * void j2f(); + * }; + */ + static CppCompositeType createJ2_struct64(VbtManager vbtManager) { + return createJ2_struct64(vbtManager, null, null, null, null); + } + + static CppCompositeType createJ2_struct64(VbtManager vbtManager, CppCompositeType I2_struct, + CppCompositeType I1_struct, CppCompositeType C_struct, CppCompositeType E_struct) { + CppCompositeType J2_struct = createStruct64("J2", 96); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I2_struct == null) { + CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); + CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); + I2_struct = createI2_struct64(vbtManager, G_struct, H1_struct, C_struct, E_struct); + G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I1_struct == null) { + CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); + I1_struct = createI1_struct64(vbtManager, G1_struct, H_struct, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + J2_struct.addDirectBaseClass(I2_struct, 0); + J2_struct.addDirectBaseClass(I1_struct, 40); + J2_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + J2_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + J2_struct.addMember("j21", u4, false, 80); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J2_struct; + } + + //============================================================================================== + /* + * struct J3 : I2, I1, A { + * int j31; + * void j3f(); + * }; + */ + static CppCompositeType createJ3_struct32(VbtManager vbtManager) { + return createJ3_struct32(vbtManager, null, null, null, null, null); + } + + static CppCompositeType createJ3_struct32(VbtManager vbtManager, CppCompositeType I2_struct, + CppCompositeType I1_struct, CppCompositeType A_struct, CppCompositeType C_struct, + CppCompositeType E_struct) { + CppCompositeType J3_struct = createStruct32("J3", 60); + try { + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I2_struct == null) { + CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); + CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); + I2_struct = createI2_struct32(vbtManager, G_struct, H1_struct, C_struct, E_struct); + G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I1_struct == null) { + CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); + I1_struct = createI1_struct32(vbtManager, G1_struct, H_struct, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (A_struct == null) { + A_struct = createA_struct32(vbtManager); + A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + J3_struct.addDirectBaseClass(I2_struct, 0); + J3_struct.addDirectBaseClass(I1_struct, 20); + J3_struct.addDirectBaseClass(A_struct, 40); + J3_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + J3_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + J3_struct.addMember("j31", u4, false, 48); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J3_struct; + } + + //============================================================================================== + /* + * struct J3 : I2, I1, A { + * int j31; + * void j3f(); + * }; + */ + static CppCompositeType createJ3_struct64(VbtManager vbtManager) { + return createJ3_struct64(vbtManager, null, null, null, null, null); + } + + static CppCompositeType createJ3_struct64(VbtManager vbtManager, CppCompositeType I2_struct, + CppCompositeType I1_struct, CppCompositeType A_struct, CppCompositeType C_struct, + CppCompositeType E_struct) { + CppCompositeType J3_struct = createStruct64("J3", 104); + try { + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I2_struct == null) { + CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); + CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); + I2_struct = createI2_struct64(vbtManager, G_struct, H1_struct, C_struct, E_struct); + G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I1_struct == null) { + CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); + I1_struct = createI1_struct32(vbtManager, G1_struct, H_struct, C_struct, E_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (A_struct == null) { + A_struct = createA_struct64(vbtManager); + A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + J3_struct.addDirectBaseClass(I2_struct, 0); + J3_struct.addDirectBaseClass(I1_struct, 40); + J3_struct.addDirectBaseClass(A_struct, 80); + J3_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + J3_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + J3_struct.addMember("j31", u4, false, 88); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J3_struct; + } + + //============================================================================================== + /* + * struct J4 : I3, GG1, I, A, virtual GG2, virtual GG3 { + * int j41; + * void j4f(); + * }; + */ + static CppCompositeType createJ4_struct32(VbtManager vbtManager) { + return createJ4_struct32(vbtManager, null, null, null, null, null, null, null, null, null, + null); + } + + static CppCompositeType createJ4_struct32(VbtManager vbtManager, CppCompositeType I3_struct, + CppCompositeType GG1_struct, CppCompositeType I_struct, CppCompositeType A_struct, + CppCompositeType GG2_struct, CppCompositeType GG3_struct, CppCompositeType C_struct, + CppCompositeType E_struct, CppCompositeType CC1_struct, CppCompositeType CC2_struct) { + CppCompositeType J4_struct = createStruct32("J4", 92); + try { + if (A_struct == null) { + A_struct = createA_struct32(vbtManager); + A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (CC1_struct == null) { + CC1_struct = createCC1_struct32(vbtManager); + CC1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (CC2_struct == null) { + CC2_struct = createCC2_struct32(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I3_struct == null) { + CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); + I3_struct = createI3_struct32(vbtManager, G1_struct, H1_struct, E_struct, C_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (GG1_struct == null) { + GG1_struct = createGG1_struct32(vbtManager, CC1_struct); + GG1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I_struct == null) { + CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); + CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); + I_struct = createI_struct32(vbtManager, G_struct, H_struct, C_struct); + G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (GG2_struct == null) { + GG2_struct = createGG2_struct32(vbtManager, CC2_struct); + GG2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (GG3_struct == null) { + GG3_struct = createGG3_struct32(vbtManager, CC2_struct); + GG3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + J4_struct.addDirectBaseClass(I3_struct, 0); + J4_struct.addDirectBaseClass(GG1_struct, 20); + J4_struct.addDirectBaseClass(I_struct, 28); + J4_struct.addDirectBaseClass(A_struct, 48); + J4_struct.addDirectVirtualBaseClass(GG2_struct, 0, vbptr32, 5); + J4_struct.addDirectVirtualBaseClass(GG3_struct, 0, vbptr32, 6); + J4_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + J4_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + J4_struct.addIndirectVirtualBaseClass(CC1_struct, 0, vbptr32, 3); + J4_struct.addIndirectVirtualBaseClass(CC2_struct, 0, vbptr32, 4); + J4_struct.addMember("j41", u4, false, 56); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J4_struct; + } + + //============================================================================================== + /* + * struct J4 : I3, GG1, I, A, virtual GG2, virtual GG3 { + * int j41; + * void j4f(); + * }; + */ + static CppCompositeType createJ4_struct64(VbtManager vbtManager) { + return createJ4_struct64(vbtManager, null, null, null, null, null, null, null, null, null, + null); + } + + static CppCompositeType createJ4_struct64(VbtManager vbtManager, CppCompositeType I3_struct, + CppCompositeType GG1_struct, CppCompositeType I_struct, CppCompositeType A_struct, + CppCompositeType GG2_struct, CppCompositeType GG3_struct, CppCompositeType C_struct, + CppCompositeType E_struct, CppCompositeType CC1_struct, CppCompositeType CC2_struct) { + CppCompositeType J4_struct = createStruct64("J4", 160); + try { + if (A_struct == null) { + A_struct = createA_struct64(vbtManager); + A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (CC1_struct == null) { + CC1_struct = createCC1_struct64(vbtManager); + CC1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (CC2_struct == null) { + CC2_struct = createCC2_struct64(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I3_struct == null) { + CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); + I3_struct = createI3_struct32(vbtManager, G1_struct, H1_struct, E_struct, C_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (GG1_struct == null) { + GG1_struct = createGG1_struct64(vbtManager, CC1_struct); + GG1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I_struct == null) { + CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); + CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); + I_struct = createI_struct32(vbtManager, G_struct, H_struct, C_struct); + G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (GG2_struct == null) { + GG2_struct = createGG2_struct64(vbtManager, CC2_struct); + GG2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (GG3_struct == null) { + GG3_struct = createGG3_struct64(vbtManager, CC2_struct); + GG3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + J4_struct.addDirectBaseClass(I3_struct, 0); + J4_struct.addDirectBaseClass(GG1_struct, 40); + J4_struct.addDirectBaseClass(I_struct, 56); + J4_struct.addDirectBaseClass(A_struct, 96); + J4_struct.addDirectVirtualBaseClass(GG2_struct, 0, vbptr64, 5); + J4_struct.addDirectVirtualBaseClass(GG3_struct, 0, vbptr64, 6); + J4_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr64, 1); + J4_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); + J4_struct.addIndirectVirtualBaseClass(CC1_struct, 0, vbptr64, 3); + J4_struct.addIndirectVirtualBaseClass(CC2_struct, 0, vbptr64, 4); + J4_struct.addMember("j41", u4, false, 104); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J4_struct; + } + + //============================================================================================== + /* + * struct J4 : virtual GG2, virtual GG3, I3, GG1, I, A { + * int j51; + * void j5f(); + * }; + */ + static CppCompositeType createJ5_syntactic_struct32(VbtManager vbtManager) { + return createJ5_syntactic_struct32(vbtManager, null, null, null, null, null, null, null, + null, null, null); + } + + static CppCompositeType createJ5_syntactic_struct32(VbtManager vbtManager, + CppCompositeType I3_struct, CppCompositeType GG1_struct, CppCompositeType I_struct, + CppCompositeType A_struct, CppCompositeType GG2_struct, CppCompositeType GG3_struct, + CppCompositeType C_struct, CppCompositeType E_struct, CppCompositeType CC1_struct, + CppCompositeType CC2_struct) { + CppCompositeType J5_struct = createStruct32("J5", 0); // TODO need without size + try { + if (A_struct == null) { + A_struct = createA_syntactic_struct32(vbtManager); + } + if (C_struct == null) { + C_struct = createC_syntactic_struct32(vbtManager); + } + if (E_struct == null) { + E_struct = createE_syntactic_struct32(vbtManager); + } + if (CC1_struct == null) { + CC1_struct = createCC1_syntactic_struct32(vbtManager); + } + if (CC2_struct == null) { + CC2_struct = createCC2_syntactic_struct32(vbtManager); + } + if (I3_struct == null) { + CppCompositeType G1_struct = + createG1_syntactic_struct32(vbtManager, C_struct, E_struct); + CppCompositeType H1_struct = + createH1_syntactic_struct32(vbtManager, E_struct, C_struct); + I3_struct = createI3_syntactic_struct32(vbtManager, G1_struct, H1_struct, E_struct, + C_struct); + } + if (GG1_struct == null) { + GG1_struct = createGG1_syntactic_struct32(vbtManager, CC1_struct); + } + if (I_struct == null) { + CppCompositeType G_struct = createG_syntactic_struct32(vbtManager, C_struct); + CppCompositeType H_struct = createH_syntactic_struct32(vbtManager, C_struct); + I_struct = createI_syntactic_struct32(vbtManager, G_struct, H_struct, C_struct); + } + if (GG2_struct == null) { + GG2_struct = createGG2_syntactic_struct32(vbtManager, CC2_struct); + } + if (GG3_struct == null) { + GG3_struct = createGG3_syntactic_struct32(vbtManager, CC2_struct); + } + J5_struct.addVirtualSyntacticBaseClass(GG2_struct); + J5_struct.addVirtualSyntacticBaseClass(GG3_struct); + J5_struct.addDirectSyntacticBaseClass(I3_struct); + J5_struct.addDirectSyntacticBaseClass(GG1_struct); + J5_struct.addDirectSyntacticBaseClass(I_struct); + J5_struct.addDirectSyntacticBaseClass(A_struct); + J5_struct.addMember("j51", u4, false, 0); // TODO nned syntactic without index + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J5_struct; + } + + //============================================================================================== + /* + * struct J4 : virtual GG2, virtual GG3, I3, GG1, I, A { + * int j51; + * void j5f(); + * }; + */ + static CppCompositeType createJ5_struct32(VbtManager vbtManager) { + return createJ5_struct32(vbtManager, null, null, null, null, null, null, null, null, null, + null); + } + + static CppCompositeType createJ5_struct32(VbtManager vbtManager, CppCompositeType I3_struct, + CppCompositeType GG1_struct, CppCompositeType I_struct, CppCompositeType A_struct, + CppCompositeType GG2_struct, CppCompositeType GG3_struct, CppCompositeType C_struct, + CppCompositeType E_struct, CppCompositeType CC1_struct, CppCompositeType CC2_struct) { + CppCompositeType J5_struct = createStruct32("J5", 92); + try { + if (A_struct == null) { + A_struct = createA_struct32(vbtManager); + A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct32(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct32(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (CC1_struct == null) { + CC1_struct = createCC1_struct32(vbtManager); + CC1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (CC2_struct == null) { + CC2_struct = createCC2_struct32(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I3_struct == null) { + CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); + CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); + I3_struct = createI3_struct32(vbtManager, G1_struct, H1_struct, E_struct, C_struct); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (GG1_struct == null) { + GG1_struct = createGG1_struct32(vbtManager, CC1_struct); + GG1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (I_struct == null) { + CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); + CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); + I_struct = createI_struct32(vbtManager, G_struct, H_struct, C_struct); + G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (GG2_struct == null) { + GG2_struct = createGG2_struct32(vbtManager, CC2_struct); + GG2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (GG3_struct == null) { + GG3_struct = createGG3_struct32(vbtManager, CC2_struct); + GG3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + J5_struct.addDirectBaseClass(I3_struct, 0); + J5_struct.addDirectBaseClass(GG1_struct, 20); + J5_struct.addDirectBaseClass(I_struct, 28); + J5_struct.addDirectBaseClass(A_struct, 48); + J5_struct.addDirectVirtualBaseClass(GG2_struct, 0, vbptr32, 4); + J5_struct.addDirectVirtualBaseClass(GG3_struct, 0, vbptr32, 5); + J5_struct.addIndirectVirtualBaseClass(CC2_struct, 0, vbptr32, 3); + J5_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + J5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + J5_struct.addIndirectVirtualBaseClass(CC1_struct, 0, vbptr32, 6); + J5_struct.addMember("j51", u4, false, 56); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J5_struct; + } + + //============================================================================================== + /* + * struct J4 : virtual GG2, virtual GG3, I3, GG1, I, A { + * int j51; + * void j5f(); + * }; + */ + static CppCompositeType createJ5_struct64(VbtManager vbtManager) { + return createJ5_struct64(vbtManager, null, null, null, null, null, null, null, null, null, + null); + } + + static CppCompositeType createJ5_struct64(VbtManager vbtManager, CppCompositeType I3_struct, + CppCompositeType GG1_struct, CppCompositeType I_struct, CppCompositeType A_struct, + CppCompositeType GG2_struct, CppCompositeType GG3_struct, CppCompositeType C_struct, + CppCompositeType E_struct, CppCompositeType CC1_struct, CppCompositeType CC2_struct) { + CppCompositeType J5_struct = createStruct64("J5", 164); + try { + if (A_struct == null) { + A_struct = createA_struct64(vbtManager); + A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (C_struct == null) { + C_struct = createC_struct64(vbtManager); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (E_struct == null) { + E_struct = createE_struct64(vbtManager); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (CC1_struct == null) { + CC1_struct = createCC1_struct64(vbtManager); + CC1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (CC2_struct == null) { + CC2_struct = createCC2_struct64(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I3_struct == null) { + CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); + CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); + I3_struct = createI3_struct32(vbtManager, G1_struct, H1_struct, E_struct, C_struct); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (GG1_struct == null) { + GG1_struct = createGG1_struct32(vbtManager, CC1_struct); + GG1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (I_struct == null) { + CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); + CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); + I_struct = createI_struct32(vbtManager, G_struct, H_struct, C_struct); + G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (GG2_struct == null) { + GG2_struct = createGG2_struct64(vbtManager, CC2_struct); + GG2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (GG3_struct == null) { + GG3_struct = createGG3_struct64(vbtManager, CC2_struct); + GG3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + J5_struct.addDirectBaseClass(I3_struct, 0); + J5_struct.addDirectBaseClass(GG1_struct, 40); + J5_struct.addDirectBaseClass(I_struct, 56); + J5_struct.addDirectBaseClass(A_struct, 96); + J5_struct.addDirectVirtualBaseClass(GG2_struct, 0, vbptr32, 4); + J5_struct.addDirectVirtualBaseClass(GG3_struct, 0, vbptr32, 5); + J5_struct.addIndirectVirtualBaseClass(CC2_struct, 0, vbptr32, 3); + J5_struct.addIndirectVirtualBaseClass(C_struct, 0, vbptr32, 1); + J5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); + J5_struct.addIndirectVirtualBaseClass(CC1_struct, 0, vbptr32, 6); + J5_struct.addMember("j51", u4, false, 104); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J5_struct; + } + + //============================================================================================== + /* + * struct J6 : virtual GG4, virtual GG3, A { //GG4 has no members + * int j61; + * void j6f(); + * }; + */ + static CppCompositeType createJ6_struct32(VbtManager vbtManager) { + return createJ6_struct32(vbtManager, null, null, null, null, null); + } + + static CppCompositeType createJ6_struct32(VbtManager vbtManager, CppCompositeType A_struct, + CppCompositeType GG4_struct, CppCompositeType GG3_struct, CppCompositeType CC2_struct, + CppCompositeType CC3_struct) { + CppCompositeType J6_struct = createStruct32("J6", 36); + try { + if (A_struct == null) { + A_struct = createA_struct32(vbtManager); + A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (CC2_struct == null) { + CC2_struct = createCC2_struct32(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (CC3_struct == null) { + CC3_struct = createCC3_struct32(vbtManager); + CC3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (GG4_struct == null) { + GG4_struct = createGG4_struct32(vbtManager, CC3_struct); + GG4_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + if (GG3_struct == null) { + GG3_struct = createGG3_struct32(vbtManager, CC2_struct); + GG3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + } + J6_struct.addDirectBaseClass(A_struct, 0); + J6_struct.addDirectVirtualBaseClass(GG4_struct, 8, vbptr32, 2); + J6_struct.addDirectVirtualBaseClass(GG3_struct, 8, vbptr32, 4); + J6_struct.addIndirectVirtualBaseClass(CC3_struct, 8, vbptr32, 1); + J6_struct.addIndirectVirtualBaseClass(CC2_struct, 8, vbptr32, 3); + J6_struct.addMember("j61", u4, false, 12); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J6_struct; + } + + //============================================================================================== + /* + * struct J6 : virtual GG4, virtual GG3, A { //GG4 has no members + * int j61; + * void j6f(); + * }; + */ + static CppCompositeType createJ6_struct64(VbtManager vbtManager) { + return createJ6_struct64(vbtManager, null, null, null, null, null); + } + + static CppCompositeType createJ6_struct64(VbtManager vbtManager, CppCompositeType A_struct, + CppCompositeType GG4_struct, CppCompositeType GG3_struct, CppCompositeType CC2_struct, + CppCompositeType CC3_struct) { + CppCompositeType J6_struct = createStruct64("J6", 64); + try { + if (A_struct == null) { + A_struct = createA_struct64(vbtManager); + A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (CC2_struct == null) { + CC2_struct = createCC2_struct64(vbtManager); + CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (CC3_struct == null) { + CC3_struct = createCC3_struct64(vbtManager); + CC3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (GG4_struct == null) { + GG4_struct = createGG4_struct64(vbtManager, CC3_struct); + GG4_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + if (GG3_struct == null) { + GG3_struct = createGG3_struct64(vbtManager, CC2_struct); + GG3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + } + J6_struct.addDirectBaseClass(A_struct, 0); + J6_struct.addDirectVirtualBaseClass(GG4_struct, 8, vbptr64, 2); + J6_struct.addDirectVirtualBaseClass(GG3_struct, 8, vbptr64, 4); + J6_struct.addIndirectVirtualBaseClass(CC3_struct, 8, vbptr64, 1); + J6_struct.addIndirectVirtualBaseClass(CC2_struct, 8, vbptr64, 3); + J6_struct.addMember("j61", u4, false, 16); + } + catch (Exception e) { + Msg.error(null, "Error in static initialization of test", e); + assert false; + } + return J6_struct; + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + //@formatter:off + /* + struct A { + char c; + int i; + }; + + class A size(8): + +--- + 0 | c + | (size=3) + 4 | i + +--- + */ + //@formatter:on + @Test + public void testA_32_vbt() throws Exception { + CppCompositeType A_struct = createA_struct32(pdbVbtManager32); + A_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = A_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedA_32(), composite, true); + } + + @Test + public void testA_32_speculative() throws Exception { + CppCompositeType A_struct = createA_struct32(vbtManager32); + A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = A_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedA_32(), composite, true); + } + + private String getExpectedA_32() { + String expected = + //@formatter:off + "/A\n" + + "Aligned\n" + + "Structure A {\n" + + " 0 A_direct 8 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedA_32() { + return convertCommentsToSpeculative(getExpectedA_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct A { + char c; + int i; + }; + + class A size(8): + +--- + 0 | c + | (size=3) + 4 | i + +--- + */ + //@formatter:on + @Test + public void testA_64_vbt() throws Exception { + CppCompositeType A_struct = createA_struct64(pdbVbtManager64); + A_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = A_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedA_64(), composite, true); + } + + @Test + public void testA_64_speculative() throws Exception { + CppCompositeType A_struct = createA_struct64(vbtManager64); + A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = A_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedA_64(), composite, true); + } + + private String getExpectedA_64() { + String expected = + //@formatter:off + "/A\n" + + "Aligned\n" + + "Structure A {\n" + + " 0 A_direct 8 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedA_64() { + return convertCommentsToSpeculative(getExpectedA_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct C { + int c1; + void cf(); + }; + + class C size(4): + +--- + 0 | c1 + +--- + */ + //@formatter:on + @Test + public void testC_32_vbt() throws Exception { + CppCompositeType C_struct = createC_struct32(pdbVbtManager32); + C_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = C_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedC_32(), composite, true); + } + + @Test + public void testC_32_speculative() throws Exception { + CppCompositeType C_struct = createC_struct32(vbtManager32); + C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = C_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedC_32(), composite, true); + } + + private String getExpectedC_32() { + String expected = + //@formatter:off + "/C\n" + + "Aligned\n" + + "Structure C {\n" + + " 0 C_direct 4 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedC_32() { + return convertCommentsToSpeculative(getExpectedC_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct C { + int c1; + void cf(); + }; + + class C size(4): + +--- + 0 | c1 + +--- + */ + //@formatter:on + @Test + public void testC_64_vbt() throws Exception { + CppCompositeType C_struct = createC_struct64(pdbVbtManager64); + C_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = C_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedC_64(), composite, true); + } + + @Test + public void testC_64_speculative() throws Exception { + CppCompositeType C_struct = createC_struct64(vbtManager64); + C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = C_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedC_64(), composite, true); + } + + private String getExpectedC_64() { + String expected = + //@formatter:off + "/C\n" + + "Aligned\n" + + "Structure C {\n" + + " 0 C_direct 4 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedC_64() { + return convertCommentsToSpeculative(getExpectedC_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct CC1 { + int cc11; + void cc1f(); + }; + + class CC1 size(4): + +--- + 0 | cc11 + +--- + */ + //@formatter:on + @Test + public void testCC1_32_vbt() throws Exception { + CppCompositeType CC1_struct = createCC1_struct32(pdbVbtManager32); + CC1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = CC1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedCC1_32(), composite, true); + } + + @Test + public void testCC1_32_speculative() throws Exception { + CppCompositeType CC1_struct = createCC1_struct32(vbtManager32); + CC1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = CC1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC1_32(), composite, true); + } + + private String getExpectedCC1_32() { + String expected = + //@formatter:off + "/CC1\n" + + "Aligned\n" + + "Structure CC1 {\n" + + " 0 CC1_direct 4 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC1/CC1_direct\n" + + "Aligned\n" + + "Structure CC1_direct {\n" + + " 0 undefined4 4 cc11 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedCC1_32() { + return convertCommentsToSpeculative(getExpectedCC1_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct CC1 { + int cc11; + void cc1f(); + }; + + class CC1 size(4): + +--- + 0 | cc11 + +--- + */ + //@formatter:on + @Test + public void testCC1_64_vbt() throws Exception { + CppCompositeType CC1_struct = createCC1_struct64(pdbVbtManager64); + CC1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = CC1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedCC1_64(), composite, true); + } + + @Test + public void testCC1_64_speculative() throws Exception { + CppCompositeType CC1_struct = createCC1_struct64(vbtManager64); + CC1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = CC1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC1_64(), composite, true); + } + + private String getExpectedCC1_64() { + String expected = + //@formatter:off + "/CC1\n" + + "Aligned\n" + + "Structure CC1 {\n" + + " 0 CC1_direct 4 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC1/CC1_direct\n" + + "Aligned\n" + + "Structure CC1_direct {\n" + + " 0 undefined4 4 cc11 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedCC1_64() { + return convertCommentsToSpeculative(getExpectedCC1_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct CC2 { + int cc21; + void cc2f(); + }; + + class CC2 size(4): + +--- + 0 | cc21 + +--- + */ + //@formatter:on + @Test + public void testCC2_32_vbt() throws Exception { + CppCompositeType CC2_struct = createCC2_struct32(pdbVbtManager32); + CC2_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = CC2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedCC2_32(), composite, true); + } + + @Test + public void testCC2_32_speculative() throws Exception { + CppCompositeType CC2_struct = createCC2_struct32(vbtManager32); + CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = CC2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC2_32(), composite, true); + } + + private String getExpectedCC2_32() { + String expected = + //@formatter:off + "/CC2\n" + + "Aligned\n" + + "Structure CC2 {\n" + + " 0 CC2_direct 4 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedCC2_32() { + return convertCommentsToSpeculative(getExpectedCC2_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct CC2 { + int cc21; + void cc2f(); + }; + + class CC2 size(4): + +--- + 0 | cc21 + +--- + */ + //@formatter:on + @Test + public void testCC2_64_vbt() throws Exception { + CppCompositeType CC2_struct = createCC2_struct64(pdbVbtManager64); + CC2_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = CC2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedCC2_64(), composite, true); + } + + @Test + public void testCC2_64_speculative() throws Exception { + CppCompositeType CC2_struct = createCC2_struct64(vbtManager64); + CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = CC2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC2_64(), composite, true); + } + + private String getExpectedCC2_64() { + String expected = + //@formatter:off + "/CC2\n" + + "Aligned\n" + + "Structure CC2 {\n" + + " 0 CC2_direct 4 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedCC2_64() { + return convertCommentsToSpeculative(getExpectedCC2_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct CC3 { + void cc3f(); + }; + + class CC3 size(1): + +--- + +--- + */ + //@formatter:on + @Test + public void testCC3_32_vbt() throws Exception { + CppCompositeType CC3_struct = createCC3_struct32(pdbVbtManager32); + CC3_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = CC3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedCC3_32(), composite, true); + } + + @Test + public void testCC3_32_speculative() throws Exception { + CppCompositeType CC3_struct = createCC3_struct32(vbtManager32); + CC3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = CC3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC3_32(), composite, true); + } + + private String getExpectedCC3_32() { + String expected = + //@formatter:off + "/CC3\n" + + "Unaligned\n" + + "Structure CC3 {\n" + + "}\n" + + "Size = 1 Actual Alignment = 1"; + //@formatter:on + return expected; + } + + private String getSpeculatedCC3_32() { + return convertCommentsToSpeculative(getExpectedCC3_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct CC3 { + void cc3f(); + }; + + class CC3 size(1): + +--- + +--- + */ + //@formatter:on + @Test + public void testCC3_64_vbt() throws Exception { + CppCompositeType CC3_struct = createCC3_struct64(pdbVbtManager64); + CC3_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = CC3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedCC3_64(), composite, true); + } + + @Test + public void testCC3_64_speculative() throws Exception { + CppCompositeType CC3_struct = createCC3_struct64(vbtManager64); + CC3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = CC3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC3_64(), composite, true); + } + + private String getExpectedCC3_64() { + String expected = + //@formatter:off + "/CC3\n" + + "Unaligned\n" + + "Structure CC3 {\n" + + "}\n" + + "Size = 1 Actual Alignment = 1"; + //@formatter:on + return expected; + } + + private String getSpeculatedCC3_64() { + return convertCommentsToSpeculative(getExpectedCC3_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct D : C { + int d1; + void df(); + }; + + class D size(8): + +--- + 0 | +--- (base class C) + 0 | | c1 + | +--- + 4 | d1 + +--- + */ + //@formatter:on + @Test + public void testD_32_vbt() throws Exception { + CppCompositeType D_struct = createD_struct32(pdbVbtManager32); + D_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = D_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedD_32(), composite, true); + } + + @Test + public void testD_32_speculative() throws Exception { + CppCompositeType D_struct = createD_struct32(vbtManager32); + D_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = D_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedD_32(), composite, true); + } + + private String getExpectedD_32() { + String expected = + //@formatter:off + "/D\n" + + "Aligned\n" + + "Structure D {\n" + + " 0 D_direct 8 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/D/D_direct\n" + + "Aligned\n" + + "Structure D_direct {\n" + + " 0 C_direct 4 \"\"\n" + + " 4 undefined4 4 d1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedD_32() { + return convertCommentsToSpeculative(getExpectedD_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct D : C { + int d1; + void df(); + }; + + class D size(8): + +--- + 0 | +--- (base class C) + 0 | | c1 + | +--- + 4 | d1 + +--- + */ + //@formatter:on + @Test + public void testD_64_vbt() throws Exception { + CppCompositeType D_struct = createD_struct64(pdbVbtManager64); + D_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = D_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedD_64(), composite, true); + } + + @Test + public void testD_64_speculative() throws Exception { + CppCompositeType D_struct = createD_struct64(vbtManager64); + D_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = D_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedD_64(), composite, true); + } + + private String getExpectedD_64() { + String expected = + //@formatter:off + "/D\n" + + "Aligned\n" + + "Structure D {\n" + + " 0 D_direct 8 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/D/D_direct\n" + + "Aligned\n" + + "Structure D_direct {\n" + + " 0 C_direct 4 \"\"\n" + + " 4 undefined4 4 d1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedD_64() { + return convertCommentsToSpeculative(getExpectedD_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct E { + int e1; + void ef(); + }; + + class E size(4): + +--- + 0 | e1 + +--- + */ + //@formatter:on + @Test + public void testE_32_vbt() throws Exception { + CppCompositeType E_struct = createE_struct32(pdbVbtManager32); + E_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = E_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedE_32(), composite, true); + } + + @Test + public void testE_32_speculative() throws Exception { + CppCompositeType E_struct = createE_struct32(vbtManager32); + E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = E_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedE_32(), composite, true); + } + + private String getExpectedE_32() { + String expected = + //@formatter:off + "/E\n" + + "Aligned\n" + + "Structure E {\n" + + " 0 E_direct 4 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedE_32() { + return convertCommentsToSpeculative(getExpectedE_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct E { + int e1; + void ef(); + }; + + class E size(4): + +--- + 0 | e1 + +--- + */ + //@formatter:on + @Test + public void testE_64_vbt() throws Exception { + CppCompositeType E_struct = createE_struct64(pdbVbtManager64); + E_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = E_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedE_64(), composite, true); + } + + @Test + public void testE_64_speculative() throws Exception { + CppCompositeType E_struct = createE_struct64(vbtManager64); + E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = E_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedE_64(), composite, true); + } + + private String getExpectedE_64() { + String expected = + //@formatter:off + "/E\n" + + "Aligned\n" + + "Structure E {\n" + + " 0 E_direct 4 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedE_64() { + return convertCommentsToSpeculative(getExpectedE_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct F : C, E { + int f1; + void ff(); + }; + + class F size(12): + +--- + 0 | +--- (base class C) + 0 | | c1 + | +--- + 4 | +--- (base class E) + 4 | | e1 + | +--- + 8 | f1 + +--- + */ + //@formatter:on + @Test + public void testF_32_vbt() throws Exception { + CppCompositeType F_struct = createF_struct32(pdbVbtManager32); + F_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = F_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedF_32(), composite, true); + } + + @Test + public void testF_32_speculative() throws Exception { + CppCompositeType F_struct = createF_struct32(vbtManager32); + F_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = F_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedF_32(), composite, true); + } + + private String getExpectedF_32() { + String expected = + //@formatter:off + "/F\n" + + "Aligned\n" + + "Structure F {\n" + + " 0 F_direct 12 \"\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/F/F_direct\n" + + "Aligned\n" + + "Structure F_direct {\n" + + " 0 C_direct 4 \"\"\n" + + " 4 E_direct 4 \"\"\n" + + " 8 undefined4 4 f1 \"\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedF_32() { + return convertCommentsToSpeculative(getExpectedF_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct F : C, E { + int f1; + void ff(); + }; + + class F size(12): + +--- + 0 | +--- (base class C) + 0 | | c1 + | +--- + 4 | +--- (base class E) + 4 | | e1 + | +--- + 8 | f1 + +--- + */ + //@formatter:on + @Test + public void testF_64_vbt() throws Exception { + CppCompositeType F_struct = createF_struct64(pdbVbtManager64); + F_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = F_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedF_64(), composite, true); + } + + @Test + public void testF_64_speculative() throws Exception { + CppCompositeType F_struct = createF_struct64(vbtManager64); + F_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = F_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedF_64(), composite, true); + } + + private String getExpectedF_64() { + String expected = + //@formatter:off + "/F\n" + + "Aligned\n" + + "Structure F {\n" + + " 0 F_direct 12 \"\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/F/F_direct\n" + + "Aligned\n" + + "Structure F_direct {\n" + + " 0 C_direct 4 \"\"\n" + + " 4 E_direct 4 \"\"\n" + + " 8 undefined4 4 f1 \"\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedF_64() { + return convertCommentsToSpeculative(getExpectedF_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct G : virtual C { + int g1; + void gf(); + }; + + class G size(12): + +--- + 0 | {vbptr} + 4 | g1 + +--- + +--- (virtual base C) + 8 | c1 + +--- + + G::$vbtable@: + 0 | 0 + 1 | 8 (Gd(G+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 8 0 4 0 + */ + //@formatter:on + @Test + public void testG_32_vbt() throws Exception { + CppCompositeType G_struct = createG_struct32(pdbVbtManager32); + G_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = G_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedG_32(), composite, true); + } + + @Test + public void testG_32_speculative() throws Exception { + CppCompositeType G_struct = createG_struct32(vbtManager32); + G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = G_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedG_32(), composite, true); + } + + private String getExpectedG_32() { + String expected = + //@formatter:off + "/G\n" + + "Aligned\n" + + "Structure G {\n" + + " 0 G_direct 8 \"\"\n" + + " 8 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedG_32() { + return convertCommentsToSpeculative(getExpectedG_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct G : virtual C { + int g1; + void gf(); + }; + + class G size(20): + +--- + 0 | {vbptr} + 8 | g1 + | (size=4) + +--- + +--- (virtual base C) + 16 | c1 + +--- + + G::$vbtable@: + 0 | 0 + 1 | 16 (Gd(G+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 16 0 4 0 + */ + //@formatter:on + @Test + public void testG_64_vbt() throws Exception { + CppCompositeType G_struct = createG_struct64(pdbVbtManager64); + G_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = G_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedG_64(), composite, true); + } + + @Test + public void testG_64_speculative() throws Exception { + CppCompositeType G_struct = createG_struct64(vbtManager64); + G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = G_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedG_64(), composite, true); + } + + private String getExpectedG_64() { + String expected = + //@formatter:off + "/G\n" + + "Aligned\n" + + "Structure G {\n" + + " 0 G_direct 16 \"\"\n" + + " 16 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedG_64() { + return convertCommentsToSpeculative(getExpectedG_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct H : virtual C { + int h1; + void hf(); + }; + + class H size(12): + +--- + 0 | {vbptr} + 4 | h1 + +--- + +--- (virtual base C) + 8 | c1 + +--- + + H::$vbtable@: + 0 | 0 + 1 | 8 (Hd(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 8 0 4 0 + */ + //@formatter:on + @Test + public void testH_32_vbt() throws Exception { + CppCompositeType H_struct = createH_struct32(pdbVbtManager32); + H_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = H_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedH_32(), composite, true); + } + + @Test + public void testH_32_speculative() throws Exception { + CppCompositeType H_struct = createH_struct32(vbtManager32); + H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = H_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedH_32(), composite, true); + } + + private String getExpectedH_32() { + String expected = + //@formatter:off + "/H\n" + + "Aligned\n" + + "Structure H {\n" + + " 0 H_direct 8 \"\"\n" + + " 8 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedH_32() { + return convertCommentsToSpeculative(getExpectedH_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct H : virtual C { + int h1; + void hf(); + }; + + class H size(20): + +--- + 0 | {vbptr} + 8 | h1 + | (size=4) + +--- + +--- (virtual base C) + 16 | c1 + +--- + + H::$vbtable@: + 0 | 0 + 1 | 16 (Hd(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 16 0 4 0 + */ + //@formatter:on + @Test + public void testH_64_vbt() throws Exception { + CppCompositeType H_struct = createH_struct64(pdbVbtManager64); + H_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = H_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedH_64(), composite, true); + } + + @Test + public void testH_64_speculative() throws Exception { + CppCompositeType H_struct = createH_struct64(vbtManager64); + H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = H_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedH_64(), composite, true); + } + + private String getExpectedH_64() { + String expected = + //@formatter:off + "/H\n" + + "Aligned\n" + + "Structure H {\n" + + " 0 H_direct 16 \"\"\n" + + " 16 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedH_64() { + return convertCommentsToSpeculative(getExpectedH_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct G1 : virtual C, virtual E { + int g11; + void g1f(); + }; + + class G1 size(16): + +--- + 0 | {vbptr} + 4 | g11 + +--- + +--- (virtual base C) + 8 | c1 + +--- + +--- (virtual base E) + 12 | e1 + +--- + + G1::$vbtable@: + 0 | 0 + 1 | 8 (G1d(G1+0)C) + 2 | 12 (G1d(G1+0)E) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 8 0 4 0 + E 12 0 8 0 + */ + //@formatter:on + @Test + public void testG1_32_vbt() throws Exception { + CppCompositeType G1_struct = createG1_struct32(pdbVbtManager32); + G1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = G1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedG1_32(), composite, true); + } + + @Test + public void testG1_32_speculative() throws Exception { + CppCompositeType G1_struct = createG1_struct32(vbtManager32); + G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = G1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedG1_32(), composite, true); + } + + private String getExpectedG1_32() { + String expected = + //@formatter:off + "/G1\n" + + "Aligned\n" + + "Structure G1 {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 C_direct 4 \"(Virtual Base C)\"\n" + + " 12 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedG1_32() { + return convertCommentsToSpeculative(getExpectedG1_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct G1 : virtual C, virtual E { + int g11; + void g1f(); + }; + + class G1 size(24): + +--- + 0 | {vbptr} + 8 | g11 + | (size=4) + +--- + +--- (virtual base C) + 16 | c1 + +--- + +--- (virtual base E) + 20 | e1 + +--- + + G1::$vbtable@: + 0 | 0 + 1 | 16 (G1d(G1+0)C) + 2 | 20 (G1d(G1+0)E) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 16 0 4 0 + E 20 0 8 0 + */ + //@formatter:on + @Test + public void testG1_64_vbt() throws Exception { + CppCompositeType G1_struct = createG1_struct64(pdbVbtManager64); + G1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = G1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedG1_64(), composite, true); + } + + @Test + public void testG1_64_speculative() throws Exception { + CppCompositeType G1_struct = createG1_struct64(vbtManager64); + G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = G1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedG1_64(), composite, true); + } + + private String getExpectedG1_64() { + String expected = + //@formatter:off + "/G1\n" + + "Aligned\n" + + "Structure G1 {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 C_direct 4 \"(Virtual Base C)\"\n" + + " 20 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedG1_64() { + return convertCommentsToSpeculative(getExpectedG1_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct H1 : virtual E, virtual C { //order reversed from G1 + int h11; + void h1f(); + }; + + class H1 size(16): + +--- + 0 | {vbptr} + 4 | h11 + +--- + +--- (virtual base E) + 8 | e1 + +--- + +--- (virtual base C) + 12 | c1 + +--- + + H1::$vbtable@: + 0 | 0 + 1 | 8 (H1d(H1+0)E) + 2 | 12 (H1d(H1+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + E 8 0 4 0 + C 12 0 8 0 + */ + //@formatter:on + @Test + public void testH1_32_vbt() throws Exception { + CppCompositeType H1_struct = createH1_struct32(pdbVbtManager32); + H1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = H1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedH1_32(), composite, true); + } + + @Test + public void testH1_32_speculative() throws Exception { + CppCompositeType H1_struct = createH1_struct32(vbtManager32); + H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = H1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedH1_32(), composite, true); + } + + private String getExpectedH1_32() { + String expected = + //@formatter:off + "/H1\n" + + "Aligned\n" + + "Structure H1 {\n" + + " 0 H1_direct 8 \"\"\n" + + " 8 E_direct 4 \"(Virtual Base E)\"\n" + + " 12 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedH1_32() { + return convertCommentsToSpeculative(getExpectedH1_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct H1 : virtual E, virtual C { //order reversed from G1 + int h11; + void h1f(); + }; + + class H1 size(24): + +--- + 0 | {vbptr} + 8 | h11 + | (size=4) + +--- + +--- (virtual base E) + 16 | e1 + +--- + +--- (virtual base C) + 20 | c1 + +--- + + H1::$vbtable@: + 0 | 0 + 1 | 16 (H1d(H1+0)E) + 2 | 20 (H1d(H1+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + E 16 0 4 0 + C 20 0 8 0 + */ + //@formatter:on + @Test + public void testH1_64_vbt() throws Exception { + CppCompositeType H1_struct = createH1_struct64(pdbVbtManager64); + H1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = H1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedH1_64(), composite, true); + } + + @Test + public void testH1_64_speculative() throws Exception { + CppCompositeType H1_struct = createH1_struct64(vbtManager64); + H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = H1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedH1_64(), composite, true); + } + + private String getExpectedH1_64() { + String expected = + //@formatter:off + "/H1\n" + + "Aligned\n" + + "Structure H1 {\n" + + " 0 H1_direct 16 \"\"\n" + + " 16 E_direct 4 \"(Virtual Base E)\"\n" + + " 20 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedH1_64() { + return convertCommentsToSpeculative(getExpectedH1_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct GG1 : virtual CC1 { + int gg11; + void gg1f(); + }; + + class GG1 size(12): + +--- + 0 | {vbptr} + 4 | gg11 + +--- + +--- (virtual base CC1) + 8 | cc11 + +--- + + GG1::$vbtable@: + 0 | 0 + 1 | 8 (GG1d(GG1+0)CC1) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC1 8 0 4 0 + */ + //@formatter:on + @Test + public void testGG1_32_vbt() throws Exception { + CppCompositeType GG1_struct = createGG1_struct32(pdbVbtManager32); + GG1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = GG1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedGG1_32(), composite, true); + } + + @Test + public void testGG1_32_speculative() throws Exception { + CppCompositeType GG1_struct = createGG1_struct32(vbtManager32); + GG1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = GG1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG1_32(), composite, true); + } + + private String getExpectedGG1_32() { + String expected = + //@formatter:off + "/GG1\n" + + "Aligned\n" + + "Structure GG1 {\n" + + " 0 GG1_direct 8 \"\"\n" + + " 8 CC1_direct 4 \"(Virtual Base CC1)\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4\n" + + "/CC1/CC1_direct\n" + + "Aligned\n" + + "Structure CC1_direct {\n" + + " 0 undefined4 4 cc11 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/GG1/GG1_direct\n" + + "Aligned\n" + + "Structure GG1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedGG1_32() { + return convertCommentsToSpeculative(getExpectedGG1_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct GG1 : virtual CC1 { + int gg11; + void gg1f(); + }; + + class GG1 size(20): + +--- + 0 | {vbptr} + 8 | gg11 + | (size=4) + +--- + +--- (virtual base CC1) + 16 | cc11 + +--- + + GG1::$vbtable@: + 0 | 0 + 1 | 16 (GG1d(GG1+0)CC1) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC1 16 0 4 0 + */ + //@formatter:on + @Test + public void testGG1_64_vbt() throws Exception { + CppCompositeType GG1_struct = createGG1_struct64(pdbVbtManager64); + GG1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = GG1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedGG1_64(), composite, true); + } + + @Test + public void testGG1_64_speculative() throws Exception { + CppCompositeType GG1_struct = createGG1_struct64(vbtManager64); + GG1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = GG1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG1_64(), composite, true); + } + + private String getExpectedGG1_64() { + String expected = + //@formatter:off + "/GG1\n" + + "Aligned\n" + + "Structure GG1 {\n" + + " 0 GG1_direct 16 \"\"\n" + + " 16 CC1_direct 4 \"(Virtual Base CC1)\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8\n" + + "/CC1/CC1_direct\n" + + "Aligned\n" + + "Structure CC1_direct {\n" + + " 0 undefined4 4 cc11 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/GG1/GG1_direct\n" + + "Aligned\n" + + "Structure GG1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedGG1_64() { + return convertCommentsToSpeculative(getExpectedGG1_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct GG2 : virtual CC2 { + int gg21; + void gg2f(); + }; + + class GG2 size(12): + +--- + 0 | {vbptr} + 4 | gg21 + +--- + +--- (virtual base CC2) + 8 | cc21 + +--- + + GG2::$vbtable@: + 0 | 0 + 1 | 8 (GG2d(GG2+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC2 8 0 4 0 + */ + //@formatter:on + @Test + public void testGG2_32_vbt() throws Exception { + CppCompositeType GG2_struct = createGG2_struct32(pdbVbtManager32); + GG2_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = GG2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedGG2_32(), composite, true); + } + + @Test + public void testGG2_32_speculative() throws Exception { + CppCompositeType GG2_struct = createGG2_struct32(vbtManager32); + GG2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = GG2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG2_32(), composite, true); + } + + private String getExpectedGG2_32() { + String expected = + //@formatter:off + "/GG2\n" + + "Aligned\n" + + "Structure GG2 {\n" + + " 0 GG2_direct 8 \"\"\n" + + " 8 CC2_direct 4 \"(Virtual Base CC2)\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/GG2/GG2_direct\n" + + "Aligned\n" + + "Structure GG2_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg21 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedGG2_32() { + return convertCommentsToSpeculative(getExpectedGG2_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct GG2 : virtual CC2 { + int gg21; + void gg2f(); + }; + + class GG2 size(20): + +--- + 0 | {vbptr} + 8 | gg21 + | (size=4) + +--- + +--- (virtual base CC2) + 16 | cc21 + +--- + + GG2::$vbtable@: + 0 | 0 + 1 | 16 (GG2d(GG2+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC2 16 0 4 0 + */ + //@formatter:on + @Test + public void testGG2_64_vbt() throws Exception { + CppCompositeType GG2_struct = createGG2_struct64(pdbVbtManager64); + GG2_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = GG2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedGG2_64(), composite, true); + } + + @Test + public void testGG2_64_speculative() throws Exception { + CppCompositeType GG2_struct = createGG2_struct64(vbtManager64); + GG2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = GG2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG2_64(), composite, true); + } + + private String getExpectedGG2_64() { + String expected = + //@formatter:off + "/GG2\n" + + "Aligned\n" + + "Structure GG2 {\n" + + " 0 GG2_direct 16 \"\"\n" + + " 16 CC2_direct 4 \"(Virtual Base CC2)\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/GG2/GG2_direct\n" + + "Aligned\n" + + "Structure GG2_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg21 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedGG2_64() { + return convertCommentsToSpeculative(getExpectedGG2_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct GG3 : virtual CC2 { + int gg31; + void gg3f(); + }; + + class GG3 size(12): + +--- + 0 | {vbptr} + 4 | gg31 + +--- + +--- (virtual base CC2) + 8 | cc21 + +--- + + GG3::$vbtable@: + 0 | 0 + 1 | 8 (GG3d(GG3+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC2 8 0 4 0 + */ + //@formatter:on + @Test + public void testGG3_32_vbt() throws Exception { + CppCompositeType GG3_struct = createGG3_struct32(pdbVbtManager32); + GG3_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = GG3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedGG3_32(), composite, true); + } + + @Test + public void testGG3_32_speculative() throws Exception { + CppCompositeType GG3_struct = createGG3_struct32(vbtManager32); + GG3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = GG3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG3_32(), composite, true); + } + + private String getExpectedGG3_32() { + String expected = + //@formatter:off + "/GG3\n" + + "Aligned\n" + + "Structure GG3 {\n" + + " 0 GG3_direct 8 \"\"\n" + + " 8 CC2_direct 4 \"(Virtual Base CC2)\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/GG3/GG3_direct\n" + + "Aligned\n" + + "Structure GG3_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg31 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedGG3_32() { + return convertCommentsToSpeculative(getExpectedGG3_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct GG3 : virtual CC2 { + int gg31; + void gg3f(); + }; + + class GG3 size(20): + +--- + 0 | {vbptr} + 8 | gg31 + | (size=4) + +--- + +--- (virtual base CC2) + 16 | cc21 + +--- + + GG3::$vbtable@: + 0 | 0 + 1 | 16 (GG3d(GG3+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC2 16 0 4 0 + */ + //@formatter:on + @Test + public void testGG3_64_vbt() throws Exception { + CppCompositeType GG3_struct = createGG3_struct64(pdbVbtManager64); + GG3_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = GG3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedGG3_64(), composite, true); + } + + @Test + public void testGG3_64_speculative() throws Exception { + CppCompositeType GG3_struct = createGG3_struct64(vbtManager64); + GG3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = GG3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG3_64(), composite, true); + } + + private String getExpectedGG3_64() { + String expected = + //@formatter:off + "/GG3\n" + + "Aligned\n" + + "Structure GG3 {\n" + + " 0 GG3_direct 16 \"\"\n" + + " 16 CC2_direct 4 \"(Virtual Base CC2)\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/GG3/GG3_direct\n" + + "Aligned\n" + + "Structure GG3_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg31 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedGG3_64() { + return convertCommentsToSpeculative(getExpectedGG3_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct GG4 : virtual CC3 { + int gg41; + void gg4f(); + }; + + class GG4 size(8): + +--- + 0 | {vbptr} + 4 | gg41 + +--- + +--- (virtual base CC3) + +--- + + GG4::$vbtable@: + 0 | 0 + 1 | 8 (GG4d(GG4+0)CC3) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC3 8 0 4 0 + */ + //@formatter:on + // TODO: consider if we want to change the format on the output to provide information + // about zero-sized virtual structure components trailing at the end. We currently let + // this information drop on the floor. So in this case, our output does not show + // the fact that CC3 is a zero-sized virtual parent. + @Test + public void testGG4_32_vbt() throws Exception { + CppCompositeType GG4_struct = createGG4_struct32(pdbVbtManager32); + GG4_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = GG4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedGG4_32(), composite, true); + } + + @Test + public void testGG4_32_speculative() throws Exception { + CppCompositeType GG4_struct = createGG4_struct32(vbtManager32); + GG4_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = GG4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG4_32(), composite, true); + } + + private String getExpectedGG4_32() { + String expected = + //@formatter:off + "/GG4\n" + + "Aligned\n" + + "Structure GG4 {\n" + + " 0 GG4_direct 8 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/GG4/GG4_direct\n" + + "Aligned\n" + + "Structure GG4_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg41 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedGG4_32() { + return convertCommentsToSpeculative(getExpectedGG4_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct GG4 : virtual CC3 { + int gg41; + void gg4f(); + }; + + class GG4 size(16): + +--- + 0 | {vbptr} + 8 | gg41 + | (size=4) + +--- + +--- (virtual base CC3) + +--- + + GG4::$vbtable@: + 0 | 0 + 1 | 16 (GG4d(GG4+0)CC3) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC3 16 0 4 0 + */ + //@formatter:on + // TODO: consider if we want to change the format on the output to provide information + // about zero-sized virtual structure components trailing at the end. We currently let + // this information drop on the floor. So in this case, our output does not show + // the fact that CC3 is a zero-sized virtual parent. + @Test + public void testGG4_64_vbt() throws Exception { + CppCompositeType GG4_struct = createGG4_struct64(pdbVbtManager64); + GG4_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = GG4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedGG4_64(), composite, true); + } + + @Test + public void testGG4_64_speculative() throws Exception { + CppCompositeType GG4_struct = createGG4_struct64(vbtManager64); + GG4_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = GG4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG4_64(), composite, true); + } + + private String getExpectedGG4_64() { + String expected = + //@formatter:off + "/GG4\n" + + "Aligned\n" + + "Structure GG4 {\n" + + " 0 GG4_direct 16 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/GG4/GG4_direct\n" + + "Aligned\n" + + "Structure GG4_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg41 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8"; + + //@formatter:on + return expected; + } + + private String getSpeculatedGG4_64() { + return convertCommentsToSpeculative(getExpectedGG4_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct I : G, H { + int i1; + void _if(); + }; + + class I size(24): + +--- + 0 | +--- (base class G) + 0 | | {vbptr} + 4 | | g1 + | +--- + 8 | +--- (base class H) + 8 | | {vbptr} + 12 | | h1 + | +--- + 16 | i1 + +--- + +--- (virtual base C) + 20 | c1 + +--- + + I::$vbtable@G@: + 0 | 0 + 1 | 20 (Id(G+0)C) + + I::$vbtable@H@: + 0 | 0 + 1 | 12 (Id(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 20 0 4 0 + */ + //@formatter:on + @Test + public void testI_32_vbt() throws Exception { + CppCompositeType I_struct = createI_struct32(pdbVbtManager32); + I_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = I_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI_32(), composite, true); + } + + @Test + public void testI_32_speculative() throws Exception { + CppCompositeType I_struct = createI_struct32(vbtManager32); + I_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = I_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI_32(), composite, true); + } + + private String getExpectedI_32() { + String expected = + //@formatter:off + "/I\n" + + "Aligned\n" + + "Structure I {\n" + + " 0 I_direct 20 \"\"\n" + + " 20 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I/I_direct\n" + + "Aligned\n" + + "Structure I_direct {\n" + + " 0 G_direct 8 \"\"\n" + + " 8 H_direct 8 \"\"\n" + + " 16 undefined4 4 i1 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedI_32() { + return convertCommentsToSpeculative(getExpectedI_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct I : G, H { + int i1; + void _if(); + }; + + class I size(44): + +--- + 0 | +--- (base class G) + 0 | | {vbptr} + 8 | | g1 + | | (size=4) + | | (size=4) + | +--- + 16 | +--- (base class H) + 16 | | {vbptr} + 24 | | h1 + | | (size=4) + | | (size=4) + | +--- + 32 | i1 + | (size=4) + +--- + +--- (virtual base C) + 40 | c1 + +--- + + I::$vbtable@G@: + 0 | 0 + 1 | 40 (Id(G+0)C) + + I::$vbtable@H@: + 0 | 0 + 1 | 24 (Id(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 40 0 4 0 + */ + //@formatter:on + @Test + public void testI_64_vbt() throws Exception { + CppCompositeType I_struct = createI_struct64(pdbVbtManager64); + I_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = I_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI_64(), composite, true); + } + + @Test + public void testI_64_speculative() throws Exception { + CppCompositeType I_struct = createI_struct64(vbtManager64); + I_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = I_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI_64(), composite, true); + } + + private String getExpectedI_64() { + String expected = + //@formatter:off + "/I\n" + + "Aligned\n" + + "Structure I {\n" + + " 0 I_direct 40 \"\"\n" + + " 40 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 48 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I/I_direct\n" + + "Aligned\n" + + "Structure I_direct {\n" + + " 0 G_direct 16 \"\"\n" + + " 16 H_direct 16 \"\"\n" + + " 32 undefined4 4 i1 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedI_64() { + return convertCommentsToSpeculative(getExpectedI_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct I1 : G1, H { + int i11; + void _i1f(); + }; + + class I1 size(28): + +--- + 0 | +--- (base class G1) + 0 | | {vbptr} + 4 | | g11 + | +--- + 8 | +--- (base class H) + 8 | | {vbptr} + 12 | | h1 + | +--- + 16 | i11 + +--- + +--- (virtual base C) + 20 | c1 + +--- + +--- (virtual base E) + 24 | e1 + +--- + + I1::$vbtable@G1@: + 0 | 0 + 1 | 20 (I1d(G1+0)C) + 2 | 24 (I1d(G1+0)E) + + I1::$vbtable@H@: + 0 | 0 + 1 | 12 (I1d(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 20 0 4 0 + E 24 0 8 0 + */ + //@formatter:on + @Test + public void testI1_32_vbt() throws Exception { + CppCompositeType I1_struct = createI1_struct32(pdbVbtManager32); + I1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = I1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI1_32(), composite, true); + } + + @Test + public void testI1_32_speculative() throws Exception { + CppCompositeType I1_struct = createI1_struct32(vbtManager32); + I1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = I1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI1_32(), composite, true); + } + + private String getExpectedI1_32() { + String expected = + //@formatter:off + "/I1\n" + + "Aligned\n" + + "Structure I1 {\n" + + " 0 I1_direct 20 \"\"\n" + + " 20 C_direct 4 \"(Virtual Base C)\"\n" + + " 24 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 28 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I1/I1_direct\n" + + "Aligned\n" + + "Structure I1_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 H_direct 8 \"\"\n" + + " 16 undefined4 4 i11 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedI1_32() { + return convertCommentsToSpeculative(getExpectedI1_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct I1 : G1, H { + int i11; + void _i1f(); + }; + + class I1 size(48): + +--- + 0 | +--- (base class G1) + 0 | | {vbptr} + 8 | | g11 + | | (size=4) + | +--- + 16 | +--- (base class H) + 16 | | {vbptr} + 24 | | h1 + | | (size=4) + | | (size=4) + | +--- + 32 | i11 + | (size=4) + +--- + +--- (virtual base C) + 40 | c1 + +--- + +--- (virtual base E) + 44 | e1 + +--- + + I1::$vbtable@G1@: + 0 | 0 + 1 | 40 (I1d(G1+0)C) + 2 | 44 (I1d(G1+0)E) + + I1::$vbtable@H@: + 0 | 0 + 1 | 24 (I1d(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 40 0 4 0 + E 44 0 8 0 + */ + //@formatter:on + @Test + public void testI1_64_vbt() throws Exception { + CppCompositeType I1_struct = createI1_struct64(pdbVbtManager64); + I1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = I1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI1_64(), composite, true); + } + + @Test + public void testI1_64_speculative() throws Exception { + CppCompositeType I1_struct = createI1_struct64(vbtManager64); + I1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = I1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI1_64(), composite, true); + } + + private String getExpectedI1_64() { + String expected = + //@formatter:off + "/I1\n" + + "Aligned\n" + + "Structure I1 {\n" + + " 0 I1_direct 40 \"\"\n" + + " 40 C_direct 4 \"(Virtual Base C)\"\n" + + " 44 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 48 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I1/I1_direct\n" + + "Aligned\n" + + "Structure I1_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 H_direct 16 \"\"\n" + + " 32 undefined4 4 i11 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedI1_64() { + return convertCommentsToSpeculative(getExpectedI1_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct I2 : G, H1 { + int i21; + void _i2f(); + }; + + class I2 size(28): + +--- + 0 | +--- (base class G) + 0 | | {vbptr} + 4 | | g1 + | +--- + 8 | +--- (base class H1) + 8 | | {vbptr} + 12 | | h11 + | +--- + 16 | i21 + +--- + +--- (virtual base C) + 20 | c1 + +--- + +--- (virtual base E) + 24 | e1 + +--- + + I2::$vbtable@G@: + 0 | 0 + 1 | 20 (I2d(G+0)C) + 2 | 24 (I2d(I2+0)E) + + I2::$vbtable@H1@: + 0 | 0 + 1 | 16 (I2d(H1+0)E) + 2 | 12 (I2d(H1+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 20 0 4 0 + E 24 0 8 0 + */ + //@formatter:on + @Test + public void testI2_32_vbt() throws Exception { + CppCompositeType I2_struct = createI2_struct32(pdbVbtManager32); + I2_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = I2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI2_32(), composite, true); + } + + @Test + public void testI2_32_speculative() throws Exception { + CppCompositeType I2_struct = createI2_struct32(vbtManager32); + I2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = I2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI2_32(), composite, true); + } + + private String getExpectedI2_32() { + String expected = + //@formatter:off + "/I2\n" + + "Aligned\n" + + "Structure I2 {\n" + + " 0 I2_direct 20 \"\"\n" + + " 20 C_direct 4 \"(Virtual Base C)\"\n" + + " 24 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 28 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I2/I2_direct\n" + + "Aligned\n" + + "Structure I2_direct {\n" + + " 0 G_direct 8 \"\"\n" + + " 8 H1_direct 8 \"\"\n" + + " 16 undefined4 4 i21 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedI2_32() { + return convertCommentsToSpeculative(getExpectedI2_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct I2 : G, H1 { + int i21; + void _i2f(); + }; + + class I2 size(48): + +--- + 0 | +--- (base class G) + 0 | | {vbptr} + 8 | | g1 + | | (size=4) + | | (size=4) + | +--- + 16 | +--- (base class H1) + 16 | | {vbptr} + 24 | | h11 + | | (size=4) + | +--- + 32 | i21 + | (size=4) + +--- + +--- (virtual base C) + 40 | c1 + +--- + +--- (virtual base E) + 44 | e1 + +--- + + I2::$vbtable@G@: + 0 | 0 + 1 | 40 (I2d(G+0)C) + 2 | 44 (I2d(I2+0)E) + + I2::$vbtable@H1@: + 0 | 0 + 1 | 28 (I2d(H1+0)E) + 2 | 24 (I2d(H1+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 40 0 4 0 + E 44 0 8 0 + */ + //@formatter:on + @Test + public void testI2_64_vbt() throws Exception { + CppCompositeType I2_struct = createI2_struct64(pdbVbtManager64); + I2_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = I2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI2_64(), composite, true); + } + + @Test + public void testI2_64_speculative() throws Exception { + CppCompositeType I2_struct = createI2_struct64(vbtManager64); + I2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = I2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI2_64(), composite, true); + } + + private String getExpectedI2_64() { + String expected = + //@formatter:off + "/I2\n" + + "Aligned\n" + + "Structure I2 {\n" + + " 0 I2_direct 40 \"\"\n" + + " 40 C_direct 4 \"(Virtual Base C)\"\n" + + " 44 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 48 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I2/I2_direct\n" + + "Aligned\n" + + "Structure I2_direct {\n" + + " 0 G_direct 16 \"\"\n" + + " 16 H1_direct 16 \"\"\n" + + " 32 undefined4 4 i21 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedI2_64() { + return convertCommentsToSpeculative(getExpectedI2_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct I3 : G1, H1 { + int i31; + void _i3f(); + }; + + class I3 size(28): + +--- + 0 | +--- (base class G1) + 0 | | {vbptr} + 4 | | g11 + | +--- + 8 | +--- (base class H1) + 8 | | {vbptr} + 12 | | h11 + | +--- + 16 | i31 + +--- + +--- (virtual base C) + 20 | c1 + +--- + +--- (virtual base E) + 24 | e1 + +--- + + I3::$vbtable@G1@: + 0 | 0 + 1 | 20 (I3d(G1+0)C) + 2 | 24 (I3d(G1+0)E) + + I3::$vbtable@H1@: + 0 | 0 + 1 | 16 (I3d(H1+0)E) + 2 | 12 (I3d(H1+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 20 0 4 0 + E 24 0 8 0 + */ + //@formatter:on + @Test + public void testI3_32_vbt() throws Exception { + CppCompositeType I3_struct = createI3_struct32(pdbVbtManager32); + I3_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = I3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI3_32(), composite, true); + } + + @Test + public void testI3_32_speculative() throws Exception { + CppCompositeType I3_struct = createI3_struct32(vbtManager32); + I3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = I3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI3_32(), composite, true); + } + + private String getExpectedI3_32() { + String expected = + //@formatter:off + "/I3\n" + + "Aligned\n" + + "Structure I3 {\n" + + " 0 I3_direct 20 \"\"\n" + + " 20 C_direct 4 \"(Virtual Base C)\"\n" + + " 24 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 28 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I3/I3_direct\n" + + "Aligned\n" + + "Structure I3_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 H1_direct 8 \"\"\n" + + " 16 undefined4 4 i31 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedI3_32() { + return convertCommentsToSpeculative(getExpectedI3_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct I3 : G1, H1 { + int i31; + void _i3f(); + }; + + class I3 size(48): + +--- + 0 | +--- (base class G1) + 0 | | {vbptr} + 8 | | g11 + | | (size=4) + | +--- + 16 | +--- (base class H1) + 16 | | {vbptr} + 24 | | h11 + | | (size=4) + | +--- + 32 | i31 + | (size=4) + +--- + +--- (virtual base C) + 40 | c1 + +--- + +--- (virtual base E) + 44 | e1 + +--- + + I3::$vbtable@G1@: + 0 | 0 + 1 | 40 (I3d(G1+0)C) + 2 | 44 (I3d(G1+0)E) + + I3::$vbtable@H1@: + 0 | 0 + 1 | 28 (I3d(H1+0)E) + 2 | 24 (I3d(H1+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 40 0 4 0 + E 44 0 8 0 + */ + //@formatter:on + @Test + public void testI3_64_vbt() throws Exception { + CppCompositeType I3_struct = createI3_struct64(pdbVbtManager64); + I3_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = I3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI3_64(), composite, true); + } + + @Test + public void testI3_64_speculative() throws Exception { + CppCompositeType I3_struct = createI3_struct64(vbtManager64); + I3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = I3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI3_64(), composite, true); + } + + private String getExpectedI3_64() { + String expected = + //@formatter:off + "/I3\n" + + "Aligned\n" + + "Structure I3 {\n" + + " 0 I3_direct 40 \"\"\n" + + " 40 C_direct 4 \"(Virtual Base C)\"\n" + + " 44 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 48 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I3/I3_direct\n" + + "Aligned\n" + + "Structure I3_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 H1_direct 16 \"\"\n" + + " 32 undefined4 4 i31 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedI3_64() { + return convertCommentsToSpeculative(getExpectedI3_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct I4 : G1, virtual E, virtual C { + int i41; + void _i4f(); + }; + + class I4 size(20): + +--- + 0 | +--- (base class G1) + 0 | | {vbptr} + 4 | | g11 + | +--- + 8 | i41 + +--- + +--- (virtual base C) + 12 | c1 + +--- + +--- (virtual base E) + 16 | e1 + +--- + + I4::$vbtable@: + 0 | 0 + 1 | 12 (I4d(G1+0)C) + 2 | 16 (I4d(G1+0)E) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 12 0 4 0 + E 16 0 8 0 + */ + //@formatter:on + @Test + public void testI4_32_vbt() throws Exception { + CppCompositeType I4_struct = createI4_struct32(pdbVbtManager32); + I4_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = I4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI4_32(), composite, true); + } + + @Test + public void testI4_32_speculative() throws Exception { + CppCompositeType I4_struct = createI4_struct32(vbtManager32); + I4_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = I4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI4_32(), composite, true); + } + + private String getExpectedI4_32() { + String expected = + //@formatter:off + "/I4\n" + + "Aligned\n" + + "Structure I4 {\n" + + " 0 I4_direct 12 \"\"\n" + + " 12 C_direct 4 \"(Virtual Base C)\"\n" + + " 16 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I4/I4_direct\n" + + "Aligned\n" + + "Structure I4_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 undefined4 4 i41 \"\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4"; + + //@formatter:on + return expected; + } + + private String getSpeculatedI4_32() { + return convertCommentsToSpeculative(getExpectedI4_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct I4 : G1, virtual E, virtual C { + int i41; + void _i4f(); + }; + + class I4 size(32): + +--- + 0 | +--- (base class G1) + 0 | | {vbptr} + 8 | | g11 + | | (size=4) + | +--- + 16 | i41 + | (size=4) + +--- + +--- (virtual base C) + 24 | c1 + +--- + +--- (virtual base E) + 28 | e1 + +--- + + I4::$vbtable@: + 0 | 0 + 1 | 24 (I4d(G1+0)C) + 2 | 28 (I4d(G1+0)E) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 24 0 4 0 + E 28 0 8 0 */ + //@formatter:on + @Test + public void testI4_64_vbt() throws Exception { + CppCompositeType I4_struct = createI4_struct64(pdbVbtManager64); + I4_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = I4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI4_64(), composite, true); + } + + @Test + public void testI4_64_speculative() throws Exception { + CppCompositeType I4_struct = createI4_struct64(vbtManager64); + I4_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = I4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI4_64(), composite, true); + } + + private String getExpectedI4_64() { + String expected = + //@formatter:off + "/I4\n" + + "Aligned\n" + + "Structure I4 {\n" + + " 0 I4_direct 24 \"\"\n" + + " 24 C_direct 4 \"(Virtual Base C)\"\n" + + " 28 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 32 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I4/I4_direct\n" + + "Aligned\n" + + "Structure I4_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 undefined4 4 i41 \"\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedI4_64() { + return convertCommentsToSpeculative(getExpectedI4_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct I5 : virtual E, virtual C, G1 { + int i51; + void _i5f(); + }; + + class I5 size(20): + +--- + 0 | +--- (base class G1) + 0 | | {vbptr} + 4 | | g11 + | +--- + 8 | i51 + +--- + +--- (virtual base E) + 12 | e1 + +--- + +--- (virtual base C) + 16 | c1 + +--- + + I5::$vbtable@: + 0 | 0 + 1 | 16 (I5d(G1+0)C) + 2 | 12 (I5d(G1+0)E) + vbi: class offset o.vbptr o.vbte fVtorDisp + E 12 0 8 0 + C 16 0 4 0 + */ + //@formatter:on + @Test + public void testI5_32_vbt() throws Exception { + CppCompositeType I5_struct = createI5_struct32(pdbVbtManager32); + I5_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = I5_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedtI5_32(), composite, true); + } + + @Test + public void testI5_32_speculative() throws Exception { + CppCompositeType I5_struct = createI5_struct32(vbtManager32); + I5_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = I5_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedtI5_32(), composite, true); + } + + private String getExpectedtI5_32() { + String expected = + //@formatter:off + "/I5\n" + + "Aligned\n" + + "Structure I5 {\n" + + " 0 I5_direct 12 \"\"\n" + + " 12 E_direct 4 \"(Virtual Base E)\"\n" + + " 16 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I5/I5_direct\n" + + "Aligned\n" + + "Structure I5_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 undefined4 4 i51 \"\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + // NOTE: We know that this is an incorrect layout (it matches that of I4), but we are + // measuring our result against the best we can determine (C and E virtual bases are + // switched from the actual as the Base Class records in the PDB are given in the exact + // same order as for I4. Using the VBT-based algorithm can produce the correct layout, but + // the speculative algorithm works without it. + private String getSpeculatedtI5_32() { + String expected = + //@formatter:off + "/I5\n" + + "Aligned\n" + + "Structure I5 {\n" + + " 0 I5_direct 12 \"\"\n" + + " 12 C_direct 4 \"((Speculative Placement) Virtual Base C)\"\n" + + " 16 E_direct 4 \"((Speculative Placement) Virtual Base E)\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I5/I5_direct\n" + + "Aligned\n" + + "Structure I5_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 undefined4 4 i51 \"\"\n" + + "}\n" + + "Size = 12 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + //============================================================================================== + //@formatter:off + /* + struct I5 : virtual E, virtual C, G1 { + int i51; + void _i5f(); + }; + + class I5 size(32): + +--- + 0 | +--- (base class G1) + 0 | | {vbptr} + 8 | | g11 + | | (size=4) + | +--- + 16 | i51 + | (size=4) + +--- + +--- (virtual base E) + 24 | e1 + +--- + +--- (virtual base C) + 28 | c1 + +--- + + I5::$vbtable@: + 0 | 0 + 1 | 28 (I5d(G1+0)C) + 2 | 24 (I5d(G1+0)E) + vbi: class offset o.vbptr o.vbte fVtorDisp + E 24 0 8 0 + C 28 0 4 0 + */ + //@formatter:on + @Test + public void testI5_64_vbt() throws Exception { + CppCompositeType I5_struct = createI5_struct64(pdbVbtManager64); + I5_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = I5_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedI5_64(), composite, true); + } + + @Test + public void testI5_64_speculative() throws Exception { + CppCompositeType I5_struct = createI5_struct64(vbtManager64); + I5_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = I5_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI5_64(), composite, true); + } + + private String getExpectedI5_64() { + String expected = + //@formatter:off + "/I5\n" + + "Aligned\n" + + "Structure I5 {\n" + + " 0 I5_direct 24 \"\"\n" + + " 24 E_direct 4 \"(Virtual Base E)\"\n" + + " 28 C_direct 4 \"(Virtual Base C)\"\n" + + "}\n" + + "Size = 32 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I5/I5_direct\n" + + "Aligned\n" + + "Structure I5_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 undefined4 4 i51 \"\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + // NOTE: We know that this is an incorrect layout (it matches that of I4), but we are + // measuring our result against the best we can determine (C and E virtual bases are + // switched from the actual as the Base Class records in the PDB are given in the exact + // same order as for I4. Using the VBT-based algorithm can produce the correct layout, but + // the speculative algorithm works without it. + private String getSpeculatedI5_64() { + String expected = + //@formatter:off + "/I5\n" + + "Aligned\n" + + "Structure I5 {\n" + + " 0 I5_direct 24 \"\"\n" + + " 24 C_direct 4 \"((Speculative Placement) Virtual Base C)\"\n" + + " 28 E_direct 4 \"((Speculative Placement) Virtual Base E)\"\n" + + "}\n" + + "Size = 32 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I5/I5_direct\n" + + "Aligned\n" + + "Structure I5_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 undefined4 4 i51 \"\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + //============================================================================================== + //@formatter:off + /* + struct J1 : I1, I2 { + int j11; + void j1f(); + }; + + class J1 size(52): + +--- + 0 | +--- (base class I1) + 0 | | +--- (base class G1) + 0 | | | {vbptr} + 4 | | | g11 + | | +--- + 8 | | +--- (base class H) + 8 | | | {vbptr} + 12 | | | h1 + | | +--- + 16 | | i11 + | +--- + 20 | +--- (base class I2) + 20 | | +--- (base class G) + 20 | | | {vbptr} + 24 | | | g1 + | | +--- + 28 | | +--- (base class H1) + 28 | | | {vbptr} + 32 | | | h11 + | | +--- + 36 | | i21 + | +--- + 40 | j11 + +--- + +--- (virtual base C) + 44 | c1 + +--- + +--- (virtual base E) + 48 | e1 + +--- + + J1::$vbtable@G1@: + 0 | 0 + 1 | 44 (J1d(G1+0)C) + 2 | 48 (J1d(G1+0)E) + + J1::$vbtable@H@: + 0 | 0 + 1 | 36 (J1d(H+0)C) + + J1::$vbtable@G@: + 0 | 0 + 1 | 24 (J1d(G+0)C) + 2 | 28 (J1d(I2+0)E) + + J1::$vbtable@H1@: + 0 | 0 + 1 | 20 (J1d(H1+0)E) + 2 | 16 (J1d(H1+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 44 0 4 0 + E 48 0 8 0 + */ + //@formatter:on + @Test + public void testJ1_32_vbt() throws Exception { + CppCompositeType J1_struct = createJ1_struct32(pdbVbtManager32); + J1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = J1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ1_32(), composite, true); + } + + @Test + public void testJ1_32_speculative() throws Exception { + CppCompositeType J1_struct = createJ1_struct32(vbtManager32); + J1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = J1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ1_32(), composite, true); + } + + private String getExpectedJ1_32() { + String expected = + //@formatter:off + "/J1\n" + + "Aligned\n" + + "Structure J1 {\n" + + " 0 J1_direct 44 \"\"\n" + + " 44 C_direct 4 \"(Virtual Base C)\"\n" + + " 48 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 52 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I1/I1_direct\n" + + "Aligned\n" + + "Structure I1_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 H_direct 8 \"\"\n" + + " 16 undefined4 4 i11 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/I2/I2_direct\n" + + "Aligned\n" + + "Structure I2_direct {\n" + + " 0 G_direct 8 \"\"\n" + + " 8 H1_direct 8 \"\"\n" + + " 16 undefined4 4 i21 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/J1/J1_direct\n" + + "Aligned\n" + + "Structure J1_direct {\n" + + " 0 I1_direct 20 \"\"\n" + + " 20 I2_direct 20 \"\"\n" + + " 40 undefined4 4 j11 \"\"\n" + + "}\n" + + "Size = 44 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedJ1_32() { + return convertCommentsToSpeculative(getExpectedJ1_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct J1 : I1, I2 { + int j11; + void j1f(); + }; + + class J1 size(96): + +--- + 0 | +--- (base class I1) + 0 | | +--- (base class G1) + 0 | | | {vbptr} + 8 | | | g11 + | | | (size=4) + | | +--- + 16 | | +--- (base class H) + 16 | | | {vbptr} + 24 | | | h1 + | | | (size=4) + | | | (size=4) + | | +--- + 32 | | i11 + | | (size=4) + | +--- + 40 | +--- (base class I2) + 40 | | +--- (base class G) + 40 | | | {vbptr} + 48 | | | g1 + | | | (size=4) + | | | (size=4) + | | +--- + 56 | | +--- (base class H1) + 56 | | | {vbptr} + 64 | | | h11 + | | | (size=4) + | | +--- + 72 | | i21 + | | (size=4) + | +--- + 80 | j11 + | (size=4) + +--- + +--- (virtual base C) + 88 | c1 + +--- + +--- (virtual base E) + 92 | e1 + +--- + + J1::$vbtable@G1@: + 0 | 0 + 1 | 88 (J1d(G1+0)C) + 2 | 92 (J1d(G1+0)E) + + J1::$vbtable@H@: + 0 | 0 + 1 | 72 (J1d(H+0)C) + + J1::$vbtable@G@: + 0 | 0 + 1 | 48 (J1d(G+0)C) + 2 | 52 (J1d(I2+0)E) + + J1::$vbtable@H1@: + 0 | 0 + 1 | 36 (J1d(H1+0)E) + 2 | 32 (J1d(H1+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 88 0 4 0 + E 92 0 8 0 + */ + //@formatter:on + @Test + public void testJ1_64_vbt() throws Exception { + CppCompositeType J1_struct = createJ1_struct64(pdbVbtManager64); + J1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = J1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ1_64(), composite, true); + } + + @Test + public void testJ1_64_speculative() throws Exception { + CppCompositeType J1_struct = createJ1_struct64(vbtManager64); + J1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = J1_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ1_64(), composite, true); + } + + private String getExpectedJ1_64() { + String expected = + //@formatter:off + "/J1\n" + + "Aligned\n" + + "Structure J1 {\n" + + " 0 J1_direct 88 \"\"\n" + + " 88 C_direct 4 \"(Virtual Base C)\"\n" + + " 92 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 96 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I1/I1_direct\n" + + "Aligned\n" + + "Structure I1_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 H_direct 16 \"\"\n" + + " 32 undefined4 4 i11 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/I2/I2_direct\n" + + "Aligned\n" + + "Structure I2_direct {\n" + + " 0 G_direct 16 \"\"\n" + + " 16 H1_direct 16 \"\"\n" + + " 32 undefined4 4 i21 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/J1/J1_direct\n" + + "Aligned\n" + + "Structure J1_direct {\n" + + " 0 I1_direct 40 \"\"\n" + + " 40 I2_direct 40 \"\"\n" + + " 80 undefined4 4 j11 \"\"\n" + + "}\n" + + "Size = 88 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedJ1_64() { + return convertCommentsToSpeculative(getExpectedJ1_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct J2 : I2, I1 { + int j21; + void j2f(); + }; + + class J2 size(52): + +--- + 0 | +--- (base class I2) + 0 | | +--- (base class G) + 0 | | | {vbptr} + 4 | | | g1 + | | +--- + 8 | | +--- (base class H1) + 8 | | | {vbptr} + 12 | | | h11 + | | +--- + 16 | | i21 + | +--- + 20 | +--- (base class I1) + 20 | | +--- (base class G1) + 20 | | | {vbptr} + 24 | | | g11 + | | +--- + 28 | | +--- (base class H) + 28 | | | {vbptr} + 32 | | | h1 + | | +--- + 36 | | i11 + | +--- + 40 | j21 + +--- + +--- (virtual base C) + 44 | c1 + +--- + +--- (virtual base E) + 48 | e1 + +--- + + J2::$vbtable@G@: + 0 | 0 + 1 | 44 (J2d(G+0)C) + 2 | 48 (J2d(I2+0)E) + + J2::$vbtable@H1@: + 0 | 0 + 1 | 40 (J2d(H1+0)E) + 2 | 36 (J2d(H1+0)C) + + J2::$vbtable@G1@: + 0 | 0 + 1 | 24 (J2d(G1+0)C) + 2 | 28 (J2d(G1+0)E) + + J2::$vbtable@H@: + 0 | 0 + 1 | 16 (J2d(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 44 0 4 0 + E 48 0 8 0 + */ + //@formatter:on + @Test + public void testJ2_32_vbt() throws Exception { + CppCompositeType J2_struct = createJ2_struct32(pdbVbtManager32); + J2_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = J2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ2_32(), composite, true); + } + + @Test + public void testJ2_32_speculative() throws Exception { + CppCompositeType J2_struct = createJ2_struct32(vbtManager32); + J2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = J2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ2_32(), composite, true); + } + + private String getExpectedJ2_32() { + String expected = + //@formatter:off + "/J2\n" + + "Aligned\n" + + "Structure J2 {\n" + + " 0 J2_direct 44 \"\"\n" + + " 44 C_direct 4 \"(Virtual Base C)\"\n" + + " 48 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 52 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I1/I1_direct\n" + + "Aligned\n" + + "Structure I1_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 H_direct 8 \"\"\n" + + " 16 undefined4 4 i11 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/I2/I2_direct\n" + + "Aligned\n" + + "Structure I2_direct {\n" + + " 0 G_direct 8 \"\"\n" + + " 8 H1_direct 8 \"\"\n" + + " 16 undefined4 4 i21 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/J2/J2_direct\n" + + "Aligned\n" + + "Structure J2_direct {\n" + + " 0 I2_direct 20 \"\"\n" + + " 20 I1_direct 20 \"\"\n" + + " 40 undefined4 4 j21 \"\"\n" + + "}\n" + + "Size = 44 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedJ2_32() { + return convertCommentsToSpeculative(getExpectedJ2_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct J2 : I2, I1 { + int j21; + void j2f(); + }; + + class J2 size(96): + +--- + 0 | +--- (base class I2) + 0 | | +--- (base class G) + 0 | | | {vbptr} + 8 | | | g1 + | | | (size=4) + | | | (size=4) + | | +--- + 16 | | +--- (base class H1) + 16 | | | {vbptr} + 24 | | | h11 + | | | (size=4) + | | +--- + 32 | | i21 + | | (size=4) + | +--- + 40 | +--- (base class I1) + 40 | | +--- (base class G1) + 40 | | | {vbptr} + 48 | | | g11 + | | | (size=4) + | | +--- + 56 | | +--- (base class H) + 56 | | | {vbptr} + 64 | | | h1 + | | | (size=4) + | | | (size=4) + | | +--- + 72 | | i11 + | | (size=4) + | +--- + 80 | j21 + | (size=4) + +--- + +--- (virtual base C) + 88 | c1 + +--- + +--- (virtual base E) + 92 | e1 + +--- + + J2::$vbtable@G@: + 0 | 0 + 1 | 88 (J2d(G+0)C) + 2 | 92 (J2d(I2+0)E) + + J2::$vbtable@H1@: + 0 | 0 + 1 | 76 (J2d(H1+0)E) + 2 | 72 (J2d(H1+0)C) + + J2::$vbtable@G1@: + 0 | 0 + 1 | 48 (J2d(G1+0)C) + 2 | 52 (J2d(G1+0)E) + + J2::$vbtable@H@: + 0 | 0 + 1 | 32 (J2d(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 88 0 4 0 + E 92 0 8 0 + */ + //@formatter:on + @Test + public void testJ2_64_vbt() throws Exception { + CppCompositeType J2_struct = createJ2_struct64(pdbVbtManager64); + J2_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = J2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ2_64(), composite, true); + } + + @Test + public void testJ2_64_speculative() throws Exception { + CppCompositeType J2_struct = createJ2_struct64(vbtManager64); + J2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = J2_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ2_64(), composite, true); + } + + private String getExpectedJ2_64() { + String expected = + //@formatter:off + "/J2\n" + + "Aligned\n" + + "Structure J2 {\n" + + " 0 J2_direct 88 \"\"\n" + + " 88 C_direct 4 \"(Virtual Base C)\"\n" + + " 92 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 96 Actual Alignment = 8\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I1/I1_direct\n" + + "Aligned\n" + + "Structure I1_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 H_direct 16 \"\"\n" + + " 32 undefined4 4 i11 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/I2/I2_direct\n" + + "Aligned\n" + + "Structure I2_direct {\n" + + " 0 G_direct 16 \"\"\n" + + " 16 H1_direct 16 \"\"\n" + + " 32 undefined4 4 i21 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/J2/J2_direct\n" + + "Aligned\n" + + "Structure J2_direct {\n" + + " 0 I2_direct 40 \"\"\n" + + " 40 I1_direct 40 \"\"\n" + + " 80 undefined4 4 j21 \"\"\n" + + "}\n" + + "Size = 88 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedJ2_64() { + return convertCommentsToSpeculative(getExpectedJ2_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct J3 : I2, I1, A { + int j31; + void j3f(); + }; + + class J3 size(60): + +--- + 0 | +--- (base class I2) + 0 | | +--- (base class G) + 0 | | | {vbptr} + 4 | | | g1 + | | +--- + 8 | | +--- (base class H1) + 8 | | | {vbptr} + 12 | | | h11 + | | +--- + 16 | | i21 + | +--- + 20 | +--- (base class I1) + 20 | | +--- (base class G1) + 20 | | | {vbptr} + 24 | | | g11 + | | +--- + 28 | | +--- (base class H) + 28 | | | {vbptr} + 32 | | | h1 + | | +--- + 36 | | i11 + | +--- + 40 | +--- (base class A) + 40 | | c + | | (size=3) + 44 | | i + | +--- + 48 | j31 + +--- + +--- (virtual base C) + 52 | c1 + +--- + +--- (virtual base E) + 56 | e1 + +--- + + J3::$vbtable@G@: + 0 | 0 + 1 | 52 (J3d(G+0)C) + 2 | 56 (J3d(I2+0)E) + + J3::$vbtable@H1@: + 0 | 0 + 1 | 48 (J3d(H1+0)E) + 2 | 44 (J3d(H1+0)C) + + J3::$vbtable@G1@: + 0 | 0 + 1 | 32 (J3d(G1+0)C) + 2 | 36 (J3d(G1+0)E) + + J3::$vbtable@H@: + 0 | 0 + 1 | 24 (J3d(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 52 0 4 0 + E 56 0 8 0 + */ + //@formatter:on + @Test + public void testJ3_32_vbt() throws Exception { + CppCompositeType J3_struct = createJ3_struct32(pdbVbtManager32); + J3_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = J3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ3_32(), composite, true); + } + + @Test + public void testJ3_32_speculative() throws Exception { + CppCompositeType J3_struct = createJ3_struct32(vbtManager32); + J3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = J3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ3_32(), composite, true); + } + + private String getExpectedJ3_32() { + String expected = + //@formatter:off + "/J3\n" + + "Aligned\n" + + "Structure J3 {\n" + + " 0 J3_direct 52 \"\"\n" + + " 52 C_direct 4 \"(Virtual Base C)\"\n" + + " 56 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 60 Actual Alignment = 4\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I1/I1_direct\n" + + "Aligned\n" + + "Structure I1_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 H_direct 8 \"\"\n" + + " 16 undefined4 4 i11 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/I2/I2_direct\n" + + "Aligned\n" + + "Structure I2_direct {\n" + + " 0 G_direct 8 \"\"\n" + + " 8 H1_direct 8 \"\"\n" + + " 16 undefined4 4 i21 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/J3/J3_direct\n" + + "Aligned\n" + + "Structure J3_direct {\n" + + " 0 I2_direct 20 \"\"\n" + + " 20 I1_direct 20 \"\"\n" + + " 40 A_direct 8 \"\"\n" + + " 48 undefined4 4 j31 \"\"\n" + + "}\n" + + "Size = 52 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedJ3_32() { + return convertCommentsToSpeculative(getExpectedJ3_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct J3 : I2, I1, A { + int j31; + void j3f(); + }; + + class J3 size(104): + +--- + 0 | +--- (base class I2) + 0 | | +--- (base class G) + 0 | | | {vbptr} + 8 | | | g1 + | | | (size=4) + | | | (size=4) + | | +--- + 16 | | +--- (base class H1) + 16 | | | {vbptr} + 24 | | | h11 + | | | (size=4) + | | +--- + 32 | | i21 + | | (size=4) + | +--- + 40 | +--- (base class I1) + 40 | | +--- (base class G1) + 40 | | | {vbptr} + 48 | | | g11 + | | | (size=4) + | | +--- + 56 | | +--- (base class H) + 56 | | | {vbptr} + 64 | | | h1 + | | | (size=4) + | | | (size=4) + | | +--- + 72 | | i11 + | | (size=4) + | +--- + 80 | +--- (base class A) + 80 | | c + | | (size=3) + 84 | | i + | +--- + 88 | j31 + | (size=4) + +--- + +--- (virtual base C) + 96 | c1 + +--- + +--- (virtual base E) + 100 | e1 + +--- + + J3::$vbtable@G@: + 0 | 0 + 1 | 96 (J3d(G+0)C) + 2 | 100 (J3d(I2+0)E) + + J3::$vbtable@H1@: + 0 | 0 + 1 | 84 (J3d(H1+0)E) + 2 | 80 (J3d(H1+0)C) + + J3::$vbtable@G1@: + 0 | 0 + 1 | 56 (J3d(G1+0)C) + 2 | 60 (J3d(G1+0)E) + + J3::$vbtable@H@: + 0 | 0 + 1 | 40 (J3d(H+0)C) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 96 0 4 0 + E 100 0 8 0 + */ + //@formatter:on + @Test + public void testJ3_64_vbt() throws Exception { + CppCompositeType J3_struct = createJ3_struct64(pdbVbtManager64); + J3_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = J3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ3_64(), composite, true); + } + + @Test + public void testJ3_64_speculative() throws Exception { + CppCompositeType J3_struct = createJ3_struct64(vbtManager64); + J3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = J3_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ3_64(), composite, true); + } + + private String getExpectedJ3_64() { + String expected = + //@formatter:off + "/J3\n" + + "Aligned\n" + + "Structure J3 {\n" + + " 0 J3_direct 96 \"\"\n" + + " 96 C_direct 4 \"(Virtual Base C)\"\n" + + " 100 E_direct 4 \"(Virtual Base E)\"\n" + + "}\n" + + "Size = 104 Actual Alignment = 8\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I1/I1_direct\n" + + "Aligned\n" + + "Structure I1_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 H_direct 16 \"\"\n" + + " 32 undefined4 4 i11 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/I2/I2_direct\n" + + "Aligned\n" + + "Structure I2_direct {\n" + + " 0 G_direct 16 \"\"\n" + + " 16 H1_direct 16 \"\"\n" + + " 32 undefined4 4 i21 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/J3/J3_direct\n" + + "Aligned\n" + + "Structure J3_direct {\n" + + " 0 I2_direct 40 \"\"\n" + + " 40 I1_direct 40 \"\"\n" + + " 80 A_direct 8 \"\"\n" + + " 88 undefined4 4 j31 \"\"\n" + + "}\n" + + "Size = 96 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedJ3_64() { + return convertCommentsToSpeculative(getExpectedJ3_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct J4 : I3, GG1, I, A, virtual GG2, virtual GG3 { + int j41; + void j4f(); + }; + + class J4 size(92): + +--- + 0 | +--- (base class I3) + 0 | | +--- (base class G1) + 0 | | | {vbptr} + 4 | | | g11 + | | +--- + 8 | | +--- (base class H1) + 8 | | | {vbptr} + 12 | | | h11 + | | +--- + 16 | | i31 + | +--- + 20 | +--- (base class GG1) + 20 | | {vbptr} + 24 | | gg11 + | +--- + 28 | +--- (base class I) + 28 | | +--- (base class G) + 28 | | | {vbptr} + 32 | | | g1 + | | +--- + 36 | | +--- (base class H) + 36 | | | {vbptr} + 40 | | | h1 + | | +--- + 44 | | i1 + | +--- + 48 | +--- (base class A) + 48 | | c + | | (size=3) + 52 | | i + | +--- + 56 | j41 + +--- + +--- (virtual base C) + 60 | c1 + +--- + +--- (virtual base E) + 64 | e1 + +--- + +--- (virtual base CC1) + 68 | cc11 + +--- + +--- (virtual base CC2) + 72 | cc21 + +--- + +--- (virtual base GG2) + 76 | {vbptr} + 80 | gg21 + +--- + +--- (virtual base GG3) + 84 | {vbptr} + 88 | gg31 + +--- + + J4::$vbtable@G1@: + 0 | 0 + 1 | 60 (J4d(G1+0)C) + 2 | 64 (J4d(G1+0)E) + 3 | 68 (J4d(J4+0)CC1) + 4 | 72 (J4d(J4+0)CC2) + 5 | 76 (J4d(J4+0)GG2) + 6 | 84 (J4d(J4+0)GG3) + + J4::$vbtable@H1@: + 0 | 0 + 1 | 56 (J4d(H1+0)E) + 2 | 52 (J4d(H1+0)C) + + J4::$vbtable@GG1@: + 0 | 0 + 1 | 48 (J4d(GG1+0)CC1) + + J4::$vbtable@G@: + 0 | 0 + 1 | 32 (J4d(G+0)C) + + J4::$vbtable@H@: + 0 | 0 + 1 | 24 (J4d(H+0)C) + + J4::$vbtable@GG2@: + 0 | 0 + 1 | -4 (J4d(GG2+0)CC2) + + J4::$vbtable@GG3@: + 0 | 0 + 1 | -12 (J4d(GG3+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 60 0 4 0 + E 64 0 8 0 + CC1 68 0 12 0 + CC2 72 0 16 0 + GG2 76 0 20 0 + GG3 84 0 24 0 + */ + //@formatter:on + @Test + public void testJ4_32_vbt() throws Exception { + CppCompositeType J4_struct = createJ4_struct32(pdbVbtManager32); + J4_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = J4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ4_32(), composite, true); + } + + @Test + public void testJ4_32_speculative() throws Exception { + CppCompositeType J4_struct = createJ4_struct32(vbtManager32); + J4_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = J4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ4_32(), composite, true); + } + + private String getExpectedJ4_32() { + String expected = + //@formatter:off + "/J4\n" + + "Aligned\n" + + "Structure J4 {\n" + + " 0 J4_direct 60 \"\"\n" + + " 60 C_direct 4 \"(Virtual Base C)\"\n" + + " 64 E_direct 4 \"(Virtual Base E)\"\n" + + " 68 CC1_direct 4 \"(Virtual Base CC1)\"\n" + + " 72 CC2_direct 4 \"(Virtual Base CC2)\"\n" + + " 76 GG2_direct 8 \"(Virtual Base GG2)\"\n" + + " 84 GG3_direct 8 \"(Virtual Base GG3)\"\n" + + "}\n" + + "Size = 92 Actual Alignment = 4\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC1/CC1_direct\n" + + "Aligned\n" + + "Structure CC1_direct {\n" + + " 0 undefined4 4 cc11 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/GG1/GG1_direct\n" + + "Aligned\n" + + "Structure GG1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/GG2/GG2_direct\n" + + "Aligned\n" + + "Structure GG2_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg21 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/GG3/GG3_direct\n" + + "Aligned\n" + + "Structure GG3_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg31 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I/I_direct\n" + + "Aligned\n" + + "Structure I_direct {\n" + + " 0 G_direct 8 \"\"\n" + + " 8 H_direct 8 \"\"\n" + + " 16 undefined4 4 i1 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/I3/I3_direct\n" + + "Aligned\n" + + "Structure I3_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 H1_direct 8 \"\"\n" + + " 16 undefined4 4 i31 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/J4/J4_direct\n" + + "Aligned\n" + + "Structure J4_direct {\n" + + " 0 I3_direct 20 \"\"\n" + + " 20 GG1_direct 8 \"\"\n" + + " 28 I_direct 20 \"\"\n" + + " 48 A_direct 8 \"\"\n" + + " 56 undefined4 4 j41 \"\"\n" + + "}\n" + + "Size = 60 Actual Alignment = 4"; + //@formatter:on + return expected; + } + + private String getSpeculatedJ4_32() { + return convertCommentsToSpeculative(getExpectedJ4_32()); + } + + //============================================================================================== + //@formatter:off + /* + struct J4 : I3, GG1, I, A, virtual GG2, virtual GG3 { + int j41; + void j4f(); + }; + + class J4 size(160): + +--- + 0 | +--- (base class I3) + 0 | | +--- (base class G1) + 0 | | | {vbptr} + 8 | | | g11 + | | | (size=4) + | | +--- + 16 | | +--- (base class H1) + 16 | | | {vbptr} + 24 | | | h11 + | | | (size=4) + | | +--- + 32 | | i31 + | | (size=4) + | +--- + 40 | +--- (base class GG1) + 40 | | {vbptr} + 48 | | gg11 + | | (size=4) + | | (size=4) + | +--- + 56 | +--- (base class I) + 56 | | +--- (base class G) + 56 | | | {vbptr} + 64 | | | g1 + | | | (size=4) + | | | (size=4) + | | +--- + 72 | | +--- (base class H) + 72 | | | {vbptr} + 80 | | | h1 + | | | (size=4) + | | | (size=4) + | | +--- + 88 | | i1 + | | (size=4) + | | (size=4) + | +--- + 96 | +--- (base class A) + 96 | | c + | | (size=3) + 100 | | i + | +--- + 104 | j41 + | (size=4) + +--- + +--- (virtual base C) + 112 | c1 + +--- + +--- (virtual base E) + 116 | e1 + +--- + +--- (virtual base CC1) + 120 | cc11 + +--- + +--- (virtual base CC2) + 124 | cc21 + +--- + +--- (virtual base GG2) + 128 | {vbptr} + 136 | gg21 + | (size=4) + | (size=4) + +--- + +--- (virtual base GG3) + 144 | {vbptr} + 152 | gg31 + | (size=4) + | (size=4) + +--- + + J4::$vbtable@G1@: + 0 | 0 + 1 | 112 (J4d(G1+0)C) + 2 | 116 (J4d(G1+0)E) + 3 | 120 (J4d(J4+0)CC1) + 4 | 124 (J4d(J4+0)CC2) + 5 | 128 (J4d(J4+0)GG2) + 6 | 144 (J4d(J4+0)GG3) + + J4::$vbtable@H1@: + 0 | 0 + 1 | 100 (J4d(H1+0)E) + 2 | 96 (J4d(H1+0)C) + + J4::$vbtable@GG1@: + 0 | 0 + 1 | 80 (J4d(GG1+0)CC1) + + J4::$vbtable@G@: + 0 | 0 + 1 | 56 (J4d(G+0)C) + + J4::$vbtable@H@: + 0 | 0 + 1 | 40 (J4d(H+0)C) + + J4::$vbtable@GG2@: + 0 | 0 + 1 | -4 (J4d(GG2+0)CC2) + + J4::$vbtable@GG3@: + 0 | 0 + 1 | -20 (J4d(GG3+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + C 112 0 4 0 + E 116 0 8 0 + CC1 120 0 12 0 + CC2 124 0 16 0 + GG2 128 0 20 0 + GG3 144 0 24 0 + */ + //@formatter:on + @Test + public void testJ4_64_vbt() throws Exception { + CppCompositeType J4_struct = createJ4_struct64(pdbVbtManager64); + J4_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = J4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ4_64(), composite, true); + } + + @Test + public void testJ4_64_speculative() throws Exception { + CppCompositeType J4_struct = createJ4_struct64(vbtManager64); + J4_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = J4_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ4_64(), composite, true); + } + + private String getExpectedJ4_64() { + String expected = + //@formatter:off + "/J4\n" + + "Aligned\n" + + "Structure J4 {\n" + + " 0 J4_direct 112 \"\"\n" + + " 112 C_direct 4 \"(Virtual Base C)\"\n" + + " 116 E_direct 4 \"(Virtual Base E)\"\n" + + " 120 CC1_direct 4 \"(Virtual Base CC1)\"\n" + + " 124 CC2_direct 4 \"(Virtual Base CC2)\"\n" + + " 128 GG2_direct 16 \"(Virtual Base GG2)\"\n" + + " 144 GG3_direct 16 \"(Virtual Base GG3)\"\n" + + "}\n" + + "Size = 160 Actual Alignment = 8\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC1/CC1_direct\n" + + "Aligned\n" + + "Structure CC1_direct {\n" + + " 0 undefined4 4 cc11 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/GG1/GG1_direct\n" + + "Aligned\n" + + "Structure GG1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/GG2/GG2_direct\n" + + "Aligned\n" + + "Structure GG2_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg21 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/GG3/GG3_direct\n" + + "Aligned\n" + + "Structure GG3_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg31 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I/I_direct\n" + + "Aligned\n" + + "Structure I_direct {\n" + + " 0 G_direct 16 \"\"\n" + + " 16 H_direct 16 \"\"\n" + + " 32 undefined4 4 i1 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/I3/I3_direct\n" + + "Aligned\n" + + "Structure I3_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 H1_direct 16 \"\"\n" + + " 32 undefined4 4 i31 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/J4/J4_direct\n" + + "Aligned\n" + + "Structure J4_direct {\n" + + " 0 I3_direct 40 \"\"\n" + + " 40 GG1_direct 16 \"\"\n" + + " 56 I_direct 40 \"\"\n" + + " 96 A_direct 8 \"\"\n" + + " 104 undefined4 4 j41 \"\"\n" + + "}\n" + + "Size = 112 Actual Alignment = 8"; + //@formatter:on + return expected; + } + + private String getSpeculatedJ4_64() { + return convertCommentsToSpeculative(getExpectedJ4_64()); + } + + //============================================================================================== + //@formatter:off + /* + struct J5 : virtual GG2, virtual GG3, I3, GG1, I, A { + int j51; + void j5f(); + }; + + class J5 size(92): + +--- + 0 | +--- (base class I3) + 0 | | +--- (base class G1) + 0 | | | {vbptr} + 4 | | | g11 + | | +--- + 8 | | +--- (base class H1) + 8 | | | {vbptr} + 12 | | | h11 + | | +--- + 16 | | i31 + | +--- + 20 | +--- (base class GG1) + 20 | | {vbptr} + 24 | | gg11 + | +--- + 28 | +--- (base class I) + 28 | | +--- (base class G) + 28 | | | {vbptr} + 32 | | | g1 + | | +--- + 36 | | +--- (base class H) + 36 | | | {vbptr} + 40 | | | h1 + | | +--- + 44 | | i1 + | +--- + 48 | +--- (base class A) + 48 | | c + | | (size=3) + 52 | | i + | +--- + 56 | j51 + +--- + +--- (virtual base CC2) + 60 | cc21 + +--- + +--- (virtual base GG2) + 64 | {vbptr} + 68 | gg21 + +--- + +--- (virtual base GG3) + 72 | {vbptr} + 76 | gg31 + +--- + +--- (virtual base C) + 80 | c1 + +--- + +--- (virtual base E) + 84 | e1 + +--- + +--- (virtual base CC1) + 88 | cc11 + +--- + + J5::$vbtable@G1@: + 0 | 0 + 1 | 80 (J5d(G1+0)C) + 2 | 84 (J5d(G1+0)E) + 3 | 60 (J5d(J5+0)CC2) + 4 | 64 (J5d(J5+0)GG2) + 5 | 72 (J5d(J5+0)GG3) + 6 | 88 (J5d(J5+0)CC1) + + J5::$vbtable@H1@: + 0 | 0 + 1 | 76 (J5d(H1+0)E) + 2 | 72 (J5d(H1+0)C) + + J5::$vbtable@GG1@: + 0 | 0 + 1 | 68 (J5d(GG1+0)CC1) + + J5::$vbtable@G@: + 0 | 0 + 1 | 52 (J5d(G+0)C) + + J5::$vbtable@H@: + 0 | 0 + 1 | 44 (J5d(H+0)C) + + J5::$vbtable@GG2@: + 0 | 0 + 1 | -4 (J5d(GG2+0)CC2) + + J5::$vbtable@GG3@: + 0 | 0 + 1 | -12 (J5d(GG3+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC2 60 0 12 0 + GG2 64 0 16 0 + GG3 72 0 20 0 + C 80 0 4 0 + E 84 0 8 0 + CC1 88 0 24 0 + */ + //@formatter:on + @Test + public void testJ5_32_vbt() throws Exception { + CppCompositeType J5_struct = createJ5_struct32(pdbVbtManager32); + J5_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = J5_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ5_32(), composite, true); + } + + // TODO: Need to work on layout algorithm... believe we can do better, but don't have + // a decision on the best speculative results yet. +// @Test + public void testJ5_32_speculative() throws Exception { + CppCompositeType J5_struct = createJ5_struct32(vbtManager32); + J5_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = J5_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ5_32(), composite, true); + } + + private String getExpectedJ5_32() { + String expected = + //@formatter:off + "/J5\n" + + "Aligned\n" + + "Structure J5 {\n" + + " 0 J5_direct 60 \"\"\n" + + " 60 CC2_direct 4 \"(Virtual Base CC2)\"\n" + + " 64 GG2_direct 8 \"(Virtual Base GG2)\"\n" + + " 72 GG3_direct 8 \"(Virtual Base GG3)\"\n" + + " 80 C_direct 4 \"(Virtual Base C)\"\n" + + " 84 E_direct 4 \"(Virtual Base E)\"\n" + + " 88 CC1_direct 4 \"(Virtual Base CC1)\"\n" + + "}\n" + + "Size = 92 Actual Alignment = 4\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC1/CC1_direct\n" + + "Aligned\n" + + "Structure CC1_direct {\n" + + " 0 undefined4 4 cc11 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/GG1/GG1_direct\n" + + "Aligned\n" + + "Structure GG1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/GG2/GG2_direct\n" + + "Aligned\n" + + "Structure GG2_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg21 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/GG3/GG3_direct\n" + + "Aligned\n" + + "Structure GG3_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg31 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/I/I_direct\n" + + "Aligned\n" + + "Structure I_direct {\n" + + " 0 G_direct 8 \"\"\n" + + " 8 H_direct 8 \"\"\n" + + " 16 undefined4 4 i1 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/I3/I3_direct\n" + + "Aligned\n" + + "Structure I3_direct {\n" + + " 0 G1_direct 8 \"\"\n" + + " 8 H1_direct 8 \"\"\n" + + " 16 undefined4 4 i31 \"\"\n" + + "}\n" + + "Size = 20 Actual Alignment = 4\n" + + "/J5/J5_direct\n" + + "Aligned\n" + + "Structure J5_direct {\n" + + " 0 I3_direct 20 \"\"\n" + + " 20 GG1_direct 8 \"\"\n" + + " 28 I_direct 20 \"\"\n" + + " 48 A_direct 8 \"\"\n" + + " 56 undefined4 4 j51 \"\"\n" + + "}\n" + + "Size = 60 Actual Alignment = 4"; + + //@formatter:on + return expected; + } + + private String getSpeculatedJ5_32() { + String expected = + //@formatter:off + "NOT YET DETERMINED"; + //@formatter:on + return expected; + } + + //============================================================================================== + //@formatter:off + /* + struct J5 : virtual GG2, virtual GG3, I3, GG1, I, A { + int j51; + void j5f(); + }; + + class J5 size(164): + +--- + 0 | +--- (base class I3) + 0 | | +--- (base class G1) + 0 | | | {vbptr} + 8 | | | g11 + | | | (size=4) + | | +--- + 16 | | +--- (base class H1) + 16 | | | {vbptr} + 24 | | | h11 + | | | (size=4) + | | +--- + 32 | | i31 + | | (size=4) + | +--- + 40 | +--- (base class GG1) + 40 | | {vbptr} + 48 | | gg11 + | | (size=4) + | | (size=4) + | +--- + 56 | +--- (base class I) + 56 | | +--- (base class G) + 56 | | | {vbptr} + 64 | | | g1 + | | | (size=4) + | | | (size=4) + | | +--- + 72 | | +--- (base class H) + 72 | | | {vbptr} + 80 | | | h1 + | | | (size=4) + | | | (size=4) + | | +--- + 88 | | i1 + | | (size=4) + | | (size=4) + | +--- + 96 | +--- (base class A) + 96 | | c + | | (size=3) + 100 | | i + | +--- + 104 | j51 + | (size=4) + | (size=4) + +--- + +--- (virtual base CC2) + 112 | cc21 + +--- + +--- (virtual base GG2) + 120 | {vbptr} + 128 | gg21 + | (size=4) + | (size=4) + +--- + +--- (virtual base GG3) + 136 | {vbptr} + 144 | gg31 + | (size=4) + | (size=4) + +--- + +--- (virtual base C) + 152 | c1 + +--- + +--- (virtual base E) + 156 | e1 + +--- + +--- (virtual base CC1) + 160 | cc11 + +--- + + J5::$vbtable@G1@: + 0 | 0 + 1 | 152 (J5d(G1+0)C) + 2 | 156 (J5d(G1+0)E) + 3 | 112 (J5d(J5+0)CC2) + 4 | 120 (J5d(J5+0)GG2) + 5 | 136 (J5d(J5+0)GG3) + 6 | 160 (J5d(J5+0)CC1) + + J5::$vbtable@H1@: + 0 | 0 + 1 | 140 (J5d(H1+0)E) + 2 | 136 (J5d(H1+0)C) + + J5::$vbtable@GG1@: + 0 | 0 + 1 | 120 (J5d(GG1+0)CC1) + + J5::$vbtable@G@: + 0 | 0 + 1 | 96 (J5d(G+0)C) + + J5::$vbtable@H@: + 0 | 0 + 1 | 80 (J5d(H+0)C) + + J5::$vbtable@GG2@: + 0 | 0 + 1 | -8 (J5d(GG2+0)CC2) + + J5::$vbtable@GG3@: + 0 | 0 + 1 | -24 (J5d(GG3+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC2 112 0 12 0 + GG2 120 0 16 0 + GG3 136 0 20 0 + C 152 0 4 0 + E 156 0 8 0 + CC1 160 0 24 0 + */ + //@formatter:on + @Test + public void testJ5_64_vbt() throws Exception { + CppCompositeType J5_struct = createJ5_struct64(pdbVbtManager64); + J5_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = J5_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ5_64(), composite, true); + } + + // TODO: Need to work on layout algorithm... believe we can do better, but don't have + // a decision on the best speculative results yet. +// @Test + public void testJ5_64_speculative() throws Exception { + CppCompositeType J5_struct = createJ5_struct64(vbtManager64); + J5_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = J5_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ5_64(), composite, true); + } + + private String getExpectedJ5_64() { + String expected = + //@formatter:off + "/J5\n" + + "Aligned\n" + + "Structure J5 {\n" + + " 0 J5_direct 112 \"\"\n" + + " 112 CC2_direct 4 \"(Virtual Base CC2)\"\n" + + " 120 GG2_direct 16 \"(Virtual Base GG2)\"\n" + + " 136 GG3_direct 16 \"(Virtual Base GG3)\"\n" + + " 152 C_direct 4 \"(Virtual Base C)\"\n" + + " 156 E_direct 4 \"(Virtual Base E)\"\n" + + " 160 CC1_direct 4 \"(Virtual Base CC1)\"\n" + + "}\n" + + "Size = 168 Actual Alignment = 8\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/C/C_direct\n" + + "Aligned\n" + + "Structure C_direct {\n" + + " 0 undefined4 4 c1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC1/CC1_direct\n" + + "Aligned\n" + + "Structure CC1_direct {\n" + + " 0 undefined4 4 cc11 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/E/E_direct\n" + + "Aligned\n" + + "Structure E_direct {\n" + + " 0 undefined4 4 e1 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/G/G_direct\n" + + "Aligned\n" + + "Structure G_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/G1/G1_direct\n" + + "Aligned\n" + + "Structure G1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 g11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/GG1/GG1_direct\n" + + "Aligned\n" + + "Structure GG1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/GG2/GG2_direct\n" + + "Aligned\n" + + "Structure GG2_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg21 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/GG3/GG3_direct\n" + + "Aligned\n" + + "Structure GG3_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg31 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H/H_direct\n" + + "Aligned\n" + + "Structure H_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h1 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/H1/H1_direct\n" + + "Aligned\n" + + "Structure H1_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 h11 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/I/I_direct\n" + + "Aligned\n" + + "Structure I_direct {\n" + + " 0 G_direct 16 \"\"\n" + + " 16 H_direct 16 \"\"\n" + + " 32 undefined4 4 i1 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/I3/I3_direct\n" + + "Aligned\n" + + "Structure I3_direct {\n" + + " 0 G1_direct 16 \"\"\n" + + " 16 H1_direct 16 \"\"\n" + + " 32 undefined4 4 i31 \"\"\n" + + "}\n" + + "Size = 40 Actual Alignment = 8\n" + + "/J5/J5_direct\n" + + "Aligned\n" + + "Structure J5_direct {\n" + + " 0 I3_direct 40 \"\"\n" + + " 40 GG1_direct 16 \"\"\n" + + " 56 I_direct 40 \"\"\n" + + " 96 A_direct 8 \"\"\n" + + " 104 undefined4 4 j51 \"\"\n" + + "}\n" + + "Size = 112 Actual Alignment = 8"; + + //@formatter:on + return expected; + } + + private String getSpeculatedJ5_64() { + String expected = + //@formatter:off + "NOT YET DETERMINED"; + //@formatter:on + return expected; + } + + //============================================================================================== + //@formatter:off + /* + struct J6 : virtual GG4, virtual GG3, A { //GG4 contains CC3, which has no members + int j61; + void j6f(); + }; + + class J6 size(36): + +--- + 0 | +--- (base class A) + 0 | | c + | | (size=3) + 4 | | i + | +--- + 8 | {vbptr} + 12 | j61 + +--- + +--- (virtual base CC3) + +--- + +--- (virtual base GG4) + 16 | {vbptr} + 20 | gg41 + +--- + +--- (virtual base CC2) + 24 | cc21 + +--- + +--- (virtual base GG3) + 28 | {vbptr} + 32 | gg31 + +--- + + J6::$vbtable@J6@: + 0 | -8 + 1 | 8 (J6d(J6+8)CC3) + 2 | 8 (J6d(J6+8)GG4) + 3 | 16 (J6d(J6+8)CC2) + 4 | 20 (J6d(J6+8)GG3) + + J6::$vbtable@GG4@: + 0 | 0 + 1 | 0 (J6d(GG4+0)CC3) + + J6::$vbtable@GG3@: + 0 | 0 + 1 | -4 (J6d(GG3+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC3 16 8 4 0 + GG4 16 8 8 0 + CC2 24 8 12 0 + GG3 28 8 16 0 + */ + //@formatter:on + @Test + public void testJ6_32_vbt() throws Exception { + CppCompositeType J6_struct = createJ6_struct32(pdbVbtManager32); + J6_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + Composite composite = J6_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ6_32(), composite, true); + } + + // TODO: Need to work on layout algorithm... believe we can do better, but don't have + // a decision on the best speculative results yet. +// @Test + public void testJ6_32_speculative() throws Exception { + CppCompositeType J6_struct = createJ6_struct32(vbtManager32); + J6_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + Composite composite = J6_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ6_32(), composite, true); + } + + private String getExpectedJ6_32() { + String expected = + //@formatter:off + "/J6\n" + + "Aligned\n" + + "Structure J6 {\n" + + " 0 J6_direct 16 \"\"\n" + + " 16 GG4_direct 8 \"(Virtual Base GG4)\"\n" + + " 24 CC2_direct 4 \"(Virtual Base (empty) CC3)(Virtual Base CC2)\"\n" + + " 28 GG3_direct 8 \"(Virtual Base GG3)\"\n" + + "}\n" + + "Size = 36 Actual Alignment = 4\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/GG3/GG3_direct\n" + + "Aligned\n" + + "Structure GG3_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg31 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/GG4/GG4_direct\n" + + "Aligned\n" + + "Structure GG4_direct {\n" + + " 0 int * 4 {vbptr} \"\"\n" + + " 4 undefined4 4 gg41 \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/J6/J6_direct\n" + + "Aligned\n" + + "Structure J6_direct {\n" + + " 0 A_direct 8 \"\"\n" + + " 8 int * 4 {vbptr} \"\"\n" + + " 12 undefined4 4 j61 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 4"; + + //@formatter:on + return expected; + } + + private String getSpeculatedJ6_32() { + String expected = + //@formatter:off + "NOT YET DETERMINED"; + //@formatter:on + return expected; + } + + //============================================================================================== + //@formatter:off + /* + struct J6 : virtual GG4, virtual GG3, A { //GG4 contains CC3, which has no members + int j61; + void j6f(); + }; + + class J6 size(64): + +--- + 0 | +--- (base class A) + 0 | | c + | | (size=3) + 4 | | i + | +--- + 8 | {vbptr} + 16 | j61 + | (size=4) + | (size=4) + +--- + +--- (virtual base CC3) + +--- + +--- (virtual base GG4) + 24 | {vbptr} + 32 | gg41 + | (size=4) + +--- + +--- (virtual base CC2) + 40 | cc21 + +--- + +--- (virtual base GG3) + 48 | {vbptr} + 56 | gg31 + | (size=4) + | (size=4) + +--- + + J6::$vbtable@J6@: + 0 | -8 + 1 | 16 (J6d(J6+8)CC3) + 2 | 16 (J6d(J6+8)GG4) + 3 | 32 (J6d(J6+8)CC2) + 4 | 40 (J6d(J6+8)GG3) + + J6::$vbtable@GG4@: + 0 | 0 + 1 | 0 (J6d(GG4+0)CC3) + + J6::$vbtable@GG3@: + 0 | 0 + 1 | -8 (J6d(GG3+0)CC2) + vbi: class offset o.vbptr o.vbte fVtorDisp + CC3 24 8 4 0 + GG4 24 8 8 0 + CC2 40 8 12 0 + GG3 48 8 16 0 + */ + //@formatter:on + @Test + public void testJ6_64_vbt() throws Exception { + CppCompositeType J6_struct = createJ6_struct64(pdbVbtManager64); + J6_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + Composite composite = J6_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getExpectedJ6_64(), composite, true); + } + + // TODO: Need to work on layout algorithm... believe we can do better, but don't have + // a decision on the best speculative results yet. +// @Test + public void testJ6_64_speculative() throws Exception { + CppCompositeType J6_struct = createJ6_struct64(vbtManager64); + J6_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + Composite composite = J6_struct.getComposite(); + CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ6_64(), composite, true); + } + + private String getExpectedJ6_64() { + String expected = + //@formatter:off + "/J6\n" + + "Aligned\n" + + "Structure J6 {\n" + + " 0 J6_direct 24 \"\"\n" + + " 24 GG4_direct 16 \"(Virtual Base GG4)\"\n" + + " 40 CC2_direct 4 \"(Virtual Base (empty) CC3)(Virtual Base CC2)\"\n" + + " 48 GG3_direct 16 \"(Virtual Base GG3)\"\n" + + "}\n" + + "Size = 64 Actual Alignment = 8\n" + + "/A/A_direct\n" + + "Aligned\n" + + "Structure A_direct {\n" + + " 0 undefined1 1 c \"\"\n" + + " 4 undefined4 4 i \"\"\n" + + "}\n" + + "Size = 8 Actual Alignment = 4\n" + + "/CC2/CC2_direct\n" + + "Aligned\n" + + "Structure CC2_direct {\n" + + " 0 undefined4 4 cc21 \"\"\n" + + "}\n" + + "Size = 4 Actual Alignment = 4\n" + + "/GG3/GG3_direct\n" + + "Aligned\n" + + "Structure GG3_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg31 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/GG4/GG4_direct\n" + + "Aligned\n" + + "Structure GG4_direct {\n" + + " 0 int * 8 {vbptr} \"\"\n" + + " 8 undefined4 4 gg41 \"\"\n" + + "}\n" + + "Size = 16 Actual Alignment = 8\n" + + "/J6/J6_direct\n" + + "Aligned\n" + + "Structure J6_direct {\n" + + " 0 A_direct 8 \"\"\n" + + " 8 int * 8 {vbptr} \"\"\n" + + " 16 undefined4 4 j61 \"\"\n" + + "}\n" + + "Size = 24 Actual Alignment = 8"; + + //@formatter:on + return expected; + } + + private String getSpeculatedJ6_64() { + String expected = + //@formatter:off + "NOT YET DETERMINED"; + //@formatter:on + return expected; + } + + //============================================================================================== + //============================================================================================== + //============================================================================================== + +// @Test + @Ignore + public void testJ5_32_syntactic_layout() throws Exception { + CppCompositeType J5_struct = createJ5_syntactic_struct32(pdbVbtManager32); + J5_struct.createLayoutFromSyntacticDescription(pdbVbtManager32, TaskMonitor.DUMMY); + // + //Composite composite = J5_struct.getComposite(); + //CompositeTestUtils.assertExpectedComposite(this, getExpectedJ5_32(), composite, true); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java index 27a6fb943c..b2d43790cb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java @@ -45,7 +45,9 @@ public class SymbolPathParser { throw new IllegalArgumentException( "Symbol list must contain at least one symbol name!"); } - if (name.indexOf(Namespace.DELIMITER) == -1) { +// if (name.indexOf(Namespace.DELIMITER) == -1) { + // following is temporary kludge due to struct (blah). TODO: figure/fix + if (name.startsWith("(") || name.indexOf(Namespace.DELIMITER) == -1) { List list = new ArrayList<>(); list.add(name); return list; From 9f7fc60f76e27db78460fa61367280d76e1e1639 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Sun, 6 Sep 2020 18:00:59 -0400 Subject: [PATCH 02/15] GT-3112 - PDB Universal - review changes --- ...nalyzer.java => PdbUniversalAnalyzer.java} | 7 +- ...bCategoryUtils.java => PdbCategories.java} | 4 +- .../app/util/pdb/PdbNamespaceUtils.java | 4 + .../AbstractComplexTypeApplier.java | 41 ++--- .../AbstractFunctionTypeApplier.java | 59 ++++--- .../ArgumentsListTypeApplier.java | 40 +---- .../pdb/pdbapplicator/ArrayTypeApplier.java | 39 +---- .../pdbapplicator/BaseClassTypeApplier.java | 20 +-- .../pdbapplicator/BitfieldTypeApplier.java | 27 +-- .../pdbapplicator/BlockCommentsManager.java | 3 + .../pdb/pdbapplicator/BlockSymbolApplier.java | 22 +-- .../ComplexTypeApplierMapper.java | 23 +-- .../pdbapplicator/CompositeLayoutMode.java | 7 +- .../pdbapplicator/CompositeTypeApplier.java | 154 ++++++++---------- .../pdb/pdbapplicator/CppCompositeType.java | 5 +- .../pdb/pdbapplicator/DataSymbolApplier.java | 36 ++-- ...er.java => DefaultPdbUniversalMember.java} | 13 +- ...efinedSingleAddressRangeSymbolApplier.java | 19 ++- .../pdb/pdbapplicator/EndSymbolApplier.java | 25 +-- .../pdb/pdbapplicator/EnumTypeApplier.java | 71 ++++---- .../pdbapplicator/EnumerateTypeApplier.java | 29 +--- .../pdbapplicator/FieldListTypeApplier.java | 37 ++--- ...eAndProcedureInformationSymbolApplier.java | 13 +- .../pdbapplicator/FunctionSymbolApplier.java | 50 +++--- .../pdb/pdbapplicator/LabelSymbolApplier.java | 14 +- .../LocalOptimizedSymbolApplier.java | 19 ++- .../MemberFunctionTypeApplier.java | 39 ++--- .../pdb/pdbapplicator/MemberTypeApplier.java | 36 ++-- .../pdbapplicator/ModifierTypeApplier.java | 44 +---- ...ymbolApplier.java => MsSymbolApplier.java} | 43 +++-- ...tMsTypeApplier.java => MsTypeApplier.java} | 110 ++++++++----- .../pdb/pdbapplicator/NestedTypeApplier.java | 26 +-- .../pdb/pdbapplicator/NoSymbolApplier.java | 17 +- .../util/pdb/pdbapplicator/NoTypeApplier.java | 8 +- .../pdbapplicator/OoComponentLayoutMode.java | 5 +- .../pdb/pdbapplicator/PdbAddressManager.java | 26 +-- .../util/pdb/pdbapplicator/PdbApplicator.java | 135 ++++++++------- .../pdbapplicator/PdbApplicatorMetrics.java | 112 ++++++------- .../pdbapplicator/PdbApplicatorOptions.java | 14 +- .../PdbPrimitiveTypeApplicator.java | 2 +- ...dbRegisterNameToProgramRegisterMapper.java | 13 +- .../util/pdb/pdbapplicator/PdbResearch.java | 102 +++++++----- .../util/pdb/pdbapplicator/PdbVbtManager.java | 3 +- .../PeCoffGroupSymbolApplier.java | 13 +- .../PeCoffSectionSymbolApplier.java | 11 +- .../pdb/pdbapplicator/PointerTypeApplier.java | 32 ++-- .../pdbapplicator/PrimitiveTypeApplier.java | 27 +-- .../pdbapplicator/ProcedureTypeApplier.java | 23 +-- .../pdbapplicator/PublicSymbolApplier.java | 19 ++- .../pdbapplicator/ReferenceSymbolApplier.java | 11 +- .../RegisterRelativeSymbolApplier.java | 23 +-- .../SeparatedCodeSymbolApplier.java | 27 +-- ...rParser.java => SymbolApplierFactory.java} | 15 +- .../util/pdb/pdbapplicator/SymbolGroup.java | 43 ++--- .../TrampolineSymbolApplier.java | 15 +- ...ierParser.java => TypeApplierFactory.java} | 117 +++++++------ .../pdbapplicator/TypedefSymbolApplier.java | 19 ++- .../UdtSourceLineTypeApplier.java | 16 +- ...irtualFunctionTablePointerTypeApplier.java | 20 +-- .../pdb/pdbapplicator/VtShapeTypeApplier.java | 33 ++-- .../pdb/pdbapplicator/WithSymbolApplier.java | 26 +-- .../pdbapplicator/CppCompositeTypeTest.java | 9 +- .../ghidra/app/util/SymbolPathParser.java | 2 + .../program/model/mem/MemoryBlockStub.java | 19 ++- .../ghidra/program/model/mem/MemoryStub.java | 55 ++----- 65 files changed, 1046 insertions(+), 1045 deletions(-) rename Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/{Pdb2Analyzer.java => PdbUniversalAnalyzer.java} (99%) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/{PdbCategoryUtils.java => PdbCategories.java} (98%) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/{Default2PdbMember.java => DefaultPdbUniversalMember.java} (90%) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/{AbstractMsSymbolApplier.java => MsSymbolApplier.java} (58%) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/{AbstractMsTypeApplier.java => MsTypeApplier.java} (59%) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/{SymbolApplierParser.java => SymbolApplierFactory.java} (98%) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/{TypeApplierParser.java => TypeApplierFactory.java} (78%) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/Pdb2Analyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java similarity index 99% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/Pdb2Analyzer.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java index aa633d7f5d..a15e40590c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/Pdb2Analyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java @@ -51,9 +51,10 @@ import ghidra.util.task.TaskMonitor; /** * PDB Universal Reader/Analyzer. Uses raw PDB files (not XML-converted PDBs). Attempts to - * apply the information to a program. + * apply the information to a program. It has Universal in the name to describe the fact that + * it written in java, making it platform independent, unlike a previous PDB analyzer. */ -public class Pdb2Analyzer extends AbstractAnalyzer { +public class PdbUniversalAnalyzer extends AbstractAnalyzer { // Developer turn on/off options that are in still in development. private static final boolean developerMode = false; @@ -211,7 +212,7 @@ public class Pdb2Analyzer extends AbstractAnalyzer { //============================================================================================== //============================================================================================== - public Pdb2Analyzer() { + public PdbUniversalAnalyzer() { super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); setPrototype(); // false for now; after proven... then TODO: true always diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategoryUtils.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java similarity index 98% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategoryUtils.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java index 346d3717dd..8ce9935278 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategoryUtils.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbCategories.java @@ -29,7 +29,7 @@ import ghidra.program.model.data.CategoryPath; * while parsing a PDB and the count (state) of anonymous functions for their creation within * the particular PDB's {@link Category}. */ -public class PdbCategoryUtils { +public class PdbCategories { private CategoryPath pdbRootCategory; private CategoryPath pdbUncategorizedCategory; @@ -49,7 +49,7 @@ public class PdbCategoryUtils { * @param pdbCategoryName pathname of the PDB file that this category represents. * @param moduleNames module names */ - public PdbCategoryUtils(String pdbCategoryName, List moduleNames) { + public PdbCategories(String pdbCategoryName, List moduleNames) { Objects.requireNonNull(pdbCategoryName, "pdbCategoryName cannot be null"); pdbRootCategory = new CategoryPath(CategoryPath.ROOT, pdbCategoryName); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java index e195d4f77e..db8901d521 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java @@ -85,6 +85,10 @@ public class PdbNamespaceUtils { * @param index the index number used be used as part of a unique tag name. * @return the resulting name. */ + // TODO: investigate if we can work a solution that no longer needs/has the index attached. + // I don't believe we are handling all of these correctly... someone else suggests regex, but + // that makes work in this area less clear until we know what we are doing... + // so, for now... DO NOT DO REGEX. public static String fixUnnamed(String name, int index) { if ("".equals(name)) { return String.format("", index); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java index 3f73c1f4e4..0e6aa131ca 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java @@ -19,17 +19,20 @@ import ghidra.app.util.SymbolPath; import ghidra.app.util.SymbolPathParser; 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.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractComplexMsType; import ghidra.app.util.pdb.PdbNamespaceUtils; import ghidra.program.model.data.DataType; -public abstract class AbstractComplexTypeApplier extends AbstractMsTypeApplier { +/** + * Applier for {@link AbstractComplexMsType} types. + */ +public abstract class AbstractComplexTypeApplier extends MsTypeApplier { protected SymbolPath symbolPath; protected SymbolPath fixedSymbolPath; protected AbstractComplexTypeApplier definitionApplier = null; - protected AbstractComplexTypeApplier fwdRefApplier = null; + protected AbstractComplexTypeApplier forwardReferenceApplier = null; public static AbstractComplexTypeApplier getComplexApplier(PdbApplicator applicator, RecordNumber recordNumber) throws PdbException { @@ -40,40 +43,31 @@ public abstract class AbstractComplexTypeApplier extends AbstractMsTypeApplier { /** * Constructor for complex type applier. * @param applicator {@link PdbApplicator} for which this class is working. - * @param msType {@link AbstractEnumMsType} to process. - * @throws IllegalArgumentException Upon invalid arguments. + * @param msType {@link AbstractComplexMsType} to process. */ - public AbstractComplexTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { + public AbstractComplexTypeApplier(PdbApplicator applicator, AbstractComplexMsType msType) { super(applicator, msType); String fullPathName = msType.getName(); symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName)); } - public SymbolPath getSymbolPath() { + SymbolPath getSymbolPath() { return symbolPath; } - public boolean isForwardReference() { + boolean isForwardReference() { return ((AbstractComplexMsType) msType).getMsProperty().isForwardReference(); } - public boolean isFinal() { + boolean isFinal() { return ((AbstractComplexMsType) msType).getMsProperty().isSealed(); } - public void setFwdRefApplier(AbstractComplexTypeApplier fwdRefApplier) { - this.fwdRefApplier = fwdRefApplier; + void setForwardReferenceApplier(AbstractComplexTypeApplier forwardReferenceApplier) { + this.forwardReferenceApplier = forwardReferenceApplier; } - T getFwdRefApplier(Class typeClass) { - if (!typeClass.isInstance(fwdRefApplier)) { - return null; - } - return typeClass.cast(fwdRefApplier); - } - - public void setDefinitionApplier(AbstractComplexTypeApplier definitionApplier) { + void setDefinitionApplier(AbstractComplexTypeApplier definitionApplier) { this.definitionApplier = definitionApplier; } @@ -84,6 +78,13 @@ public abstract class AbstractComplexTypeApplier extends AbstractMsTypeApplier { return typeClass.cast(definitionApplier); } + protected AbstractComplexTypeApplier getAlternativeTypeApplier() { + if (isForwardReference()) { + return definitionApplier; + } + return forwardReferenceApplier; + } + protected SymbolPath getFixedSymbolPath() { //return mine or my def's (and set mine) if (fixedSymbolPath != null) { return fixedSymbolPath; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java index 25ffaa4ff1..009174ddb0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java @@ -25,26 +25,22 @@ import ghidra.util.exception.CancelledException; /** * Applier for certain function types. */ -public abstract class AbstractFunctionTypeApplier extends AbstractMsTypeApplier { - - private boolean isDeferred = false; +public abstract class AbstractFunctionTypeApplier extends MsTypeApplier { private FunctionDefinitionDataType functionDefinition; - private AbstractMsTypeApplier returnApplier; + private MsTypeApplier returnApplier; ArgumentsListTypeApplier argsListApplier; CallingConvention callingConvention; boolean hasThisPointer; /** * Constructor for the applicator that applies a "function" type, transforming it into a - * Ghidra DataType. + * Ghidra DataType. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractMsType} to processes - * @throws IllegalArgumentException Upon invalid arguments. */ - public AbstractFunctionTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { + public AbstractFunctionTypeApplier(PdbApplicator applicator, AbstractMsType msType) { super(applicator, msType); String funcName = applicator.getNextAnonymousFunctionName(); functionDefinition = new FunctionDefinitionDataType( @@ -56,15 +52,6 @@ public abstract class AbstractFunctionTypeApplier extends AbstractMsTypeApplier } //============================================================================================== - public void setDeferred() { - isDeferred = true; - } - - @Override - public boolean isDeferred() { - return isDeferred; - } - @Override void deferredApply() throws PdbException, CancelledException { if (isDeferred()) { @@ -77,7 +64,7 @@ public abstract class AbstractFunctionTypeApplier extends AbstractMsTypeApplier * Returns the function definition being created by this applier. * @return the function definition. */ - public FunctionDefinitionDataType getFunctionDefinition() { + FunctionDefinitionDataType getFunctionDefinition() { return functionDefinition; } @@ -89,31 +76,55 @@ public abstract class AbstractFunctionTypeApplier extends AbstractMsTypeApplier return functionDefinition; } - AbstractMsTypeApplier getReturnTypeApplier() { + /** + * Returns the type applier of the return type + * @return the type applier + */ + MsTypeApplier getReturnTypeApplier() { return applicator.getTypeApplier(getReturnRecordNumber()); } + /** + * Returns the {@link ArgumentsListTypeApplier} + * @return the type applier + */ ArgumentsListTypeApplier getArgsListApplier() { - AbstractMsTypeApplier argsApplier = applicator.getTypeApplier(getArgListRecordNumber()); + MsTypeApplier argsApplier = applicator.getTypeApplier(getArgListRecordNumber()); if (argsApplier instanceof ArgumentsListTypeApplier) { return (ArgumentsListTypeApplier) applicator.getTypeApplier(getArgListRecordNumber()); } return null; } + /** + * Returns the {@link CallingConvention} + * @return the calling convention + */ protected abstract CallingConvention getCallingConvention(); - protected abstract boolean hasThisPointer() throws CancelledException, PdbException; + /** + * Returns whether the function has a "this" pointer + * @return {@code true} if it has a "this" pointer + */ + protected abstract boolean hasThisPointer(); + /** + * Returns the {@link RecordNumber} of the function return type + * @return the record number + */ protected abstract RecordNumber getReturnRecordNumber(); + /** + * Returns the {@link RecordNumber} of the function arguments list + * @return the record number + */ protected abstract RecordNumber getArgListRecordNumber(); /** * Method to create the {@link DataType} based upon the type indices of the calling - * convention, return type, and arguments list. + * convention, return type, and arguments list. * @param callingConventionParam Identification of the {@link AbstractMsType} record of the - * {@link CallingConvention}. + * {@link CallingConvention}. * @param hasThisPointerParam true if has a this pointer * @return {@link DataType} created or null upon issue. * @throws PdbException when unexpected function internals are found. @@ -169,7 +180,7 @@ public abstract class AbstractFunctionTypeApplier extends AbstractMsTypeApplier } } - public void applyInternal() throws CancelledException { + private void applyInternal() throws CancelledException { if (isApplied()) { return; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java index 6286837ca6..872512e445 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArgumentsListTypeApplier.java @@ -22,26 +22,13 @@ import java.util.List; 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.AbstractArgumentsListMsType; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.program.model.data.*; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractArgumentsListMsType} types. */ -public class ArgumentsListTypeApplier extends AbstractMsTypeApplier { - - private boolean isDeferred = false; - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractArgumentsListMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - ArgumentsListTypeApplier.class.getSimpleName()); - } - return type; - } +public class ArgumentsListTypeApplier extends MsTypeApplier { /** * Constructor for the applicator that applies a arguments list. @@ -49,21 +36,12 @@ public class ArgumentsListTypeApplier extends AbstractMsTypeApplier { * @param msType {@link AbstractArgumentsListMsType} to processes. * @throws IllegalArgumentException Upon invalid arguments. */ - public ArgumentsListTypeApplier(PdbApplicator applicator, AbstractMsType msType) + public ArgumentsListTypeApplier(PdbApplicator applicator, AbstractArgumentsListMsType msType) throws IllegalArgumentException { - super(applicator, validateType(msType)); + super(applicator, msType); } //============================================================================================== - public void setDeferred() { - isDeferred = true; - } - - @Override - public boolean isDeferred() { - return isDeferred; - } - @Override void deferredApply() throws PdbException, CancelledException { // Do nothing... Just need dependency tie of each argument to function. @@ -72,13 +50,13 @@ public class ArgumentsListTypeApplier extends AbstractMsTypeApplier { //============================================================================================== // TODO: would be nice if we did not have to implement this method. Want the applyTo() below. @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { // addMyDependenciesOnly(); // // Silently do nothing. } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @@ -104,13 +82,13 @@ public class ArgumentsListTypeApplier extends AbstractMsTypeApplier { // } // } // - public void checkForDependencies(AbstractFunctionTypeApplier functionApplier) + void checkForDependencies(AbstractFunctionTypeApplier functionApplier) throws CancelledException { AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType; List args = argsList.getArgRecordNumbers(); for (RecordNumber arg : args) { applicator.checkCanceled(); - AbstractMsTypeApplier argApplier = applicator.getTypeApplier(arg); + MsTypeApplier argApplier = applicator.getTypeApplier(arg); if (argApplier instanceof PrimitiveTypeApplier && ((PrimitiveTypeApplier) argApplier).isNoType()) { @@ -137,7 +115,7 @@ public class ArgumentsListTypeApplier extends AbstractMsTypeApplier { * arguments. * @throws CancelledException Upon user cancellation */ - public void applyTo(AbstractFunctionTypeApplier functionApplier) throws CancelledException { + void applyTo(AbstractFunctionTypeApplier functionApplier) throws CancelledException { FunctionDefinitionDataType functionDefinition = functionApplier.getFunctionDefinition(); AbstractArgumentsListMsType argsList = (AbstractArgumentsListMsType) msType; @@ -146,7 +124,7 @@ public class ArgumentsListTypeApplier extends AbstractMsTypeApplier { int parameterCount = 0; for (RecordNumber arg : args) { applicator.checkCanceled(); - AbstractMsTypeApplier argApplier = applicator.getTypeApplier(arg); + MsTypeApplier argApplier = applicator.getTypeApplier(arg); if (argApplier instanceof PrimitiveTypeApplier && ((PrimitiveTypeApplier) argApplier).isNoType()) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java index 9755a28393..3cc18f327f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ArrayTypeApplier.java @@ -19,7 +19,6 @@ import java.math.BigInteger; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractArrayMsType; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.program.model.data.*; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; @@ -27,45 +26,23 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractArrayMsType} types. */ -public class ArrayTypeApplier extends AbstractMsTypeApplier { +public class ArrayTypeApplier extends MsTypeApplier { - private boolean isDeferred = false; - - private AbstractMsTypeApplier underlyingTypeApplier = null; + private MsTypeApplier underlyingTypeApplier = null; private boolean isFlexibleArray = false; - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractArrayMsType)) { - throw new IllegalArgumentException("PDB Incorrectly applying " + - type.getClass().getSimpleName() + " to " + ArrayTypeApplier.class.getSimpleName()); - } - return type; - } - /** * Constructor for the applicator that applies a "array" type, transforming it into a - * Ghidra DataType. + * Ghidra DataType. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractArrayMsType} to processes. - * @throws IllegalArgumentException Upon invalid arguments. */ - public ArrayTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); + public ArrayTypeApplier(PdbApplicator applicator, AbstractArrayMsType msType) { + super(applicator, msType); } //============================================================================================== - public void setDeferred() { - isDeferred = true; - } - - @Override - public boolean isDeferred() { - return isDeferred; - } - - public boolean isFlexibleArray() { + boolean isFlexibleArray() { return isFlexibleArray; } @@ -76,12 +53,12 @@ public class ArrayTypeApplier extends AbstractMsTypeApplier { //============================================================================================== @Override - public BigInteger getSize() { + BigInteger getSize() { return ((AbstractArrayMsType) msType).getSize(); } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { applyOrDeferForDependencies(); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java index 236a1e48b1..b73f72eeae 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java @@ -24,9 +24,9 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, and - * {@link AbstractIndirectVirtualBaseClassMsType} types. + * {@link AbstractIndirectVirtualBaseClassMsType} types. */ -public class BaseClassTypeApplier extends AbstractMsTypeApplier { +public class BaseClassTypeApplier extends MsTypeApplier { private static AbstractMsType validateType(AbstractMsType type) throws IllegalArgumentException { @@ -57,7 +57,7 @@ public class BaseClassTypeApplier extends AbstractMsTypeApplier { // For here, we are only reporting what "we" have, not what the underlying sizes are. // ...and a value of zero is our "don't know" and "not represented" value. @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @@ -66,7 +66,7 @@ public class BaseClassTypeApplier extends AbstractMsTypeApplier { * @return the offset. * @throws PdbException if field is not available. */ - public BigInteger getOffset() throws PdbException { + BigInteger getOffset() throws PdbException { if (msType instanceof AbstractBaseClassMsType) { return ((AbstractBaseClassMsType) msType).getOffset(); } @@ -78,7 +78,7 @@ public class BaseClassTypeApplier extends AbstractMsTypeApplier { * @return the offset. * @throws PdbException if field is not available. */ - public BigInteger getBasePointerOffset() throws PdbException { + BigInteger getBasePointerOffset() throws PdbException { if (msType instanceof AbstractBaseClassMsType) { throw new PdbException("Base Pointer Offset is not valid field"); } @@ -92,7 +92,7 @@ public class BaseClassTypeApplier extends AbstractMsTypeApplier { * Returns the attributes of the base class within the inheriting class. * @return the attributes; */ - public ClassFieldMsAttributes getAttributes() { + ClassFieldMsAttributes getAttributes() { if (msType instanceof AbstractBaseClassMsType) { return ((AbstractBaseClassMsType) msType).getAttributes(); } @@ -106,7 +106,7 @@ public class BaseClassTypeApplier extends AbstractMsTypeApplier { * Returns the record number of the base class. * @return the record number; */ - public RecordNumber getBaseClassRecordNumber() { + RecordNumber getBaseClassRecordNumber() { if (msType instanceof AbstractBaseClassMsType) { return ((AbstractBaseClassMsType) msType).getBaseClassRecordNumber(); } @@ -120,7 +120,7 @@ public class BaseClassTypeApplier extends AbstractMsTypeApplier { * Returns whether there is a Virtual Base Pointer type index available. * @return {@code true} if available. */ - public boolean hasVirtualBasePointerTypeIndex() { + boolean hasVirtualBasePointerTypeIndex() { return (!(msType instanceof AbstractBaseClassMsType)); } @@ -129,7 +129,7 @@ public class BaseClassTypeApplier extends AbstractMsTypeApplier { * @return the record number; * @throws PdbException if not a virtual base class. */ - public RecordNumber getVirtualBasePointerRecordNumber() throws PdbException { + RecordNumber getVirtualBasePointerRecordNumber() throws PdbException { if (msType instanceof AbstractVirtualBaseClassMsType) { return ((AbstractVirtualBaseClassMsType) msType).getVirtualBasePointerRecordNumber(); } @@ -140,7 +140,7 @@ public class BaseClassTypeApplier extends AbstractMsTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { // do nothing at the moment. } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java index 895257c2b4..adb08e2a52 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BitfieldTypeApplier.java @@ -20,7 +20,6 @@ import java.math.BigInteger; import ghidra.app.util.bin.format.pdb.PdbBitField; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractBitfieldMsType; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.program.model.data.DataType; import ghidra.program.model.data.InvalidDataTypeException; import ghidra.util.exception.CancelledException; @@ -28,32 +27,20 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractBitfieldMsType} types. */ -public class BitfieldTypeApplier extends AbstractMsTypeApplier { - private AbstractMsTypeApplier elementTypeApplier = null; - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractBitfieldMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - BitfieldTypeApplier.class.getSimpleName()); - } - return type; - } +public class BitfieldTypeApplier extends MsTypeApplier { + private MsTypeApplier elementTypeApplier = null; /** * Constructor for bitfield applier. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractBitfieldMsType} to processes - * @throws IllegalArgumentException Upon invalid arguments. */ - public BitfieldTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); + public BitfieldTypeApplier(PdbApplicator applicator, AbstractBitfieldMsType msType) { + super(applicator, msType); } @Override - public BigInteger getSize() { + BigInteger getSize() { if (elementTypeApplier == null) { return BigInteger.ZERO; } @@ -61,7 +48,7 @@ public class BitfieldTypeApplier extends AbstractMsTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { // The bitfield does not get resolved/commited to the DataTypeManager. dataType = applyBitfieldMsType((AbstractBitfieldMsType) msType); } @@ -94,7 +81,7 @@ public class BitfieldTypeApplier extends AbstractMsTypeApplier { } @Override - public void resolve() { + void resolve() { // Do not resolve Bitfield Types... will be resolved with composite!!! } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockCommentsManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockCommentsManager.java index e6a6f01aef..64eeab4bf0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockCommentsManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockCommentsManager.java @@ -23,6 +23,9 @@ import ghidra.program.model.address.Address; import ghidra.program.model.listing.CodeUnit; import ghidra.program.model.listing.Program; +/** + * Manages the nesting of scoping blocks for functions and scoped variables. + */ public class BlockCommentsManager { private static final String BLOCK_INDENT = " "; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java index 7ad4e8900b..949da49b52 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BlockSymbolApplier.java @@ -16,22 +16,25 @@ package ghidra.app.util.pdb.pdbapplicator; 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.symbol.AbstractBlockMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; -import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractBlockMsSymbol} symbols. */ -public class BlockSymbolApplier extends AbstractMsSymbolApplier { +public class BlockSymbolApplier extends MsSymbolApplier { private AbstractBlockMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public BlockSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -43,22 +46,21 @@ public class BlockSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void apply() throws PdbException, CancelledException { - String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; - Msg.info(this, message); - PdbLog.message(message); + void apply() throws PdbException, CancelledException { + pdbLogAndInfoMessage(this, + "Cannot apply " + this.getClass().getSimpleName() + " directly to program"); } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing } @Override - public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + void manageBlockNesting(MsSymbolApplier applierParam) { if (applierParam instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; - Address address = applicator.reladdr(symbol); + Address address = applicator.getAddress(symbol); functionSymbolApplier.beginBlock(address, symbol.getName(), symbol.getLength()); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java index bf28bbf429..ec7dd3262b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java @@ -24,7 +24,7 @@ import ghidra.util.task.TaskMonitor; /** * Two-way Maps forward references with corresponding definitions for composites and enums. - * Uses the fwdref and definition members of the AbstractComplexTypeApplier. + * Uses the forward reference and definition members of the AbstractComplexTypeApplier. */ // We have probably tried 5 or more ways of doing this, all with mixed results. The current // implementation seems to yield the best results at the moment. Keeping some of the old code @@ -57,7 +57,7 @@ public class ComplexTypeApplierMapper { while (indexNumber < indexLimit) { monitor.checkCanceled(); PdbResearch.checkBreak(indexNumber); - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber++)); // From real data, we know that an enum and a composite both had the same SymbolPath, // so enums and composites must be maintained separately so they do not get matched @@ -93,13 +93,14 @@ public class ComplexTypeApplierMapper { if (appliers == null) { appliers = new LinkedList<>(); applierQueueBySymbolPath.put(symbolPath, appliers); - // Putting fwdref or def (doesn't matter which it is) + // Putting forward reference or definition (doesn't matter which it is) if (!appliers.add(complexApplier)) { // Error } } else if (appliers.peekFirst().isForwardReference() == complexApplier.isForwardReference()) { - // Only need to look at first on list, as all on list are the same fwdref or def. + // Only need to look at first on list, as all on list are the same forward reference + // of definition. // If same as what is on list, add to the list. if (!appliers.add(complexApplier)) { // Error @@ -107,14 +108,14 @@ public class ComplexTypeApplierMapper { } else { if (complexApplier.isForwardReference()) { - AbstractComplexTypeApplier defApplier = appliers.removeFirst(); - defApplier.setFwdRefApplier(complexApplier); - complexApplier.setDefinitionApplier(defApplier); + AbstractComplexTypeApplier definitionApplier = appliers.removeFirst(); + definitionApplier.setForwardReferenceApplier(complexApplier); + complexApplier.setDefinitionApplier(definitionApplier); } else { - AbstractComplexTypeApplier fwdApplier = appliers.removeFirst(); - fwdApplier.setDefinitionApplier(complexApplier); - complexApplier.setFwdRefApplier(fwdApplier); + AbstractComplexTypeApplier forwardReferenceApplier = appliers.removeFirst(); + forwardReferenceApplier.setDefinitionApplier(complexApplier); + complexApplier.setForwardReferenceApplier(forwardReferenceApplier); } if (appliers.isEmpty()) { // Do not need to keep all of these around. @@ -164,7 +165,7 @@ public class ComplexTypeApplierMapper { // } // } // -// // Only caching forward ref and then mapping only following def to fwdref. +// // Only caching forward ref and then mapping only following def to forward reference. // // Clearing cache after that def so next def does not map. // private void mapComplexApplierForwardOnly(AbstractComplexTypeApplier complexApplier) { // SymbolPath symbolPath = complexApplier.getSymbolPath(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java index 13f15adbe1..cfef2c60f9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java @@ -18,6 +18,9 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.HashMap; import java.util.Map; +/** + * PDB Analyzer Options Mode for performing object-oriented structure layout. + */ public enum CompositeLayoutMode { MEMBERS_ONLY("Legacy", 0, OoComponentLayoutMode.MEMBERS_ONLY), BASIC_SIMPLE_COMPLEX("Complex with Basic Fallback", 1, OoComponentLayoutMode.BASIC), @@ -31,7 +34,7 @@ public enum CompositeLayoutMode { } } - public final String label; + private final String label; private final int value; private OoComponentLayoutMode layoutMode; @@ -46,7 +49,7 @@ public enum CompositeLayoutMode { this.layoutMode = layoutMode; } - public OoComponentLayoutMode getLayoutMode() { + OoComponentLayoutMode getLayoutMode() { return layoutMode; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java index 16acd28ffc..12278282a4 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java @@ -31,10 +31,11 @@ import ghidra.util.exception.CancelledException; /* * Non java-doc: * Some truths: - * For AbstractMsCompositeType: do not count on "count" to be zero when MsProperty is fwdref - * (we have seen example of count==0 and not fwdref, though the majority of the time the - * two go hand-in-hand. When these did not equate, it might have been when there was no - * need for a fwdref and possibly only one definition--this would require a closer look). + * For AbstractMsCompositeType: do not count on "count" to be zero when MsProperty is forward + * reference (we have seen example of count==0 and not forward reference, though the majority + * of the time the two go hand-in-hand. When these did not equate, it might have been when + * there was no need for a forward reference and possibly only one definition--this would + * require a closer look). */ /** * Applier for {@link AbstractCompositeMsType} types. @@ -53,33 +54,21 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { // private Map componentComments; - private List members; - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractCompositeMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - CompositeTypeApplier.class.getSimpleName()); - } - return type; - } + private List members; /** * Constructor for composite type applier, for transforming a composite into a - * Ghidra DataType. + * Ghidra DataType. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractCompositeMsType} to process. - * @throws IllegalArgumentException Upon invalid arguments. */ - public CompositeTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); - String fullPathName = ((AbstractCompositeMsType) msType).getName(); + public CompositeTypeApplier(PdbApplicator applicator, AbstractCompositeMsType msType) { + super(applicator, msType); + String fullPathName = msType.getName(); symbolPath = new SymbolPath(SymbolPathParser.parse(fullPathName)); } - public CppCompositeType getClassType() { + CppCompositeType getClassType() { if (definitionApplier != null) { return ((CompositeTypeApplier) definitionApplier).getClassTypeInternal(); } @@ -90,33 +79,25 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return classType; } - List getMembers() { + List getMembers() { return members; } - // Mapping of fwdRef/def must be done prior to this call. + // Mapping of forwardReference/definition must be done prior to this call. private void getOrCreateComposite() { if (dataType != null) { return; } - if (isForwardReference()) { - if (definitionApplier != null) { - dataType = definitionApplier.getDataTypeInternal(); - classType = ((CompositeTypeApplier) definitionApplier).getClassTypeInternal(); - if (dataType != null) { - return; - } - } + + AbstractComplexTypeApplier alternativeApplier = getAlternativeTypeApplier(); + if (alternativeApplier != null) { + dataType = alternativeApplier.getDataTypeInternal(); + classType = ((CompositeTypeApplier) alternativeApplier).getClassTypeInternal(); } - else { - if (fwdRefApplier != null) { - dataType = fwdRefApplier.getDataTypeInternal(); - classType = ((CompositeTypeApplier) fwdRefApplier).getClassTypeInternal(); - if (dataType != null) { - return; - } - } + if (dataType != null) { + return; } + dataType = createEmptyComposite((AbstractCompositeMsType) msType); String mangledName = ((AbstractCompositeMsType) msType).getMangledName(); classType = new CppCompositeType((Composite) dataType, mangledName); @@ -136,7 +117,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { getOrCreateComposite(); @@ -154,7 +135,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } @Override - public void resolve() { + void resolve() { if (!isForwardReference()) { super.resolve(); } @@ -176,10 +157,10 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { // Currently do not need this dependency, as we currently do not need any contents // of the base class for filling in this class - for (AbstractMsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) { + for (MsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) { if (baseApplierIterated instanceof BaseClassTypeApplier) { BaseClassTypeApplier baseTypeApplier = (BaseClassTypeApplier) baseApplierIterated; - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getTypeApplier(baseTypeApplier.getBaseClassRecordNumber()); if (applier instanceof CompositeTypeApplier) { CompositeTypeApplier dependencyApplier = @@ -197,11 +178,11 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } } } - for (AbstractMsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) { + for (MsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) { applicator.checkCanceled(); if (memberTypeApplierIterated instanceof MemberTypeApplier) { MemberTypeApplier memberTypeApplier = (MemberTypeApplier) memberTypeApplierIterated; - AbstractMsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier(); + MsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier(); recurseAddDependency(fieldApplier); } // if (memberTypeApplierIterated instanceof NestedTypeApplier) { @@ -216,8 +197,10 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } } - private void recurseAddDependency(AbstractMsTypeApplier dependee) + private void recurseAddDependency(MsTypeApplier dependee) throws CancelledException, PdbException { + // TODO: evaluate this and make changes... this work might be being taken care of in + // ModifierTypeApplier if (dependee instanceof ModifierTypeApplier) { ModifierTypeApplier modifierApplier = (ModifierTypeApplier) dependee; recurseAddDependency(modifierApplier.getModifiedTypeApplier()); @@ -233,6 +216,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } setDeferred(); } + // TODO: evaluate this and make changes... this work might be being taken care of in + // ArrayTypeApplier else if (dependee instanceof ArrayTypeApplier) { applicator.addApplierDependency(this, dependee); setDeferred(); @@ -251,7 +236,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { else if (dependee instanceof BitfieldTypeApplier) { RecordNumber recNum = ((AbstractBitfieldMsType) ((BitfieldTypeApplier) dependee).getMsType()).getElementRecordNumber(); - AbstractMsTypeApplier underlyingApplier = applicator.getTypeApplier(recNum); + MsTypeApplier underlyingApplier = applicator.getTypeApplier(recNum); if (underlyingApplier instanceof EnumTypeApplier) { applicator.addApplierDependency(this, underlyingApplier); setDeferred(); @@ -260,7 +245,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { //We are assuming that bitfields on typedefs will not be defined. } - public void applyInternal() throws CancelledException, PdbException { + private void applyInternal() throws CancelledException, PdbException { if (isApplied()) { return; @@ -273,9 +258,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { if (type instanceof AbstractUnionMsType) { applyCpp = false; if (hasBaseClasses()) { - String msg = "Unexpected base classes for union type: " + type.getName(); - PdbLog.message(msg); - Msg.info(this, msg); + pdbLogAndInfoMessage(this, + "Unexpected base classes for union type: " + type.getName()); } } if (applyCpp) { @@ -288,7 +272,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } //============================================================================================== - void applyBasic(Composite composite, AbstractCompositeMsType type) + private void applyBasic(Composite composite, AbstractCompositeMsType type) throws CancelledException, PdbException { //boolean isClass = (type instanceof AbstractClassMsType || actsLikeClass(applicator, type)); @@ -320,10 +304,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { for (Map.Entry entry : componentComments.entrySet()) { DataTypeComponent component = structure.getComponentAt(entry.getKey()); if (component == null) { - String message = "Could not set comment for 'missing' componenent " + - entry.getKey() + " for: " + structure.getName(); - PdbLog.message(message); - Msg.info(this, message); + pdbLogAndInfoMessage(this, "Could not set comment for 'missing' componenent " + + entry.getKey() + " for: " + structure.getName()); return; } component.setComment(entry.getValue()); @@ -332,7 +314,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } //============================================================================================== - void applyCpp(Composite composite, AbstractCompositeMsType type) + private void applyCpp(Composite composite, AbstractCompositeMsType type) throws PdbException, CancelledException { // Fill in composite definition details. FieldListTypeApplier fieldListApplier = FieldListTypeApplier.getFieldListApplierSpecial( @@ -362,15 +344,6 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } //============================================================================================== - public void setDeferred() { - isDeferred = true; - } - - @Override - public boolean isDeferred() { - return isDeferred; - } - @Override void deferredApply() throws PdbException, CancelledException { if (isDeferred()) { @@ -381,19 +354,19 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { //============================================================================================== //============================================================================================== @Override - public CompositeTypeApplier getDependencyApplier() { + CompositeTypeApplier getDependencyApplier() { if (definitionApplier != null && definitionApplier instanceof CompositeTypeApplier) { return (CompositeTypeApplier) definitionApplier; } return this; } - public String getName() { + String getName() { return getMsType().getName(); } @Override - public DataType getDataType() { + DataType getDataType() { if (resolved) { return resolvedDataType; } @@ -409,12 +382,12 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return dataType; } - public boolean hasUniqueName() { + boolean hasUniqueName() { return ((AbstractCompositeMsType) msType).getMsProperty().hasUniqueName(); } @Override - public BigInteger getSize() { + BigInteger getSize() { return ((AbstractCompositeMsType) getDependencyApplier().getMsType()).getSize(); } @@ -472,7 +445,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { else { defType = (AbstractCompositeMsType) definitionApplier.getMsType(); } - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getTypeApplier(defType.getFieldDescriptorListRecordNumber()); if (!(applier instanceof FieldListTypeApplier)) { return false; @@ -504,7 +477,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { // So... it might not be good to return "true" for just checking if the type is an // instanceof AbstractClassMsType. - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getTypeApplier(defType.getFieldDescriptorListRecordNumber()); if (!(applier instanceof FieldListTypeApplier)) { return false; @@ -522,14 +495,14 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { AbstractCompositeMsType type = (AbstractCompositeMsType) msType; - for (AbstractMsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) { + for (MsTypeApplier baseApplierIterated : fieldListApplier.getBaseClassList()) { if (!(baseApplierIterated instanceof BaseClassTypeApplier)) { applicator.appendLogMsg(baseApplierIterated.getClass().getSimpleName() + " seen where BaseClassTypeApplier expected for " + type.getName()); continue; } BaseClassTypeApplier baseTypeApplier = (BaseClassTypeApplier) baseApplierIterated; - AbstractMsTypeApplier baseClassTypeApplier = + MsTypeApplier baseClassTypeApplier = applicator.getTypeApplier(baseTypeApplier.getBaseClassRecordNumber()); if (!(baseClassTypeApplier instanceof CompositeTypeApplier)) { applicator.appendLogMsg(baseApplierIterated.getClass().getSimpleName() + @@ -599,7 +572,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } private CppCompositeType getUnderlyingClassType(RecordNumber recordNumber) { - AbstractMsTypeApplier baseUnderlyingApplier = applicator.getTypeApplier(recordNumber); + MsTypeApplier baseUnderlyingApplier = applicator.getTypeApplier(recordNumber); if (!(baseUnderlyingApplier instanceof CompositeTypeApplier)) { applicator.appendLogMsg(baseUnderlyingApplier.getClass().getSimpleName() + " seen where CompositeTypeApplier expected for base class."); @@ -614,7 +587,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } private DataType getVirtualBaseTablePointerDataType(RecordNumber recordNumber) { - AbstractMsTypeApplier vbptrApplier = applicator.getTypeApplier(recordNumber); + MsTypeApplier vbptrApplier = applicator.getTypeApplier(recordNumber); if (vbptrApplier != null) { if (vbptrApplier instanceof PointerTypeApplier) { return vbptrApplier.getDataType(); @@ -663,7 +636,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { AbstractCompositeMsType type = (AbstractCompositeMsType) msType; - for (AbstractMsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) { + for (MsTypeApplier memberTypeApplierIterated : fieldListApplier.getMemberList()) { boolean handled = true; if (memberTypeApplierIterated instanceof MemberTypeApplier) { MemberTypeApplier memberTypeApplier = (MemberTypeApplier) memberTypeApplierIterated; @@ -673,7 +646,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { PdbApplicator.bigIntegerToInt(applicator, memberTypeApplier.getOffset()); ClassFieldMsAttributes memberAttributes = memberTypeApplier.getAttribute(); memberAttributes.getAccess(); // TODO: do something with this and other attributes - AbstractMsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier(); + MsTypeApplier fieldApplier = memberTypeApplier.getFieldTypeApplier(); if (fieldApplier instanceof CompositeTypeApplier) { CompositeTypeApplier defApplier = @@ -694,8 +667,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { if (fieldDataType == null) { if (fieldApplier instanceof PrimitiveTypeApplier && ((PrimitiveTypeApplier) fieldApplier).isNoType()) { - Default2PdbMember member = - new Default2PdbMember(applicator, memberName, fieldApplier, offset); + DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(applicator, + memberName, fieldApplier, offset); members.add(member); componentComments.put(offset, "NO_TYPE"); } @@ -706,8 +679,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } } else { - Default2PdbMember member = - new Default2PdbMember(applicator, memberName, fieldApplier, offset); + DefaultPdbUniversalMember member = + new DefaultPdbUniversalMember(applicator, memberName, fieldApplier, offset); members.add(member); classType.addMember(memberName, fieldDataType, isFlexibleArray, convertAttributes(memberAttributes), offset); @@ -719,16 +692,17 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { String fieldName = enumerateTypeApplier.getName(); Numeric numeric = enumerateTypeApplier.getNumeric(); // TODO: some work - PdbLog.message("Don't know how to apply EnumerateTypeApplier fieldName " + - fieldName + " and value " + numeric + " within " + msType.getName()); + pdbLogAndInfoMessage(this, + "Don't know how to apply EnumerateTypeApplier fieldName " + fieldName + + " and value " + numeric + " within " + msType.getName()); } else if (memberTypeApplierIterated instanceof VirtualFunctionTablePointerTypeApplier) { VirtualFunctionTablePointerTypeApplier vtPtrApplier = (VirtualFunctionTablePointerTypeApplier) memberTypeApplierIterated; String vftPtrMemberName = vtPtrApplier.getMemberName(); int offset = vtPtrApplier.getOffset(); - Default2PdbMember member = - new Default2PdbMember(applicator, vftPtrMemberName, vtPtrApplier, offset); + DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(applicator, + vftPtrMemberName, vtPtrApplier, offset); members.add(member); //classType.addMember(vftPtrMemberName, vtPtrApplier.getDataType(), false, offset); classType.addVirtualFunctionTablePointer(vftPtrMemberName, @@ -754,8 +728,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { // We are skipping because we've had issues and do not know what is going on // at the moment. (I think they were dependency issues... been a while.) // See not above the "if" condition. -// PdbLog.message("Skipping Composite Nested type member: " + memberName + -// " within " + type.getName()); +// pdbLogAndInfoMessage(this, "Skipping Composite Nested type member: " + +// memberName + " within " + type.getName()); // TODO: Investigate. What does it mean when the internally defined type // conficts with the name of the outer type. continue; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java index e3d286a6db..dab32bcbfa 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java @@ -31,7 +31,8 @@ import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; /** - * Notional C++ Class Type. + * Notional C++ Class Type. Much work has yet to be done with this class. For instance, the plan + * is to continue to break this class up into smaller self-contained classes. */ public class CppCompositeType { @@ -305,7 +306,7 @@ public class CppCompositeType { //============================================================================================== /* - * These "insert" methods should be used judiciously. You need to know what/why you are doing + * These "insert" methods should be used judiciously. You need to know what/why you are doing * this. Changing the order of "normal" members can mess up the layout algorithms from * {@link DefaultCompositeMember}. The only place we currently think we can use these is * when trying to place vbptr members. Not all of these methods are used too. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java index 11523eb3ee..c97e17e8b6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -24,16 +24,23 @@ import ghidra.program.model.address.Address; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; import ghidra.program.model.mem.DumbMemBufferImpl; +import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractDataMsSymbol} symbols. */ -public class DataSymbolApplier extends AbstractMsSymbolApplier { +public class DataSymbolApplier extends MsSymbolApplier { private AbstractDataMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + * @throws CancelledException upon user cancellation + */ public DataSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -45,47 +52,46 @@ public class DataSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) - throws PdbException, CancelledException { + void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException { if (applyToApplier instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; if (symbol.getSegment() == 0 && symbol.getOffset() == 0L) { return; // silently return. } - AbstractMsTypeApplier applier = getTypeApplier(); + MsTypeApplier applier = getTypeApplier(); DataType dataType = applier.getDataType(); if (dataType == null) { // TODO: check that we can have null here. return; // silently return. } String name = symbol.getName(); - Address address = applicator.reladdr(symbol); + Address address = applicator.getAddress(symbol); functionSymbolApplier.setLocalVariable(address, name, dataType); } } @Override - public void apply() throws CancelledException, PdbException { + void apply() throws CancelledException, PdbException { // skip if both zero (i.e,. process if either is not zero) if (symbol.getSegment() != 0 || symbol.getOffset() != 0L) { - Address symbolAddress = applicator.reladdr(symbol); + Address symbolAddress = applicator.getAddress(symbol); Address remapAddress = applicator.getRemapAddressByAddress(symbolAddress); RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); - boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, true); + boolean forcePrimary = applicator.shouldForcePrimarySymbol(remapAddress, true); String name = symbol.getName(); - if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { - applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); + if (!applicator.createSymbol(remapAddress, name, forcePrimary)) { + applicator.appendLogMsg("Unable to create symbol " + name + " at " + remapAddress); } - createData(symbolAddress, typeRecordNumber); + createData(remapAddress, typeRecordNumber); } } - AbstractMsTypeApplier getTypeApplier() { + MsTypeApplier getTypeApplier() { return applicator.getTypeApplier(symbol.getTypeRecordNumber()); } void createData(Address address, RecordNumber typeRecordNumber) { - AbstractMsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); + MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); if (applier == null) { applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " + typeRecordNumber + " at " + address); @@ -168,7 +174,7 @@ public class DataSymbolApplier extends AbstractMsSymbolApplier { applicator.getProgram().getListing().createData(address, dataType); } } - catch (Exception e) { + catch (CodeUnitInsertionException | DataTypeConflictException e) { applicator.appendLogMsg("Unable to create " + dataType.getDisplayName() + " at 0x" + address + ": " + e.getMessage()); } @@ -179,7 +185,7 @@ public class DataSymbolApplier extends AbstractMsSymbolApplier { address.add(dataTypeLength - 1), false); applicator.getProgram().getListing().createData(address, dataType, dataTypeLength); } - catch (Exception e) { + catch (CodeUnitInsertionException | DataTypeConflictException e) { applicator.appendLogMsg("Unable to replace " + dataType.getDisplayName() + " at 0x" + address + ": " + e.getMessage()); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/Default2PdbMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java similarity index 90% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/Default2PdbMember.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java index 2172b51983..dd77d873db 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/Default2PdbMember.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java @@ -25,9 +25,9 @@ import ghidra.util.exception.CancelledException; * PdbMember convey PDB member information used for datatype * reconstruction. */ -public class Default2PdbMember extends PdbMember { +public class DefaultPdbUniversalMember extends PdbMember { - private AbstractMsTypeApplier applier; + private MsTypeApplier applier; private DataType dataType; /** @@ -36,10 +36,10 @@ public class Default2PdbMember extends PdbMember { * @param name member field name. For bitfields this also conveys the bit-size * and optionally the bit-offset. * @param applier fieldApplier for the field datatype or base datatype associated with the - * bitfield. + * bitfield. * @param offset member's byte offset within the root composite. */ - Default2PdbMember(PdbApplicator applicator, String name, AbstractMsTypeApplier applier, + DefaultPdbUniversalMember(PdbApplicator applicator, String name, MsTypeApplier applier, int offset) { super(name, (applier.getDataType()).getName(), offset, null); this.applier = applier; @@ -54,13 +54,14 @@ public class Default2PdbMember extends PdbMember { * @param dataType for the field. * @param offset member's byte offset within the root composite. */ - Default2PdbMember(PdbApplicator applicator, String name, DataType dataType, int offset) { + DefaultPdbUniversalMember(PdbApplicator applicator, String name, DataType dataType, + int offset) { super(name, dataType.getName(), offset, null); this.applier = null; this.dataType = dataType; } - AbstractMsTypeApplier getApplier() { + MsTypeApplier getApplier() { return applier; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java index 981f05fdc8..8fa9ee6e66 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefinedSingleAddressRangeSymbolApplier.java @@ -16,20 +16,23 @@ package ghidra.app.util.pdb.pdbapplicator; 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.symbol.*; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; -import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractDefinedSingleAddressRangeMsSymbol} symbols. */ -public class DefinedSingleAddressRangeSymbolApplier extends AbstractMsSymbolApplier { +public class DefinedSingleAddressRangeSymbolApplier extends MsSymbolApplier { private AbstractDefinedSingleAddressRangeMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public DefinedSingleAddressRangeSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); @@ -42,15 +45,13 @@ public class DefinedSingleAddressRangeSymbolApplier extends AbstractMsSymbolAppl } @Override - public void apply() throws PdbException, CancelledException { - String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; - Msg.info(this, message); - PdbLog.message(message); + void apply() throws PdbException, CancelledException { + pdbLogAndInfoMessage(this, + "Cannot apply " + this.getClass().getSimpleName() + " directly to program"); } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) - throws PdbException, CancelledException { + void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException { if (applyToApplier instanceof LocalOptimizedSymbolApplier) { // TODO: eventually apply. // LocalOptimizedSymbolApplier localSymbolApplier = diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java index 52516ff904..c83ff267e2 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EndSymbolApplier.java @@ -16,18 +16,23 @@ package ghidra.app.util.pdb.pdbapplicator; 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.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.EndMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; -import ghidra.util.Msg; import ghidra.util.exception.AssertException; +import ghidra.util.exception.CancelledException; /** * Applier for {@link EndMsSymbol} symbols. */ -public class EndSymbolApplier extends AbstractMsSymbolApplier { +public class EndSymbolApplier extends MsSymbolApplier { + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + * @throws CancelledException upon user cancellation + */ public EndSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -38,25 +43,23 @@ public class EndSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void apply() throws PdbException { - String message = + void apply() throws PdbException { + pdbLogAndInfoMessage(this, String.format("Cannot apply %s directly to program (module:0X%04X, offset:0X%08X)", - this.getClass().getSimpleName(), iter.getModuleNumber(), iter.getCurrentOffset()); - Msg.info(this, message); - PdbLog.message(message); + this.getClass().getSimpleName(), iter.getModuleNumber(), iter.getCurrentOffset())); } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { if (!(applyToApplier instanceof FunctionSymbolApplier)) { return; } - FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; +// FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; // functionSymbolApplier.endBlock(); } @Override - public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + void manageBlockNesting(MsSymbolApplier applierParam) { if (applierParam instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; functionSymbolApplier.endBlock(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java index 15702ff5b1..fff603768f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumTypeApplier.java @@ -20,7 +20,8 @@ import java.util.List; import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb2.pdbreader.*; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractEnumMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.MsProperty; import ghidra.program.model.data.*; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; @@ -35,30 +36,20 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { // private int length = 0; // private boolean isSigned = false; // - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractEnumMsType)) { - throw new IllegalArgumentException("PDB Incorrectly applying " + - type.getClass().getSimpleName() + " to " + EnumTypeApplier.class.getSimpleName()); - } - return type; - } /** * Constructor for enum type applier, for transforming a enum into a - * Ghidra DataType. + * Ghidra DataType. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractEnumMsType} to process. - * @throws IllegalArgumentException Upon invalid arguments. */ - public EnumTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); + public EnumTypeApplier(PdbApplicator applicator, AbstractEnumMsType msType) { + super(applicator, msType); } @Override - public BigInteger getSize() { - AbstractMsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); + BigInteger getSize() { + MsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); if (underlyingApplier == null) { return BigInteger.ZERO; } @@ -80,7 +71,7 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { private int getLength() { // Minimum length allowed by Ghidra is 1 for enum, so all returns are min 1. - AbstractMsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); + MsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); if (underlyingApplier == null) { return 1; } @@ -91,8 +82,8 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { return Integer.max(underlyingType.getLength(), 1); } - public boolean isSigned() { - AbstractMsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); + boolean isSigned() { + MsTypeApplier underlyingApplier = getUnderlyingTypeApplier(); if (underlyingApplier == null) { return false; } @@ -107,20 +98,20 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { } @Override - public EnumTypeApplier getDependencyApplier() { + EnumTypeApplier getDependencyApplier() { if (definitionApplier != null && definitionApplier instanceof EnumTypeApplier) { return (EnumTypeApplier) definitionApplier; } return this; } - public String getName() { + String getName() { return getMsType().getName(); } - private AbstractMsTypeApplier getUnderlyingTypeApplier() { - AbstractMsTypeApplier under = null; - AbstractMsTypeApplier applier = (definitionApplier != null) ? definitionApplier : this; + private MsTypeApplier getUnderlyingTypeApplier() { + MsTypeApplier under = null; + MsTypeApplier applier = (definitionApplier != null) ? definitionApplier : this; RecordNumber underlyingRecordNumber = ((AbstractEnumMsType) applier.getMsType()).getUnderlyingRecordNumber(); under = applicator.getTypeApplier(underlyingRecordNumber); @@ -131,7 +122,7 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { return under; } - private EnumDataType createEmptyEnum(AbstractEnumMsType type) throws PdbException { + private EnumDataType createEmptyEnum(AbstractEnumMsType type) { SymbolPath fixedPath = getFixedSymbolPath(); CategoryPath categoryPath = applicator.getCategory(fixedPath.getParent()); @@ -155,10 +146,8 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { // isSigned = ((AbstractIntegerDataType) underlyingType).isSigned(); // } // else if (!(underlyingType instanceof VoidDataType)) { -// String msg = "Cannot processes enum with underlying type: " + -// underlyingType.getClass().getSimpleName(); -// Msg.info(this, msg); -// PdbLog.message(msg); +// pdbLogAndInfoMessage(this, "Cannot processes enum with underlying type: " + +// underlyingType.getClass().getSimpleName()); // throw new PdbException(msg); // } // } @@ -182,7 +171,7 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { getOrCreateEnum(); AbstractEnumMsType type = (AbstractEnumMsType) msType; @@ -196,14 +185,14 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { } @Override - public void resolve() { + void resolve() { if (!isForwardReference()) { super.resolve(); } } // Mapping of fwdRef/def must be done prior to this call. - private void getOrCreateEnum() throws PdbException { + private void getOrCreateEnum() { AbstractEnumMsType neededType = (AbstractEnumMsType) msType; if (dataType != null) { return; @@ -218,8 +207,8 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { } } else { - if (fwdRefApplier != null) { - dataType = fwdRefApplier.getDataTypeInternal(); + if (forwardReferenceApplier != null) { + dataType = forwardReferenceApplier.getDataTypeInternal(); if (dataType != null) { return; } @@ -275,19 +264,17 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { FieldListTypeApplier.getFieldListApplierSpecial(applicator, fieldListRecordNumber); // Note: not doing anything with getNamespaceList() or getMethodsList() at this time. - List memberList = fieldListApplier.getMemberList(); + List memberList = fieldListApplier.getMemberList(); int numElements = type.getNumElements(); if (memberList.size() != numElements) { - String message = "Enum expecting " + numElements + " elements, but only " + - memberList.size() + " available for " + fullPathName; - Msg.info(this, message); - PdbLog.message(message); + pdbLogAndInfoMessage(this, "Enum expecting " + numElements + " elements, but only " + + memberList.size() + " available for " + fullPathName); } EnumDataType enumDataType = (EnumDataType) dataType; int length = getLength(); boolean isSigned = isSigned(); - for (AbstractMsTypeApplier memberApplier : memberList) { + for (MsTypeApplier memberApplier : memberList) { if (memberApplier instanceof EnumerateTypeApplier) { EnumerateTypeApplier enumerateApplier = (EnumerateTypeApplier) memberApplier; SymbolPath memberSymbolPath = new SymbolPath(enumerateApplier.getName()); @@ -297,7 +284,7 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { else { // (member instanceof AbstractMemberMsType) // I do not believe (until proven otherwise) that an Enum will have members of // type AbstractMemberMsType. - PdbLog.message(getClass().getSimpleName() + ": unexpected " + + pdbLogAndInfoMessage(this, getClass().getSimpleName() + ": unexpected " + memberApplier.getClass().getSimpleName()); } } @@ -310,7 +297,7 @@ public class EnumTypeApplier extends AbstractComplexTypeApplier { return 0; } if (!numeric.isIntegral()) { - PdbLog.message("Using zero in place of non-integral enumerate: " + numeric); + pdbLogAndInfoMessage(this, "Using zero in place of non-integral enumerate: " + numeric); return 0L; // } return numeric.getIntegral().longValue() & getMask(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java index a6889993da..d104c45c0a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/EnumerateTypeApplier.java @@ -19,47 +19,34 @@ import java.math.BigInteger; import ghidra.app.util.bin.format.pdb2.pdbreader.Numeric; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractEnumerateMsType; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.pdb.PdbNamespaceUtils; import ghidra.program.model.data.DataType; /** * Applier for {@link AbstractEnumerateMsType} types. */ -public class EnumerateTypeApplier extends AbstractMsTypeApplier { +public class EnumerateTypeApplier extends MsTypeApplier { private String fieldName; private Numeric numeric; - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractEnumerateMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - EnumerateTypeApplier.class.getSimpleName()); - } - return type; - } - /** * Constructor for enumerate type applier, for transforming a enumerate into a - * Ghidra DataType. + * Ghidra DataType. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractEnumerateMsType} to process. - * @throws IllegalArgumentException Upon invalid arguments. */ - public EnumerateTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); + public EnumerateTypeApplier(PdbApplicator applicator, AbstractEnumerateMsType msType) { + super(applicator, msType); } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @Override - public void apply() { + void apply() { dataType = applyEnumerateMsType((AbstractEnumerateMsType) msType); // DataType dataType = applyEnumerateMsType((AbstractEnumerateMsType) msType); // ghDataType = dataType; // temporary while below is commented-out @@ -67,11 +54,11 @@ public class EnumerateTypeApplier extends AbstractMsTypeApplier { // ghDataTypeDB = applicator.resolve(dataType); } - public String getName() { + String getName() { return fieldName; } - public Numeric getNumeric() { + Numeric getNumeric() { return numeric; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java index 5089fbca3a..f87d9fcc16 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FieldListTypeApplier.java @@ -22,24 +22,23 @@ import java.util.List; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; import ghidra.program.model.data.DataType; -import ghidra.util.Msg; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractFieldListMsType} types and {@code NO_TYPE} when in place of the - * former type. + * former type. */ -public class FieldListTypeApplier extends AbstractMsTypeApplier { +public class FieldListTypeApplier extends MsTypeApplier { - private List baseClassList = new ArrayList<>(); - private List memberList = new ArrayList<>(); - private List methodList = new ArrayList<>(); + private List baseClassList = new ArrayList<>(); + private List memberList = new ArrayList<>(); + private List methodList = new ArrayList<>(); private boolean isEmpty; // return can be null static FieldListTypeApplier getFieldListApplierSpecial(PdbApplicator applicator, RecordNumber recordNumber) throws PdbException { - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getApplierOrNoTypeSpec(recordNumber, FieldListTypeApplier.class); FieldListTypeApplier fieldListApplier = null; if (applier instanceof FieldListTypeApplier) { @@ -95,29 +94,29 @@ public class FieldListTypeApplier extends AbstractMsTypeApplier { * Indicates that the list is empty * @return {@code true} if list is empty. */ - public boolean isEmpty() { + boolean isEmpty() { return isEmpty; } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { dataType = applyFieldListMsType((AbstractFieldListMsType) msType); } - public List getBaseClassList() { + List getBaseClassList() { return baseClassList; } - public List getMemberList() { + List getMemberList() { return memberList; } - public List getMethodList() { + List getMethodList() { return methodList; } @@ -129,7 +128,7 @@ public class FieldListTypeApplier extends AbstractMsTypeApplier { applyMethods(type.getMethodList()); for (AbstractIndexMsType indexType : type.getIndexList()) { - AbstractMsTypeApplier referencedTypeApplier = + MsTypeApplier referencedTypeApplier = applicator.getTypeApplier(indexType.getReferencedRecordNumber()); if (referencedTypeApplier instanceof FieldListTypeApplier) { FieldListTypeApplier subApplier = (FieldListTypeApplier) referencedTypeApplier; @@ -138,9 +137,7 @@ public class FieldListTypeApplier extends AbstractMsTypeApplier { methodList.addAll(subApplier.getMethodList()); } else { - String message = "referenceTypeApplier is not FieldListTypeApplier"; - Msg.info(this, message); - PdbLog.message(message); + pdbLogAndInfoMessage(this, "referenceTypeApplier is not FieldListTypeApplier"); } } return null; @@ -150,7 +147,7 @@ public class FieldListTypeApplier extends AbstractMsTypeApplier { throws CancelledException, PdbException { for (MsTypeField typeIterated : baseClasses) { // Use dummy index of zero. - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getTypeApplier((AbstractMsType) typeIterated); applier.apply(); // Need to apply here, as these are embedded records baseClassList.add(applier); @@ -160,7 +157,7 @@ public class FieldListTypeApplier extends AbstractMsTypeApplier { private void applyMembers(List members) throws CancelledException, PdbException { for (MsTypeField typeIterated : members) { // Use dummy index of zero. - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getTypeApplier((AbstractMsType) typeIterated); applier.apply(); // Need to apply here, as these are embedded records memberList.add(applier); @@ -170,7 +167,7 @@ public class FieldListTypeApplier extends AbstractMsTypeApplier { private void applyMethods(List methods) throws CancelledException, PdbException { for (MsTypeField typeIterated : methods) { // Use dummy index of zero. - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getTypeApplier((AbstractMsType) typeIterated); // TODO: note that these are likely NoTypeAppliers at the moment, as we had not // yet implemented appliers for AbstractOneMethodMsType and diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java index c8edec85f8..e18666119a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FrameAndProcedureInformationSymbolApplier.java @@ -25,10 +25,15 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link ExtraFrameAndProcedureInformationMsSymbol} symbols. */ -public class FrameAndProcedureInformationSymbolApplier extends AbstractMsSymbolApplier { +public class FrameAndProcedureInformationSymbolApplier extends MsSymbolApplier { private ExtraFrameAndProcedureInformationMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public FrameAndProcedureInformationSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); @@ -41,17 +46,15 @@ public class FrameAndProcedureInformationSymbolApplier extends AbstractMsSymbolA } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) - throws PdbException, CancelledException { + void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException { if (applyToApplier instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; -// public void applyTo(FunctionSymbolApplier functionSymbolApplier) { functionSymbolApplier.setSpecifiedFrameSize(symbol.getProcedureFrameTotalLength()); } } @Override - public void apply() { + void apply() { // Quietly do nothing } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 5963f89ad8..8207022f71 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -37,7 +37,7 @@ import ghidra.util.task.TaskMonitor; /** * Applier for {@link AbstractProcedureStartMsSymbol} and {@link AbstractThunkMsSymbol} symbols. */ -public class FunctionSymbolApplier extends AbstractMsSymbolApplier { +public class FunctionSymbolApplier extends MsSymbolApplier { private static final String BLOCK_INDENT = " "; @@ -58,11 +58,17 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { // private List stackVariableAppliers = new ArrayList<>(); - private List allAppliers = new ArrayList<>(); + private List allAppliers = new ArrayList<>(); private RegisterChangeCalculator registerChangeCalculator; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + * @throws CancelledException upon user cancellation + */ public FunctionSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) - throws CancelledException, NoSuchElementException { + throws CancelledException { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); symbolBlockNestingLevel = 0; @@ -71,11 +77,11 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { if (abstractSymbol instanceof AbstractProcedureMsSymbol) { procedureSymbol = (AbstractProcedureMsSymbol) abstractSymbol; - specifiedAddress = applicator.reladdr(procedureSymbol); + specifiedAddress = applicator.getAddress(procedureSymbol); } else if (abstractSymbol instanceof AbstractThunkMsSymbol) { thunkSymbol = (AbstractThunkMsSymbol) abstractSymbol; - specifiedAddress = applicator.reladdr(thunkSymbol); + specifiedAddress = applicator.getAddress(thunkSymbol); } else { throw new AssertException( @@ -86,14 +92,14 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { while (notDone()) { applicator.checkCanceled(); - AbstractMsSymbolApplier applier = applicator.getSymbolApplier(iter); + MsSymbolApplier applier = applicator.getSymbolApplier(iter); allAppliers.add(applier); applier.manageBlockNesting(this); } } @Override - public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + void manageBlockNesting(MsSymbolApplier applierParam) { if (applierParam instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; if (procedureSymbol != null) { @@ -114,7 +120,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { * Returns the {@link Function} for this applier. * @return the Function */ - public Function getFunction() { + Function getFunction() { return function; } @@ -122,7 +128,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { * Returns the current frame size. * @return the current frame size. */ - public long getCurrentFrameSize() { + long getCurrentFrameSize() { return currentFrameSize; } @@ -130,7 +136,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { * Returns the frame size as specified by the PDB * @return the frame size. */ - public long getSpecifiedFrameSize() { + long getSpecifiedFrameSize() { return specifiedFrameSize; } @@ -147,7 +153,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { * Get the function name * @return the function name */ - public String getName() { + String getName() { if (procedureSymbol != null) { return procedureSymbol.getName(); } @@ -158,12 +164,12 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing. } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { boolean result = applyTo(applicator.getCancelOnlyWrappingMonitor()); if (result == false) { throw new PdbException("failure in applying " + this.getClass().getSimpleName() + @@ -171,11 +177,11 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { } } - public boolean applyTo(TaskMonitor monitor) throws PdbException, CancelledException { + boolean applyTo(TaskMonitor monitor) throws PdbException, CancelledException { return applyTo(applicator.getProgram(), remapAddress, monitor); } - public boolean applyTo(Program program, Address address, TaskMonitor monitor) + boolean applyTo(Program program, Address address, TaskMonitor monitor) throws PdbException, CancelledException { boolean functionSuccess = applyFunction(program, address, monitor); @@ -186,7 +192,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { baseParamOffset = VariableUtilities.getBaseStackParamOffset(function); - for (AbstractMsSymbolApplier applier : allAppliers) { + for (MsSymbolApplier applier : allAppliers) { applier.applyTo(this); } @@ -202,11 +208,11 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { return true; } - public Integer getRegisterPrologChange(Register register) { + Integer getRegisterPrologChange(Register register) { return registerChangeCalculator.getRegChange(applicator, register); } - public int getBaseParamOffset() { + int getBaseParamOffset() { return baseParamOffset; } @@ -281,7 +287,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { } // Rest presumes procedureSymbol. RecordNumber typeRecordNumber = procedureSymbol.getTypeRecordNumber(); - AbstractMsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); + MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); if (applier == null) { applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " + typeRecordNumber + " at " + address); @@ -327,7 +333,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { return (symbolBlockNestingLevel > 0) && iter.hasNext(); } - public int endBlock() { + int endBlock() { if (--symbolBlockNestingLevel < 0) { applicator.appendLogMsg( "Block Nesting went negative for " + getName() + " at " + remapAddress); @@ -338,7 +344,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { return symbolBlockNestingLevel; } - public void beginBlock(Address startAddress, String name, long length) { + void beginBlock(Address startAddress, String name, long length) { int nestingLevel = beginBlock(startAddress); if (!applicator.getPdbApplicatorOptions().applyCodeScopeBlockComments()) { @@ -439,7 +445,7 @@ public class FunctionSymbolApplier extends AbstractMsSymbolApplier { return new CallDepthChangeInfo(function, scopeSet, frameReg, monitor); } - public Integer getRegChange(PdbApplicator applicator, Register register) { + Integer getRegChange(PdbApplicator applicator, Register register) { if (callDepthChangeInfo == null || register == null) { return null; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java index 8482dc6e55..e815af5a0d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java @@ -30,10 +30,16 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractLabelMsSymbol} symbols. */ -public class LabelSymbolApplier extends AbstractMsSymbolApplier { +public class LabelSymbolApplier extends MsSymbolApplier { private AbstractLabelMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + * @throws CancelledException upon user cancellation + */ public LabelSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -45,13 +51,13 @@ public class LabelSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { if (!applicator.getPdbApplicatorOptions().applyInstructionLabels()) { return; } // Place compiler generated symbols (e.g., $LN9) within containing function when possible String name = symbol.getName(); - Address symbolAddress = applicator.reladdr(symbol); + Address symbolAddress = applicator.getAddress(symbol); FunctionManager functionManager = applicator.getProgram().getFunctionManager(); // TODO: What do we do with labels such as this?... "__catch$?test_eh1@@YAHXZ$7" if (name.startsWith("$") && !name.contains(Namespace.DELIMITER)) { @@ -67,7 +73,7 @@ public class LabelSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java index d72c00b5ee..5b73796100 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LocalOptimizedSymbolApplier.java @@ -16,20 +16,23 @@ package ghidra.app.util.pdb.pdbapplicator; 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.symbol.*; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; -import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractLocalSymbolInOptimizedCodeMsSymbol} symbols. */ -public class LocalOptimizedSymbolApplier extends AbstractMsSymbolApplier { +public class LocalOptimizedSymbolApplier extends MsSymbolApplier { private AbstractLocalSymbolInOptimizedCodeMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public LocalOptimizedSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -41,15 +44,13 @@ public class LocalOptimizedSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void apply() throws PdbException, CancelledException { - String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; - Msg.info(this, message); - PdbLog.message(message); + void apply() throws PdbException, CancelledException { + pdbLogAndInfoMessage(this, + "Cannot apply " + this.getClass().getSimpleName() + " directly to program"); } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) - throws PdbException, CancelledException { + void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException { if (!applicator.getPdbApplicatorOptions().applyFunctionVariables()) { return; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java index 9c67bf3316..681d628987 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java @@ -20,7 +20,8 @@ import java.math.BigInteger; 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.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMemberFunctionMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention; import ghidra.program.model.data.DataType; import ghidra.util.exception.CancelledException; @@ -29,34 +30,22 @@ import ghidra.util.exception.CancelledException; */ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { -// private boolean hasThisPointer = false; - private AbstractMsTypeApplier thisPointerApplier = null; - private CompositeTypeApplier containingCompositeApplier = null; - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractMemberFunctionMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - MemberFunctionTypeApplier.class.getSimpleName()); - } - return type; - } + private MsTypeApplier thisPointerApplier = null; /** * Constructor for the applicator that applies {@link AbstractMemberFunctionMsType}, - * transforming it into a Ghidra {@link DataType}. + * transforming it into a Ghidra {@link DataType}. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractMemberFunctionMsType} to processes. * @throws IllegalArgumentException Upon type mismatch. */ - public MemberFunctionTypeApplier(PdbApplicator applicator, AbstractMsType msType) + public MemberFunctionTypeApplier(PdbApplicator applicator, AbstractMemberFunctionMsType msType) throws IllegalArgumentException { - super(applicator, validateType(msType)); + super(applicator, msType); } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @@ -66,8 +55,8 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { } @Override - protected boolean hasThisPointer() throws CancelledException, PdbException { - AbstractMsTypeApplier applier = applicator.getTypeApplier( + protected boolean hasThisPointer() { + MsTypeApplier applier = applicator.getTypeApplier( ((AbstractMemberFunctionMsType) msType).getThisPointerRecordNumber()); if ((applier instanceof PrimitiveTypeApplier && ((PrimitiveTypeApplier) applier).isNoType())) { @@ -87,7 +76,7 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { predefineClasses(); applyFunction(getCallingConvention(), hasThisPointer()); } @@ -99,7 +88,7 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointer( thisPointerApplier); if (thisPointerApplier instanceof PointerTypeApplier) { - AbstractMsTypeApplier underlyingApplier = + MsTypeApplier underlyingApplier = getThisUnderlyingApplier((PointerTypeApplier) thisPointerApplier); applicator.getPdbApplicatorMetrics().witnessMemberFunctionThisPointerUnderlyingType( underlyingApplier); @@ -185,8 +174,8 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { // return true; // } - private AbstractMsTypeApplier getThisPointerApplier(AbstractMemberFunctionMsType procType) { - AbstractMsTypeApplier applier = + private MsTypeApplier getThisPointerApplier(AbstractMemberFunctionMsType procType) { + MsTypeApplier applier = applicator.getTypeApplier(procType.getThisPointerRecordNumber()); // if ((applier instanceof PrimitiveTypeApplier && @@ -204,7 +193,7 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier { return applier; } - private AbstractMsTypeApplier getThisUnderlyingApplier(PointerTypeApplier thisApplier) { + private MsTypeApplier getThisUnderlyingApplier(PointerTypeApplier thisApplier) { return thisApplier.getUnmodifiedUnderlyingTypeApplier(); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java index 029a81ab2d..cae3cf4a65 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberTypeApplier.java @@ -18,42 +18,32 @@ package ghidra.app.util.pdb.pdbapplicator; import java.math.BigInteger; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMemberMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.ClassFieldMsAttributes; import ghidra.program.model.data.DataType; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractMemberMsType} types. */ -public class MemberTypeApplier extends AbstractMsTypeApplier { - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractMemberMsType)) { - throw new IllegalArgumentException("PDB Incorrectly applying " + - type.getClass().getSimpleName() + " to " + MemberTypeApplier.class.getSimpleName()); - } - return type; - } +public class MemberTypeApplier extends MsTypeApplier { /** * Constructor for member type applier. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractMemberMsType} to process. - * @throws IllegalArgumentException Upon invalid arguments. */ - public MemberTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); + public MemberTypeApplier(PdbApplicator applicator, AbstractMemberMsType msType) { + super(applicator, msType); } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { dataType = applyMemberMsType((AbstractMemberMsType) msType); // DataType dataType = applyMemberMsType((AbstractMemberMsType) msType); // ghDataType = dataType; // temporary while below is commented-out @@ -61,20 +51,21 @@ public class MemberTypeApplier extends AbstractMsTypeApplier { // ghDataTypeDB = applicator.resolve(dataType); } - public String getName() { + String getName() { return ((AbstractMemberMsType) msType).getName(); } - public BigInteger getOffset() { + BigInteger getOffset() { return ((AbstractMemberMsType) msType).getOffset(); } - public ClassFieldMsAttributes getAttribute() { + ClassFieldMsAttributes getAttribute() { return ((AbstractMemberMsType) msType).getAttribute(); } - public AbstractMsTypeApplier getFieldTypeApplier() { - return applicator.getTypeApplier(((AbstractMemberMsType) msType).getFieldTypeRecordNumber()); + MsTypeApplier getFieldTypeApplier() { + return applicator.getTypeApplier( + ((AbstractMemberMsType) msType).getFieldTypeRecordNumber()); } private DataType applyMemberMsType(AbstractMemberMsType type) { @@ -91,7 +82,6 @@ public class MemberTypeApplier extends AbstractMsTypeApplier { //// DataType fieldDataType = getConvertedDataType(applicator, fieldTypeIndex); return null; - } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java index 3d63599f1c..b92df8681c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ModifierTypeApplier.java @@ -19,51 +19,26 @@ import java.math.BigInteger; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractModifierMsType; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.program.model.data.DataType; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractModifierMsType} types. */ -//public class ModifierTypeApplier extends AbstractMsTypeApplier { -public class ModifierTypeApplier extends AbstractMsTypeApplier { +public class ModifierTypeApplier extends MsTypeApplier { - private boolean isDeferred = false; - - private AbstractMsTypeApplier modifiedTypeApplier = null; - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractModifierMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - ModifierTypeApplier.class.getSimpleName()); - } - return type; - } + private MsTypeApplier modifiedTypeApplier = null; /** * Constructor for modifier type applier. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractModifierMsType} to processes. - * @throws IllegalArgumentException Upon invalid arguments. */ - public ModifierTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); + public ModifierTypeApplier(PdbApplicator applicator, AbstractModifierMsType msType) { + super(applicator, msType); } //============================================================================================== - public void setDeferred() { - isDeferred = true; - } - - @Override - public boolean isDeferred() { - return isDeferred; - } - @Override void deferredApply() throws PdbException, CancelledException { // Do nothing. Already applied. Just needs late resolve @@ -71,7 +46,7 @@ public class ModifierTypeApplier extends AbstractMsTypeApplier { //============================================================================================== @Override - public BigInteger getSize() { + BigInteger getSize() { if (modifiedTypeApplier == null) { return BigInteger.ZERO; } @@ -79,7 +54,7 @@ public class ModifierTypeApplier extends AbstractMsTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { // dataType = applyModifierMsType((AbstractModifierMsType) msType); applyOrDeferForDependencies(); } @@ -87,8 +62,7 @@ public class ModifierTypeApplier extends AbstractMsTypeApplier { private void applyOrDeferForDependencies() { AbstractModifierMsType type = (AbstractModifierMsType) msType; applyModifierMsType(type); - AbstractMsTypeApplier modifiedApplier = - applicator.getTypeApplier(type.getModifiedRecordNumber()); + MsTypeApplier modifiedApplier = applicator.getTypeApplier(type.getModifiedRecordNumber()); if (modifiedApplier.isDeferred()) { applicator.addApplierDependency(this, modifiedApplier); setDeferred(); @@ -100,7 +74,7 @@ public class ModifierTypeApplier extends AbstractMsTypeApplier { } @Override - public DataType getDataType() { + DataType getDataType() { return modifiedTypeApplier.getDataType(); } @@ -130,7 +104,7 @@ public class ModifierTypeApplier extends AbstractMsTypeApplier { return modifiedTypeApplier.getCycleBreakType(); } - public AbstractMsTypeApplier getModifiedTypeApplier() { + MsTypeApplier getModifiedTypeApplier() { return modifiedTypeApplier; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java similarity index 58% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsSymbolApplier.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java index 22040424ac..78c67eb752 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java @@ -17,17 +17,31 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.Objects; +import ghidra.app.plugin.processors.sleigh.symbol.Symbol; 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.symbol.AbstractMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.CancelledException; -public abstract class AbstractMsSymbolApplier { +/** + * Abstract class representing the applier for a specific {@link AbstractMsSymbol}. The + * {@link #apply()} method creates an associated {@link Symbol}, if applicable, or might + * apply information to other {@link MsSymbolApplier AbstractMsSymbolAppliers}. + * Methods associated with the {@link MsSymbolApplier} or derived class will + * make fields available to the user from the {@link AbstractMsSymbol}. + */ +public abstract class MsSymbolApplier { protected PdbApplicator applicator; protected AbstractMsSymbolIterator iter; protected long currentOffset; - public AbstractMsSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ + public MsSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { Objects.requireNonNull(applicator, "applicator cannot be null"); Objects.requireNonNull(iter, "symbolGroup cannot be null"); this.applicator = applicator; @@ -35,6 +49,15 @@ public abstract class AbstractMsSymbolApplier { currentOffset = iter.getCurrentOffset(); } + /** + * Puts message to {@link PdbLog} and to Msg.info() + * @param originator a Logger instance, "this", or YourClass.class + * @param message the message to display + */ + protected void pdbLogAndInfoMessage(Object originator, String message) { + applicator.pdbLogAndInfoMessage(originator, message); + } + /** * Sets the offset of the {@link SymbolGroup} back to the state when this applicator was * created. @@ -49,26 +72,26 @@ public abstract class AbstractMsSymbolApplier { * @throws PdbException if there was a problem processing the data. * @throws CancelledException upon user cancellation */ - public abstract void apply() throws PdbException, CancelledException; + abstract void apply() throws PdbException, CancelledException; /** - * Applies logic of this class to another {@link AbstractMsSymbolApplier} instead of to - * "the program." + * Applies logic of this class to another {@link MsSymbolApplier} instead of to + * "the program." * @param applyToApplier the applier to which the logic of this class is applied. * @throws PdbException if there was a problem processing the data. * @throws CancelledException upon user cancellation. */ - public abstract void applyTo(AbstractMsSymbolApplier applyToApplier) + abstract void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException; /** * Manages block nesting for symbols/appliers that represent the beginning or end of blocks. - * The default is to do nothing. Otherwise the appliers should implement the appropriate - * logic. + * The default is to do nothing. Otherwise the appliers should implement the appropriate + * logic. * @param applierParam the applier which is managing blocks, which is typically - * {@link FunctionSymbolApplier}. + * {@link FunctionSymbolApplier}. */ - public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + void manageBlockNesting(MsSymbolApplier applierParam) { // Do nothing by default. } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java similarity index 59% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsTypeApplier.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java index 4af118ed9a..fd3f44f4a0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractMsTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java @@ -18,20 +18,19 @@ package ghidra.app.util.pdb.pdbapplicator; import java.math.BigInteger; import java.util.*; -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.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.program.model.data.DataType; import ghidra.util.exception.CancelledException; /** - * Abstract class representing the applier/wrapper for a specific {@link AbstractMsType}. The - * {link {@link #apply()} method creates an associated {@link DataType}, if - * applicable. Methods associated with the {@link AbstractMsTypeApplier} or derived class will - * make fields available to the user, first by trying to get them from the {@link DataType}, - * otherwise getting them from the {@link AbstractMsType}. + * Abstract class representing the applier for a specific {@link AbstractMsType}. The + * {@link #apply()} method creates an associated {@link DataType}, if applicable. + * Methods associated with the {@link MsTypeApplier} or derived class will + * make fields available to the user, first by trying to get them from the {@link DataType}, + * otherwise getting them from the {@link AbstractMsType}. */ -public abstract class AbstractMsTypeApplier implements Comparable { +public abstract class MsTypeApplier { protected PdbApplicator applicator; protected AbstractMsType msType; @@ -43,19 +42,16 @@ public abstract class AbstractMsTypeApplier implements Comparable waitSet = new HashSet<>(); + private boolean isDeferred = false; + + protected Set waitSet = new HashSet<>(); /** * Constructor. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractMsType} to apply. - * @throws IllegalArgumentException Upon invalid arguments. */ - public AbstractMsTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - if (msType == null) { - throw new IllegalArgumentException("PDB Type Applying null AbstractMsType"); - } + public MsTypeApplier(PdbApplicator applicator, AbstractMsType msType) { this.applicator = applicator; this.msType = msType; RecordNumber recordNumber = msType.getRecordNumber(); @@ -68,30 +64,74 @@ public abstract class AbstractMsTypeApplier implements Comparable list = new ArrayList<>(waitSet); + protected MsTypeApplier waitSetGetNext() { + List list = new ArrayList<>(waitSet); return list.get(0); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java index 6e57214090..3efb7eaf80 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java @@ -26,8 +26,8 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractNestedTypeMsType} and {@link AbstractNestedTypeExtMsType} types. */ -public class NestedTypeApplier extends AbstractMsTypeApplier { - private AbstractMsTypeApplier nestedTypeDefinitionApplier = null; +public class NestedTypeApplier extends MsTypeApplier { + private MsTypeApplier nestedTypeDefinitionApplier = null; private static AbstractMsType validateType(AbstractMsType type) throws IllegalArgumentException { @@ -52,7 +52,7 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { } @Override - public BigInteger getSize() { + BigInteger getSize() { if (nestedTypeDefinitionApplier == null) { return BigInteger.ZERO; } @@ -63,7 +63,7 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { * Returns the name of this nested type. * @return Name of the nested type. */ - public String getTypeName() { + String getTypeName() { if (nestedTypeDefinitionApplier == null) { return ""; } @@ -74,7 +74,7 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { * Returns the nested (member?) name for this nested type. * @return (Member?) Name for the nested type. */ - public String getMemberName() { + String getMemberName() { if (nestedTypeDefinitionApplier == null) { return ""; } @@ -84,7 +84,7 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { return ((AbstractNestedTypeExtMsType) msType).getName(); } - AbstractMsTypeApplier getNestedTypeDefinitionApplier() { + MsTypeApplier getNestedTypeDefinitionApplier() { return applicator.getTypeApplier(getNestedTypeDefinitionRecordNumber()); } @@ -99,7 +99,7 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { * Indicates if there are attributes. Returns false if not "applied" yet. * @return [@code true} if there are attributes. */ - public boolean hasAttributes() { + boolean hasAttributes() { if (nestedTypeDefinitionApplier == null) { return false; } @@ -113,7 +113,7 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { * Returns the attributes if they exist. * @return the attributes or null if they do not exist. */ - public ClassFieldMsAttributes getAttributes() { + ClassFieldMsAttributes getAttributes() { AbstractMsType type = nestedTypeDefinitionApplier.getMsType(); if (type instanceof AbstractNestedTypeExtMsType) { return ((AbstractNestedTypeExtMsType) type).getClassFieldAttributes(); @@ -122,7 +122,7 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { if (msType instanceof AbstractNestedTypeMsType) { dataType = applyNestedTypeMsType((AbstractNestedTypeMsType) msType); } @@ -132,12 +132,14 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { } private DataType applyNestedTypeMsType(AbstractNestedTypeMsType type) { - nestedTypeDefinitionApplier = applicator.getTypeApplier(type.getNestedTypeDefinitionRecordNumber()); + nestedTypeDefinitionApplier = + applicator.getTypeApplier(type.getNestedTypeDefinitionRecordNumber()); return nestedTypeDefinitionApplier.getDataType(); } private DataType applyNestedTypeExtMsType(AbstractNestedTypeExtMsType type) { - nestedTypeDefinitionApplier = applicator.getTypeApplier(type.getNestedTypeDefinitionRecordNumber()); + nestedTypeDefinitionApplier = + applicator.getTypeApplier(type.getNestedTypeDefinitionRecordNumber()); return nestedTypeDefinitionApplier.getDataType(); } @@ -163,7 +165,7 @@ public class NestedTypeApplier extends AbstractMsTypeApplier { // return modifiedTypeApplier.getCycleBreakType(applicator); } - public AbstractMsTypeApplier getNestedTypeApplier() { + MsTypeApplier getNestedTypeApplier() { return nestedTypeDefinitionApplier; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java index 1a4c0aee6b..4acb99eaca 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java @@ -19,26 +19,31 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; /** - * A dummy {@link AbstractMsSymbolApplier}, which, at a minimum, reads the symbol from the - * {@link SymbolGroup}, allowing proper sequencing of other symbols within the - * {@link SymbolGroup}. + * A dummy {@link MsSymbolApplier}, which, at a minimum, reads the symbol from the + * {@link SymbolGroup}, allowing proper sequencing of other symbols within the + * {@link SymbolGroup}. */ -public class NoSymbolApplier extends AbstractMsSymbolApplier { +public class NoSymbolApplier extends MsSymbolApplier { AbstractMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public NoSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); symbol = iter.next(); } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing. } @Override - public void apply() { + void apply() { // Do nothing. } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java index 0aea6bc6d9..56f185caa1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoTypeApplier.java @@ -21,9 +21,9 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; /** * Used for creating a wrapper for when there is not associated type to the PDB type (or if we - * have not yet created the association). + * have not yet created the association). */ -public class NoTypeApplier extends AbstractMsTypeApplier { +public class NoTypeApplier extends MsTypeApplier { /** * Constructor for nested type applier. @@ -37,12 +37,12 @@ public class NoTypeApplier extends AbstractMsTypeApplier { } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @Override - public void apply() { + void apply() { // Do nothing (maybe should log something... not sure) // applicator.getLog().appendMsg(""); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java index 0137e99b14..f75c0c3fb4 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java @@ -15,8 +15,9 @@ */ package ghidra.app.util.pdb.pdbapplicator; -//---------------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------------- +/** + * Mode for {@link CppCompositeType} class layout. + */ enum OoComponentLayoutMode { UNKNOWN, MEMBERS_ONLY, BASIC, SIMPLE, COMPLEX } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index e23bab1615..fec645aea0 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -27,7 +27,7 @@ import ghidra.util.exception.CancelledException; /** * Manages Address/Section/Segment-related PDB items. - * Has method for providing real addresses. + * Has method for providing real addresses. */ public class PdbAddressManager { @@ -72,19 +72,19 @@ public class PdbAddressManager { * @return The Address */ // Returns an address using the section and offset. - Address reladdr(AddressMsSymbol symbol) { - return reladdr(symbol.getSegment(), symbol.getOffset()); + Address getAddress(AddressMsSymbol symbol) { + return getAddress(symbol.getSegment(), symbol.getOffset()); } /** * Returns the Address for the given section and offset. Will attempt to map the address - * to a new address if the {@link PdbApplicatorOptions} + * to a new address if the {@link PdbApplicatorOptions} * @param segment The segment * @param offset The offset * @return The Address, which can be {@code Address.NO_ADDRESS} if it was the original address. */ // Returns an address using the section and offset. - Address reladdr(int segment, long offset) { + Address getAddress(int segment, long offset) { if (segment < 0 || segment > allSegmentsInfo.size()) { return Address.NO_ADDRESS; } @@ -102,9 +102,9 @@ public class PdbAddressManager { /** * Write the mapped address for a query address, where where the mapping is - * derived by using a the address of a PDB symbol as the key and finding the address of - * a symbol in the program of the same "unique" name. This is accomplished using public - * mangled symbols. If the program symbol came from the PDB, then it maps to itself. + * derived by using a the address of a PDB symbol as the key and finding the address of + * a symbol in the program of the same "unique" name. This is accomplished using public + * mangled symbols. If the program symbol came from the PDB, then it maps to itself. * @param address the query address * @param remapAddress the mapped address */ @@ -122,9 +122,9 @@ public class PdbAddressManager { /** * Returns the Address of an existing symbol for the query address, where the mapping is - * derived by using a the address of a PDB symbol as the key and finding the address of - * a symbol in the program of the same "unique" name. This is accomplished using public - * mangled symbols. If the program symbol came from the PDB, then it maps to itself. + * derived by using a the address of a PDB symbol as the key and finding the address of + * a symbol in the program of the same "unique" name. This is accomplished using public + * mangled symbols. If the program symbol came from the PDB, then it maps to itself. * @param address the query address * @return the remapAddress */ @@ -270,7 +270,7 @@ public class PdbAddressManager { long offset = sym.getOffset(); int length = sym.getLength(); int characteristics = sym.getCharacteristics(); - Address address = reladdr(sym); + Address address = getAddress(sym); PdbLog.message(String.format("%s: [%04X:%08X](%s) Len:%08X, Characteristics:%08X", name, segment, offset, address.toString(), length, characteristics)); } @@ -307,7 +307,7 @@ public class PdbAddressManager { MemoryBlock[] blocks = mem.getBlocks(); List segmentMapList = pdb.getDatabaseInterface().getSegmentMapList(); /** - * Program has additional "Headers" block set up by the {@link PeLoader}. + * Program has additional "Headers" block set up by the {@link PeLoader}. */ int progIndexLimit = blocks.length; int pdbIndexLimit = segmentMapList.size(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java index 81151949fc..f30b6ea142 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -25,7 +25,7 @@ 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.importer.MessageLog; -import ghidra.app.util.pdb.PdbCategoryUtils; +import ghidra.app.util.pdb.PdbCategories; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.graph.*; import ghidra.graph.algo.GraphNavigator; @@ -36,11 +36,29 @@ import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; import ghidra.util.Msg; -import ghidra.util.exception.CancelledException; -import ghidra.util.exception.InvalidInputException; +import ghidra.util.exception.*; import ghidra.util.task.CancelOnlyWrappingTaskMonitor; import ghidra.util.task.TaskMonitor; +/** + * The main engine for applying an AbstractPdb to Ghidra, whether a Program or DataTypeManager. + * The class is to be constructed first. + *

    + * The + * {@link #applyTo(Program, DataTypeManager, Address, PdbApplicatorOptions, TaskMonitor, MessageLog)} + * method is then called with the appropriate {@link PdbApplicatorOptions} along with a + * {@link Program} and/or {@link DataTypeManager}. Either, but not both can be null. + * If the Program is not null but the DatatypeManager is null, then the DataTypeManager is gotten + * from the Program. If the Program is null, then data types can be applied to a DataTypeManager. + * The validation logic for the parameters is found in + * {@link #validateAndSetParameters(Program, DataTypeManager, Address, PdbApplicatorOptions, TaskMonitor, MessageLog)}. + *

    + * Once the parameters are validated, appropriate classes and storage containers are constructed. + * Then processing commences, first with data types, followed by symbol-related processing. + *

    + * {@link PdbApplicatorMetrics} are captured during the processing and status and logging is + * reported to various mechanisms including {@link Msg}, {@link MessageLog}, and {@link PdbLog}. + */ public class PdbApplicator { /** @@ -49,7 +67,7 @@ public class PdbApplicator { * @param big BigInteger value to convert. * @return the integer value. */ - public static long bigIntegerToLong(PdbApplicator myApplicator, BigInteger big) { + static long bigIntegerToLong(PdbApplicator myApplicator, BigInteger big) { try { return big.longValueExact(); } @@ -67,7 +85,7 @@ public class PdbApplicator { * @param big BigInteger value to convert. * @return the integer value. */ - public static int bigIntegerToInt(PdbApplicator myApplicator, BigInteger big) { + static int bigIntegerToInt(PdbApplicator myApplicator, BigInteger big) { try { return big.intValueExact(); } @@ -106,11 +124,11 @@ public class PdbApplicator { //============================================================================================== private int resolveCount; - private PdbCategoryUtils categoryUtils; + private PdbCategories categoryUtils; private PdbPrimitiveTypeApplicator pdbPrimitiveTypeApplicator; - private TypeApplierParser typeApplierParser; + private TypeApplierFactory typeApplierParser; private ComplexTypeApplierMapper complexApplierMapper; - private JungDirectedGraph> applierDependencyGraph; + private JungDirectedGraph> applierDependencyGraph; /** * This namespace map documents as follows: *

    @@ -121,7 +139,7 @@ public class PdbApplicator {
     	private Map isClassByNamespace;
     
     	//==============================================================================================
    -	private SymbolApplierParser symbolApplierParser;
    +	private SymbolApplierFactory symbolApplierParser;
     
     	// Investigating... might change from String to AbstractSymbolApplier.
     	private Map> labelsByAddress;
    @@ -142,13 +160,13 @@ public class PdbApplicator {
     	//==============================================================================================
     	/**
     	 * Applies the PDB to the {@link Program} or {@link DataTypeManager}. Either, but not both,
    -	 *  can be null.
    +	 * can be null.
     	 * @param programParam The {@link Program} to which to apply the PDB. Can be null in certain
    -	 *  circumstances.
    +	 * circumstances.
     	 * @param dataTypeManagerParam The {@link DataTypeManager} to which to apply data types. Can be
    -	 *  null in certain circumstances.
    +	 * null in certain circumstances.
     	 * @param imageBaseParam Address bases from which symbol addresses are based. If null, uses
    -	 *  the image base of the program (both cannot be null).
    +	 * the image base of the program (both cannot be null).
     	 * @param applicatorOptionsParam {@link PdbApplicatorOptions} used for applying the PDB.
     	 * @param monitorParam TaskMonitor uses for watching progress and cancellation notices.
     	 * @param logParam The MessageLog to which to output messages.
    @@ -187,7 +205,7 @@ public class PdbApplicator {
     	private void processTypes() throws CancelledException, PdbException {
     		setMonitorMessage("PDB: Applying to DTM " + dataTypeManager.getName() + "...");
     
    -		PdbResearch.initCheckBreak(); // for developmental debug
    +		PdbResearch.initBreakPointRecordNumbers(); // for developmental debug
     
     		resolveCount = 0;
     
    @@ -279,7 +297,7 @@ public class PdbApplicator {
     
     		categoryUtils = setPdbCatogoryUtils(pdbFilename);
     		pdbPrimitiveTypeApplicator = new PdbPrimitiveTypeApplicator(dataTypeManager);
    -		typeApplierParser = new TypeApplierParser(this);
    +		typeApplierParser = new TypeApplierFactory(this);
     		complexApplierMapper = new ComplexTypeApplierMapper(this);
     		applierDependencyGraph = new JungDirectedGraph<>();
     		isClassByNamespace = new TreeMap<>();
    @@ -294,7 +312,7 @@ public class PdbApplicator {
     			vbtManager = new VbtManager(getDataTypeManager());
     		}
     
    -		symbolApplierParser = new SymbolApplierParser(this);
    +		symbolApplierParser = new SymbolApplierFactory(this);
     
     		// Investigations
     		labelsByAddress = new HashMap<>();
    @@ -378,6 +396,16 @@ public class PdbApplicator {
     		log.appendMsg(message);
     	}
     
    +	/**
    +	 * Puts message to {@link PdbLog} and to Msg.info()
    +	 * @param originator a Logger instance, "this", or YourClass.class
    +	 * @param message the message to display
    +	 */
    +	void pdbLogAndInfoMessage(Object originator, String message) {
    +		PdbLog.message(message);
    +		Msg.info(originator, message);
    +	}
    +
     	/**
     	 * Returns the {@link TaskMonitor} to available for this analyzer.
     	 * @return the monitor.
    @@ -387,7 +415,9 @@ public class PdbApplicator {
     	}
     
     	/**
    -	 * Returns the {@link CancelOnlyWrappingTaskMonitor} to available for this analyzer.
    +	 * Returns the {@link CancelOnlyWrappingTaskMonitor} to available for this analyzer.  This is
    +	 * useful for the user to be able to control the monitor progress bar without called commands
    +	 * changing its progress on smaller tasks.
     	 * @return the monitor.
     	 */
     	TaskMonitor getCancelOnlyWrappingMonitor() {
    @@ -443,9 +473,9 @@ public class PdbApplicator {
     	//==============================================================================================
     	/**
     	 * Get the {@link CategoryPath} associated with the {@link SymbolPath} specified, rooting
    -	 *  it either at the PDB Category.
    +	 * it either at the PDB Category.
     	 * @param symbolPath Symbol path to be used to create the CategoryPath. Null represents global
    -	 *  namespace.
    +	 * namespace.
     	 * @return {@link CategoryPath} created for the input.
     	 */
     	CategoryPath getCategory(SymbolPath symbolPath) {
    @@ -476,7 +506,7 @@ public class PdbApplicator {
     	 * Returns the {@link CategoryPath} for Anonymous Types Category for the PDB.
     	 * @return the {@link CategoryPath}
     	 */
    -	public CategoryPath getAnonymousTypesCategory() {
    +	CategoryPath getAnonymousTypesCategory() {
     		return categoryUtils.getAnonymousTypesCategory();
     	}
     
    @@ -498,7 +528,7 @@ public class PdbApplicator {
     		categoryUtils.incrementNextAnonymousFunctionName();
     	}
     
    -	private PdbCategoryUtils setPdbCatogoryUtils(String pdbFilename)
    +	private PdbCategories setPdbCatogoryUtils(String pdbFilename)
     			throws CancelledException, PdbException {
     
     		List categoryNames = new ArrayList<>();
    @@ -514,18 +544,18 @@ public class PdbApplicator {
     		if (index == -1) {
     			index = pdbFilename.lastIndexOf("/");
     		}
    -		return new PdbCategoryUtils(pdbFilename.substring(index + 1), categoryNames);
    +		return new PdbCategories(pdbFilename.substring(index + 1), categoryNames);
     	}
     
     	//==============================================================================================
     	// Applier-based-DataType-dependency-related methods.
     	//==============================================================================================
    -	void addApplierDependency(AbstractMsTypeApplier depender) {
    +	void addApplierDependency(MsTypeApplier depender) {
     		Objects.requireNonNull(depender);
     		applierDependencyGraph.addVertex(depender.getDependencyApplier());
     	}
     
    -	void addApplierDependency(AbstractMsTypeApplier depender, AbstractMsTypeApplier dependee) {
    +	void addApplierDependency(MsTypeApplier depender, MsTypeApplier dependee) {
     		Objects.requireNonNull(depender);
     		Objects.requireNonNull(dependee);
     		// TODO: Possibly do checks on dependee and depender types for actual creation
    @@ -541,7 +571,7 @@ public class PdbApplicator {
     			new DefaultGEdge<>(depender.getDependencyApplier(), dependee.getDependencyApplier()));
     	}
     
    -	List getVerticesInPostOrder() {
    +	List getVerticesInPostOrder() {
     		setMonitorMessage("PDB: Determining data type dependency order...");
     		return GraphAlgorithms.getVerticesInPostOrder(applierDependencyGraph,
     			GraphNavigator.topDownNavigator());
    @@ -550,29 +580,28 @@ public class PdbApplicator {
     	//==============================================================================================
     	//==============================================================================================
     	//==============================================================================================
    -	AbstractMsTypeApplier getApplierSpec(RecordNumber recordNumber,
    -			Class expected) throws PdbException {
    +	MsTypeApplier getApplierSpec(RecordNumber recordNumber, Class expected)
    +			throws PdbException {
     		return typeApplierParser.getApplierSpec(recordNumber, expected);
     	}
     
    -	AbstractMsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber,
    -			Class expected) throws PdbException {
    +	MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber,
    +			Class expected) throws PdbException {
     		return typeApplierParser.getApplierOrNoTypeSpec(recordNumber, expected);
     	}
     
    -	AbstractMsTypeApplier getTypeApplier(RecordNumber recordNumber) {
    +	MsTypeApplier getTypeApplier(RecordNumber recordNumber) {
     		return typeApplierParser.getTypeApplier(recordNumber);
     	}
     
    -	AbstractMsTypeApplier getTypeApplier(AbstractMsType type) {
    +	MsTypeApplier getTypeApplier(AbstractMsType type) {
     		return typeApplierParser.getTypeApplier(type);
     	}
     
     	//==============================================================================================
     	//==============================================================================================
     	//==============================================================================================
    -	public int findModuleNumberBySectionOffsetContribution(int section, long offset)
    -			throws PdbException {
    +	int findModuleNumberBySectionOffsetContribution(int section, long offset) throws PdbException {
     		for (AbstractSectionContribution sectionContribution : pdb.getDatabaseInterface().getSectionContributionList()) {
     			int sectionContributionOffset = sectionContribution.getOffset();
     			int maxSectionContributionOffset =
    @@ -594,8 +623,7 @@ public class PdbApplicator {
     			tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) {
     			monitor.checkCanceled();
     			PdbResearch.checkBreak(indexNumber);
    -			AbstractMsTypeApplier applier =
    -				getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
    +			MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
     			//PdbResearch.checkBreak(indexNumber, applier);
     			applier.apply();
     			monitor.incrementProgress(1);
    @@ -657,8 +685,7 @@ public class PdbApplicator {
     		setMonitorMessage("PDB: Processing " + num + " item type components...");
     		for (int indexNumber = ipi.getTypeIndexMin(); indexNumber < num; indexNumber++) {
     			monitor.checkCanceled();
    -			AbstractMsTypeApplier applier =
    -				getTypeApplier(RecordNumber.itemRecordNumber(indexNumber));
    +			MsTypeApplier applier = getTypeApplier(RecordNumber.itemRecordNumber(indexNumber));
     			applier.apply();
     			monitor.incrementProgress(1);
     		}
    @@ -672,11 +699,11 @@ public class PdbApplicator {
     
     	//==============================================================================================
     	private void processDeferred() throws CancelledException, PdbException {
    -		List verticesInPostOrder = getVerticesInPostOrder();
    +		List verticesInPostOrder = getVerticesInPostOrder();
     		monitor.initialize(verticesInPostOrder.size());
     		setMonitorMessage("PDB: Processing " + verticesInPostOrder.size() +
     			" deferred data type dependencies...");
    -		for (AbstractMsTypeApplier applier : verticesInPostOrder) {
    +		for (MsTypeApplier applier : verticesInPostOrder) {
     			monitor.checkCanceled();
     			PdbResearch.checkBreak(applier.index);
     			//checkBreak(applier.index, applier);
    @@ -699,8 +726,7 @@ public class PdbApplicator {
     			tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) {
     			monitor.checkCanceled();
     			PdbResearch.checkBreak(indexNumber);
    -			AbstractMsTypeApplier applier =
    -				getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
    +			MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber));
     			PdbResearch.checkBreak(indexNumber, applier);
     			applier.resolve();
     			monitor.incrementProgress(1);
    @@ -758,8 +784,8 @@ public class PdbApplicator {
     	 * @param symbol The {@link AddressMsSymbol}
     	 * @return The Address
     	 */
    -	Address reladdr(AddressMsSymbol symbol) {
    -		return pdbAddressManager.reladdr(symbol);
    +	Address getAddress(AddressMsSymbol symbol) {
    +		return pdbAddressManager.getAddress(symbol);
     	}
     
     	/**
    @@ -768,15 +794,15 @@ public class PdbApplicator {
     	 * @param offset The offset
     	 * @return The Address
     	 */
    -	Address reladdr(int segment, long offset) {
    -		return pdbAddressManager.reladdr(segment, offset);
    +	Address getAddress(int segment, long offset) {
    +		return pdbAddressManager.getAddress(segment, offset);
     	}
     
     	/**
     	 * Write the mapped address for a query address, where where the mapping is
    -	 *  derived by using a the address of a PDB symbol as the key and finding the address of
    -	 *  a symbol in the program of the same "unique" name. This is accomplished using public
    -	 *  mangled symbols.  If the program symbol came from the PDB, then it maps to itself.
    +	 * derived by using a the address of a PDB symbol as the key and finding the address of
    +	 * a symbol in the program of the same "unique" name. This is accomplished using public
    +	 * mangled symbols.  If the program symbol came from the PDB, then it maps to itself.
     	 * @param address the query address
     	 * @param remapAddress the mapped address
     	 */
    @@ -786,9 +812,9 @@ public class PdbApplicator {
     
     	/**
     	 * Returns the Address of an existing symbol for the query address, where the mapping is
    -	 *  derived by using a the address of a PDB symbol as the key and finding the address of
    -	 *  a symbol in the program of the same "unique" name. This is accomplished using public
    -	 *  mangled symbols.  If the program symbol came from the PDB, then it maps to itself.
    +	 * derived by using a the address of a PDB symbol as the key and finding the address of
    +	 * a symbol in the program of the same "unique" name. This is accomplished using public
    +	 * mangled symbols.  If the program symbol came from the PDB, then it maps to itself.
     	 * @param address the query address
     	 * @return the remapAddress
     	 */
    @@ -1131,15 +1157,14 @@ public class PdbApplicator {
     	//==============================================================================================
     	//==============================================================================================
     	//==============================================================================================
    -	AbstractMsSymbolApplier getSymbolApplier(AbstractMsSymbolIterator iter)
    -			throws CancelledException, NoSuchElementException {
    +	MsSymbolApplier getSymbolApplier(AbstractMsSymbolIterator iter) throws CancelledException {
     		return symbolApplierParser.getSymbolApplier(iter);
     	}
     
     	//==============================================================================================
     	void procSym(AbstractMsSymbolIterator iter) throws CancelledException {
     		try {
    -			AbstractMsSymbolApplier applier = getSymbolApplier(iter);
    +			MsSymbolApplier applier = getSymbolApplier(iter);
     			applier.apply();
     		}
     		catch (PdbException e) {
    @@ -1216,7 +1241,7 @@ public class PdbApplicator {
     				symbolTable.createNameSpace(parentNamespace, name, SourceType.IMPORTED);
     			}
     		}
    -		catch (Exception e) {
    +		catch (InvalidInputException | DuplicateNameException e) {
     			log.appendMsg("Unable to create class namespace: " + parentNamespace.getName(true) +
     				Namespace.DELIMITER + name + " due to exception: " + e.toString());
     		}
    diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java
    index 0296958d90..dd90917bcc 100644
    --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java
    +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java
    @@ -25,68 +25,70 @@ import ghidra.program.model.listing.Program;
     
     /**
      * Metrics captured during the application of a PDB.  This is a Ghidra class separate from the
    - *  PDB API that we have crafted to help us quantify and qualify the ability apply the PDB
    - *  to a {@link DataTypeManager} and/or {@link Program}. 
    + * PDB API that we have crafted to help us quantify and qualify the ability apply the PDB
    + * to a {@link DataTypeManager} and/or {@link Program}. 
      */
     public class PdbApplicatorMetrics {
     
     	/**
     	 * List of symbols seen (by their ID) as Global symbols.
     	 */
    -	private static Set expectedGlobalSymbols = new HashSet<>();
    -	static {
    +	//@formatter:off
    +	private static final Set expectedGlobalSymbols = Set.of(
     		// AbstractReferenceMsSymbol
    -		expectedGlobalSymbols.add(DataReferenceStMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(DataReferenceMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(LocalProcedureReferenceMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(LocalProcedureReferenceStMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(ProcedureReferenceMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(ProcedureReferenceStMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(AnnotationReferenceMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(TokenReferenceToManagedProcedureMsSymbol.PDB_ID);
    +		DataReferenceStMsSymbol.PDB_ID,
    +		DataReferenceMsSymbol.PDB_ID,
    +		LocalProcedureReferenceMsSymbol.PDB_ID,
    +		LocalProcedureReferenceStMsSymbol.PDB_ID,
    +		ProcedureReferenceMsSymbol.PDB_ID,
    +		ProcedureReferenceStMsSymbol.PDB_ID,
    +		AnnotationReferenceMsSymbol.PDB_ID,
    +		TokenReferenceToManagedProcedureMsSymbol.PDB_ID,
     
     		// AbstractDataMsSymbol
    -		expectedGlobalSymbols.add(GlobalData16MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(GlobalData3216MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(GlobalData32MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(GlobalData32StMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(LocalData16MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(LocalData3216MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(LocalData32MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(LocalData32StMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(GlobalManagedDataMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(GlobalManagedDataStMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(LocalManagedDataMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(LocalManagedDataStMsSymbol.PDB_ID);
    +		GlobalData16MsSymbol.PDB_ID,
    +		GlobalData3216MsSymbol.PDB_ID,
    +		GlobalData32MsSymbol.PDB_ID,
    +		GlobalData32StMsSymbol.PDB_ID,
    +		LocalData16MsSymbol.PDB_ID,
    +		LocalData3216MsSymbol.PDB_ID,
    +		LocalData32MsSymbol.PDB_ID,
    +		LocalData32StMsSymbol.PDB_ID,
    +		GlobalManagedDataMsSymbol.PDB_ID,
    +		GlobalManagedDataStMsSymbol.PDB_ID,
    +		LocalManagedDataMsSymbol.PDB_ID,
    +		LocalManagedDataStMsSymbol.PDB_ID,
     
     		// AbstractUserDefinedTypeMsSymbol
    -		expectedGlobalSymbols.add(CobolUserDefinedType16MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(CobolUserDefinedTypeMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(CobolUserDefinedTypeStMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(UserDefinedType16MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(UserDefinedTypeMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(UserDefinedTypeStMsSymbol.PDB_ID);
    +		CobolUserDefinedType16MsSymbol.PDB_ID,
    +		CobolUserDefinedTypeMsSymbol.PDB_ID,
    +		CobolUserDefinedTypeStMsSymbol.PDB_ID,
    +		UserDefinedType16MsSymbol.PDB_ID,
    +		UserDefinedTypeMsSymbol.PDB_ID,
    +		UserDefinedTypeStMsSymbol.PDB_ID,
     
     		// AbstractConstantMsSymbol
    -		expectedGlobalSymbols.add(Constant16MsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(ConstantMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(ConstantStMsSymbol.PDB_ID);
    -		expectedGlobalSymbols.add(ManagedConstantMsSymbol.PDB_ID);
    -	}
    +		Constant16MsSymbol.PDB_ID,
    +		ConstantMsSymbol.PDB_ID,
    +		ConstantStMsSymbol.PDB_ID,
    +		ManagedConstantMsSymbol.PDB_ID
    +	);
    +	//@formatter:on
     
     	/**
     	 * List of symbols seen (by their ID) as Public symbols.
     	 */
    -	private static Set expectedLinkerSymbols = new HashSet<>();
    -	static {
    -		expectedLinkerSymbols.add(PeCoffSectionMsSymbol.PDB_ID);
    -		expectedLinkerSymbols.add(TrampolineMsSymbol.PDB_ID);
    -		expectedLinkerSymbols.add(ObjectNameMsSymbol.PDB_ID);
    -		expectedLinkerSymbols.add(Compile3MsSymbol.PDB_ID);
    -		expectedLinkerSymbols.add(Compile2MsSymbol.PDB_ID);
    -		expectedLinkerSymbols.add(Compile2StMsSymbol.PDB_ID);
    -		expectedLinkerSymbols.add(EnvironmentBlockMsSymbol.PDB_ID);
    -	}
    +	//@formatter:off
    +	private static final Set expectedLinkerSymbols = Set.of(	
    +		PeCoffSectionMsSymbol.PDB_ID,
    +		TrampolineMsSymbol.PDB_ID,
    +		ObjectNameMsSymbol.PDB_ID,
    +		Compile3MsSymbol.PDB_ID,
    +		Compile2MsSymbol.PDB_ID,
    +		Compile2StMsSymbol.PDB_ID,
    +		EnvironmentBlockMsSymbol.PDB_ID
    +	);
    +	//@formatter:on
     
     	private Set> cannotApplyTypes = new HashSet<>();
     	private Set> unexpectedMemberFunctionThisPointerTypes =
    @@ -104,7 +106,7 @@ public class PdbApplicatorMetrics {
     	 * Method to capture data/item type that cannot be applied.
     	 * @param type The data/item type witnessed.
     	 */
    -	public void witnessCannotApplyDataType(AbstractMsType type) {
    +	void witnessCannotApplyDataType(AbstractMsType type) {
     		cannotApplyTypes.add(type.getClass());
     	}
     
    @@ -112,7 +114,7 @@ public class PdbApplicatorMetrics {
     	 * Method to capture symbol type that cannot be applied.
     	 * @param symbol The symbol type witnessed.
     	 */
    -	public void witnessCannotApplySymbolType(AbstractMsSymbol symbol) {
    +	void witnessCannotApplySymbolType(AbstractMsSymbol symbol) {
     		cannotApplySymbols.add(symbol.getClass());
     	}
     
    @@ -120,7 +122,7 @@ public class PdbApplicatorMetrics {
     	 * Method to capture symbol type that was unexpected as a Global symbol.
     	 * @param symbol The symbol type witnessed.
     	 */
    -	public void witnessGlobalSymbolType(AbstractMsSymbol symbol) {
    +	void witnessGlobalSymbolType(AbstractMsSymbol symbol) {
     		if (!expectedGlobalSymbols.contains(symbol.getPdbId())) {
     			unexpectedGlobalSymbols.add(symbol.getClass());
     		}
    @@ -130,7 +132,7 @@ public class PdbApplicatorMetrics {
     	 * Method to capture symbol type that was unexpected as a Public symbol.
     	 * @param symbol The symbol type witnessed.
     	 */
    -	public void witnessPublicSymbolType(AbstractMsSymbol symbol) {
    +	void witnessPublicSymbolType(AbstractMsSymbol symbol) {
     		if (!(symbol instanceof AbstractPublicMsSymbol)) {
     			unexpectedPublicSymbols.add(symbol.getClass());
     		}
    @@ -140,7 +142,7 @@ public class PdbApplicatorMetrics {
     	 * Method to capture symbol type that was unexpected as a Linker symbol.
     	 * @param symbol The symbol type witnessed.
     	 */
    -	public void witnessLinkerSymbolType(AbstractMsSymbol symbol) {
    +	void witnessLinkerSymbolType(AbstractMsSymbol symbol) {
     		if (!expectedLinkerSymbols.contains(symbol.getPdbId())) {
     			// do nothing for now
     		}
    @@ -149,7 +151,7 @@ public class PdbApplicatorMetrics {
     	/**
     	 * Method to capture witnessing of Enumerate narrowing.
     	 */
    -	public void witnessEnumerateNarrowing() {
    +	void witnessEnumerateNarrowing() {
     		witnessEnumerateNarrowing = true;
     	}
     
    @@ -157,7 +159,7 @@ public class PdbApplicatorMetrics {
     	 * Method to capture unusual this pointer types.
     	 * @param applier The {@AbstractMsTypeApplier} for the supposed this pointer.
     	 */
    -	public void witnessMemberFunctionThisPointer(AbstractMsTypeApplier applier) {
    +	void witnessMemberFunctionThisPointer(MsTypeApplier applier) {
     		// We know that we have seen PrimitiveMsTypes that are pointer types.
     		if (applier instanceof PointerTypeApplier) {
     			return;
    @@ -169,7 +171,7 @@ public class PdbApplicatorMetrics {
     	 * Method to capture unusual underlying types for a normal pointer for this pointer.
     	 * @param applier The {@AbstractMsTypeApplier} for the supposed this pointer.
     	 */
    -	public void witnessMemberFunctionThisPointerUnderlyingType(AbstractMsTypeApplier applier) {
    +	void witnessMemberFunctionThisPointerUnderlyingType(MsTypeApplier applier) {
     		if (applier instanceof CompositeTypeApplier) {
     			return;
     		}
    @@ -180,7 +182,7 @@ public class PdbApplicatorMetrics {
     	 * Method to capture unusual containing types for a member function.
     	 * @param applier The {@AbstractMsTypeApplier} for the supposed this pointer.
     	 */
    -	public void witnessMemberFunctionContainingType(AbstractMsTypeApplier applier) {
    +	void witnessMemberFunctionContainingType(MsTypeApplier applier) {
     		if (applier instanceof CompositeTypeApplier) {
     			return;
     		}
    @@ -193,7 +195,7 @@ public class PdbApplicatorMetrics {
     	 * Return some post-processing metrics for applying the PDB
     	 * @return {@link String} of pretty output.
     	 */
    -	public String getPostProcessingReport() {
    +	String getPostProcessingReport() {
     		StringBuilder builder = new StringBuilder();
     		builder.append("===Begin PdbApplicatorMetrics Report===\n");
     		builder.append(reportNonappliableTypes());
    diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java
    index 102532a674..f3a650a0c9 100644
    --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java
    +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java
    @@ -22,7 +22,7 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
      * Ghidra program.  These can be optional values used during our development of this PdbApplicator,
      * and thus might not be found in the finished product.
      */
    -public class PdbApplicatorOptions extends Exception {
    +public class PdbApplicatorOptions {
     
     	private static final boolean defaultApplyCodeScopeBlockComments = false;
     	private static final boolean defaultApplyInstructionLabels = false;
    @@ -110,7 +110,7 @@ public class PdbApplicatorOptions extends Exception {
     
     	/**
     	 * Enable/disable the option to only apply data types (skipping symbol information).
    -	 *  In other words, the default is to apply symbols.
    +	 * In other words, the default is to apply symbols.
     	 * @param applyDataTypesOnly {@code true} to turn applyDataTypesOnly on
     	 */
     	public void setApplyDataTypesOnly(boolean applyDataTypesOnly) {
    @@ -143,7 +143,7 @@ public class PdbApplicatorOptions extends Exception {
     
     	/**
     	 * Enable/disable the option to attempt to map addresses using existing mangled symbols
    -	 *  (typically public symbols).
    +	 * (typically public symbols).
     	 * @param enable {@code true} to turn remapAddressesUsingExistingPublicSymbols on
     	 */
     	public void setRemapAddressUsingExistingPublicMangledSymbols(boolean enable) {
    @@ -160,9 +160,9 @@ public class PdbApplicatorOptions extends Exception {
     
     	/**
     	 * Enable/disable the option to allow another symbol be set to primary when the existing
    -	 *  primary symbol is a mangled symbol, regardless of the Symbol SourceType.  This is
    -	 *  typically used when we can get better data type information from the PDB record than
    -	 *  we can from the demangler.
    +	 * primary symbol is a mangled symbol, regardless of the Symbol SourceType.  This is
    +	 * typically used when we can get better data type information from the PDB record than
    +	 * we can from the demangler.
     	 * @param enable {@code true} to turn allowDemotePrimaryMangledSymbol on
     	 */
     	public void setAllowDemotePrimaryMangledSymbol(boolean enable) {
    @@ -179,7 +179,7 @@ public class PdbApplicatorOptions extends Exception {
     
     	/**
     	 * Enable/disable the option to apply function params and locals, which might produce improper
    -	 *  results.
    +	 * results.
     	 * @param applyFunctionVariables {@code true} to turn applyPublicSymbolsOnly on
     	 */
     	public void setApplyFunctionVariables(boolean applyFunctionVariables) {
    diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java
    index b02ce78f43..a9aadbaeaa 100644
    --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java
    +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbPrimitiveTypeApplicator.java
    @@ -24,7 +24,7 @@ import ghidra.util.exception.AssertException;
     
     /**
      * Takes care of allocating unique instances of primitive data types for the {@link PdbApplicator},
    - *  and is used principally by the many instances of {@link PrimitiveTypeApplier}.
    + * and is used principally by the many instances of {@link PrimitiveTypeApplier}.
      */
     public class PdbPrimitiveTypeApplicator {
     
    diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java
    index 0e91814602..0d66a4df6f 100644
    --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java
    +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java
    @@ -28,12 +28,13 @@ import ghidra.util.Msg;
     public class PdbRegisterNameToProgramRegisterMapper {
     
     	// Only need to map names that are different (probably not counting case, as rsp and RSP
    -	//  are equivalent.
    -	private static Map registerNameMap = new HashMap<>();
    -	static {
    -		//registerNameMap.put("rsp", "RSP");
    -		registerNameMap.put("fbp", "RBP");
    -	}
    +	// are equivalent.
    +	//@formatter:off
    +	private static Map registerNameMap = Map.of(
    +		//"rsp", "RSP",
    +		"fbp", "RBP"
    +	);
    +	//@formatter:on
     
     	private Program program;
     	private Map pdbRegisterNameToRegisterMap;
    diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java
    index 961db15a91..0a64a64229 100644
    --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java
    +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java
    @@ -31,13 +31,24 @@ import ghidra.util.task.TaskMonitor;
     import mdemangler.*;
     import mdemangler.object.MDObjectCPP;
     
    +/**
    + * This is a class for develop research into various areas.  Anything in this class that needs to
    + * end up as part of any usable output should be moved into another class.  This class just
    + * aggregates various items being investigated, and will eventually be eliminated from the code
    + * base.
    + */
     public class PdbResearch {
     
     	//==============================================================================================
     	private static Set debugIndexNumbers;
     
     	//==============================================================================================
    -	static void initCheckBreak() {
    +	/**
    +	 * This method is used to populate debugIndexNumbers set that gets used by
    +	 * {@link #checkBreak(int recordNumber)} in which we set a breakpoint on {@code int a = 1;} to
    +	 * then allow us to debug into other code.
    +	 */
    +	static void initBreakPointRecordNumbers() {
     		debugIndexNumbers = new TreeSet<>();
     
     		debugIndexNumbers.add(12527);
    @@ -278,7 +289,14 @@ public class PdbResearch {
     
     	/**
     	 * Developmental method for breakpoints.  TODO: will delete this from production.
    -	 * @param recordNumber tmp (set negative to ignore)
    +	 * Set breakpoint on {@code int a = 1;}
    +	 * @param recordNumber the record number tha is being processed (set negative to ignore)
    +	 * 

    + * This code is useful for developer debugging because the PDB is records-based and we often + * need to set breakpoints elsewhere, determine what RecordNumber we are interested in, and + * then use this method to set a breakpoint to catch when the record number is being seen + * earlier in the state of processing. The numbers in {@link #debugIndexNumbers} is set + * by {@link #initBreakPointRecordNumbers()}. */ static void checkBreak(int recordNumber) { if (debugIndexNumbers.contains(recordNumber)) { @@ -289,10 +307,11 @@ public class PdbResearch { /** * Developmental method for breakpoints. TODO: will delete this from production. - * @param recordNumber tmp (set negative to ignore) - * @param applier tmp + * @param recordNumber the record number tha is being processed (set negative to ignore) + * @param applier the applier that might have additional, such as the name of the type of + * interest */ - static void checkBreak(int recordNumber, AbstractMsTypeApplier applier) { + static void checkBreak(int recordNumber, MsTypeApplier applier) { String nn = applier.getMsType().getName(); if ("std::__1::__map_value_compare,std::__1::__value_type,std::__1::basic_string >,std::__1::less,1>".equals( @@ -341,7 +360,7 @@ public class PdbResearch { initDeveloperOrderRecordNumbers(); for (int indexNumber : developerDebugOrderIndexNumbers) { monitor.checkCanceled(); - AbstractMsTypeApplier applier = + MsTypeApplier applier = applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); applier.apply(); } @@ -376,10 +395,10 @@ public class PdbResearch { return false; } AbstractMsSymbol symbol = iter.peek(); //temporary during development - AbstractMsSymbolApplier applier = applicator.getSymbolApplier(iter); + MsSymbolApplier applier = applicator.getSymbolApplier(iter); if (applier instanceof TypedefSymbolApplier) { TypedefSymbolApplier typedefApplier = (TypedefSymbolApplier) applier; - AbstractMsTypeApplier typeApplier = + MsTypeApplier typeApplier = applicator.getTypeApplier(typedefApplier.getTypeRecordNumber()); System.out.println("UDT " + typedefApplier.getName() + " depends on " + typeApplier.getMsType().toString()); @@ -394,7 +413,7 @@ public class PdbResearch { } else if (applier instanceof DataSymbolApplier) { DataSymbolApplier dataSymbolApplier = (DataSymbolApplier) applier; - AbstractMsTypeApplier typeApplier = dataSymbolApplier.getTypeApplier(); + MsTypeApplier typeApplier = dataSymbolApplier.getTypeApplier(); childWalkType(moduleNumber, typeApplier); } else if (applier instanceof FunctionSymbolApplier) { @@ -414,7 +433,7 @@ public class PdbResearch { } //============================================================================================== - static private boolean childWalkType(int moduleNumber, AbstractMsTypeApplier applier) { + static private boolean childWalkType(int moduleNumber, MsTypeApplier applier) { int b = 1; b = b + 1; if (applier instanceof AbstractFunctionTypeApplier) { @@ -427,7 +446,8 @@ public class PdbResearch { //============================================================================================== //============================================================================================== //============================================================================================== - static void studyDataTypeConflicts(PdbApplicator applicator, TaskMonitor monitor) { + static void studyDataTypeConflicts(PdbApplicator applicator, TaskMonitor monitor) + throws CancelledException { DataTypeConflictHandler handler = DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER; DataTypeManager dtm = applicator.getDataTypeManager(); @@ -482,7 +502,8 @@ public class PdbResearch { return composite; } - private static void fillComposite(Composite composite, TaskMonitor monitor, DataType extra) { + private static void fillComposite(Composite composite, TaskMonitor monitor, DataType extra) + throws CancelledException { List members = new ArrayList<>(); DefaultTestPdbMember member; int size = 8; @@ -496,14 +517,9 @@ public class PdbResearch { members.add(member); size += extra.getLength(); } - try { - if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, size, members, - msg -> reconstructionWarn(msg), monitor)) { - ((Structure) composite).deleteAll(); - } - } - catch (Exception e) { - Msg.info(null, "Research exception thrown"); + if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, size, members, + msg -> reconstructionWarn(msg), monitor)) { + ((Structure) composite).deleteAll(); } } @@ -674,7 +690,7 @@ public class PdbResearch { !((AbstractPublic32MsSymbol) symbol).isFunction()) { return; } - Address address = applicator.reladdr((AbstractPublicMsSymbol) symbol); + Address address = applicator.getAddress((AbstractPublicMsSymbol) symbol); String name = ((AbstractPublicMsSymbol) symbol).getName(); String demangledName = getDemangledQualifiedName(name); if (demangledName != null) { @@ -689,7 +705,7 @@ public class PdbResearch { private static void processProcedureSymbol(PdbApplicator applicator, Map> map, AbstractMsSymbol symbol) { if (symbol instanceof AbstractProcedureMsSymbol) { - Address address = applicator.reladdr((AbstractProcedureMsSymbol) symbol); + Address address = applicator.getAddress((AbstractProcedureMsSymbol) symbol); String name = ((AbstractProcedureMsSymbol) symbol).getName(); Stuff stuff = new Stuff(symbol, name, What.GLOBAL); addStuff(map, address, stuff); @@ -717,7 +733,7 @@ public class PdbResearch { /** * Gets a demangles the name and returns the qualified name. Returns null if not mangled - * or if error in demangling. + * or if error in demangling. * @param mangledString the mangled string to be decoded * @return the qualified name of the demangled string or null if not mangled or error. */ @@ -772,7 +788,7 @@ public class PdbResearch { //============================================================================================== //============================================================================================== - static void studyCompositeFwdRefDef(AbstractPdb pdb, TaskMonitor monitor) + static void studyCompositeForwardReferenceAndDefinition(AbstractPdb pdb, TaskMonitor monitor) throws CancelledException { int indexNumber = pdb.getTypeProgramInterface().getTypeIndexMin(); int indexLimit = pdb.getTypeProgramInterface().getTypeIndexMaxExclusive(); @@ -793,27 +809,27 @@ public class PdbResearch { MsProperty p; String ps; int c; - boolean isFwdRef = false; + boolean isForwardReference = false; Map> map = new HashMap<>(); if (type instanceof AbstractCompositeMsType) { AbstractCompositeMsType compType = (AbstractCompositeMsType) type; c = compType.getNumElements(); p = compType.getMsProperty(); - isFwdRef = p.isForwardReference(); - if (c == 0 && !isFwdRef) { + isForwardReference = p.isForwardReference(); + if (c == 0 && !isForwardReference) { int a = 1; a = a + 1; // For PDBs that we have looked at, if count is zero - // for a fwdref, then the field list record number is zero; - // if count is zero for a def, then, the field list record + // for a forward reference, then the field list record number is zero; + // if count is zero for a definition, then, the field list record // number refers to an actual field list. - // So... seems we can trust fwdref and ignore count. + // So... seems we can trust forward reference and ignore count. if (compType.getFieldDescriptorListRecordNumber() == RecordNumber.NO_TYPE) { int b = 1; b = b + 1; } } - else if (c != 0 && isFwdRef) { + else if (c != 0 && isForwardReference) { int a = 1; a = a + 1; } @@ -829,7 +845,8 @@ public class PdbResearch { Set set = new HashSet<>(); set.add(ps); map.put(c, set); - PdbLog.message("----------\n" + name + "\n" + c + (isFwdRef ? " fwdref" : "")); + PdbLog.message( + "----------\n" + name + "\n" + c + (isForwardReference ? " fwdref" : "")); //System.out.println("----------\n" + name + "\n" + c); int innerIndexNumber = indexNumber + 1; while (innerIndexNumber < indexLimit) { @@ -840,25 +857,26 @@ public class PdbResearch { String innerName = getSpecialRecordStart(innerType); if (name.equals(innerName)) { covered[innerIndexNumber] = true; - isFwdRef = false; + isForwardReference = false; if (type instanceof AbstractCompositeMsType) { AbstractCompositeMsType compType = (AbstractCompositeMsType) innerType; c = compType.getNumElements(); p = compType.getMsProperty(); - isFwdRef = p.isForwardReference(); - if (c == 0 && !isFwdRef) { + isForwardReference = p.isForwardReference(); + if (c == 0 && !isForwardReference) { // For PDBs that we have looked at, if count is zero - // for a fwdref, then the field list record number is zero; - // if count is zero for a def, then, the field list record - // number refers to an actual field list. - // So... seems we can trust fwdref and ignore count. + // for a forward reference, then the field list record + // number is zero; if count is zero for a definition, then, + // the field list record number refers to an actual field + // list. So... seems we can trust forward reference and + // ignore count. if (compType.getFieldDescriptorListRecordNumber() == RecordNumber.NO_TYPE) { int a = 1; a = a + 1; } } - else if (c != 0 && isFwdRef) { + else if (c != 0 && isForwardReference) { int a = 1; a = a + 1; } @@ -885,8 +903,8 @@ public class PdbResearch { else { message = " <-- repeat"; } - PdbLog.message(c + (isFwdRef ? " fwdref" : "") + message); - if (c == 0 && isFwdRef) { + PdbLog.message(c + (isForwardReference ? " fwdref" : "") + message); + if (c == 0 && isForwardReference) { PdbLog.message("Orig: " + ps + "\nNew: " + psi); } //System.out.println(c + message); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java index ced7569115..ae8bd95b84 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java @@ -33,7 +33,6 @@ import ghidra.util.task.TaskMonitor; /** * Manages virtual base table lookup for PDB classes. */ - public class PdbVbtManager extends VbtManager { Map addressByMangledName; @@ -75,7 +74,7 @@ public class PdbVbtManager extends VbtManager { AbstractPublicMsSymbol pubSymbol = (AbstractPublicMsSymbol) symbol; String name = pubSymbol.getName(); if (name.startsWith("??_8")) { - Address address = applicator.reladdr(pubSymbol); + Address address = applicator.getAddress(pubSymbol); myAddressByMangledName.put(name, address); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java index f0ec178c95..69e2bc01fa 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java @@ -26,10 +26,15 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link PeCoffGroupMsSymbol} symbols. */ -public class PeCoffGroupSymbolApplier extends AbstractMsSymbolApplier { +public class PeCoffGroupSymbolApplier extends MsSymbolApplier { private PeCoffGroupMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public PeCoffGroupSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -41,9 +46,9 @@ public class PeCoffGroupSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { applicator.addMemoryGroupRefinement(symbol); - Address symbolAddress = applicator.reladdr(symbol); + Address symbolAddress = applicator.getAddress(symbol); if (!Address.NO_ADDRESS.equals(symbolAddress)) { boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); String name = symbol.getName(); @@ -59,7 +64,7 @@ public class PeCoffGroupSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java index 1f7f011ce9..31daaea5bf 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffSectionSymbolApplier.java @@ -25,10 +25,15 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link PeCoffSectionMsSymbol} symbols. */ -public class PeCoffSectionSymbolApplier extends AbstractMsSymbolApplier { +public class PeCoffSectionSymbolApplier extends MsSymbolApplier { private PeCoffSectionMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public PeCoffSectionSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -40,7 +45,7 @@ public class PeCoffSectionSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { int sectionNum = symbol.getSectionNumber(); long realAddress = symbol.getRva(); symbol.getLength(); @@ -52,7 +57,7 @@ public class PeCoffSectionSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java index a5944bb518..719dd045aa 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PointerTypeApplier.java @@ -26,43 +26,33 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractPointerMsType} types. */ -public class PointerTypeApplier extends AbstractMsTypeApplier { - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractPointerMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - PointerTypeApplier.class.getSimpleName()); - } - return type; - } +public class PointerTypeApplier extends MsTypeApplier { private boolean isFunctionPointer = false; /** * Constructor for pointer type applier, for transforming a enum into a - * Ghidra DataType. + * Ghidra DataType. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractPointerMsType} to process * @throws IllegalArgumentException Upon invalid arguments. */ - public PointerTypeApplier(PdbApplicator applicator, AbstractMsType msType) + public PointerTypeApplier(PdbApplicator applicator, AbstractPointerMsType msType) throws IllegalArgumentException { - super(applicator, validateType(msType)); + super(applicator, msType); } - public boolean isFunctionPointer() { + boolean isFunctionPointer() { return isFunctionPointer; } @Override - public BigInteger getSize() { + BigInteger getSize() { return ((AbstractPointerMsType) msType).getSize(); } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { if (msType instanceof DummyMsType) { dataType = new PointerDataType(applicator.getDataTypeManager()); } @@ -72,12 +62,12 @@ public class PointerTypeApplier extends AbstractMsTypeApplier { } @Override - public void resolve() { + void resolve() { // Do not resolve pointer types... will be resolved naturally, as needed } - public AbstractMsTypeApplier getUnmodifiedUnderlyingTypeApplier() { - AbstractMsTypeApplier thisUnderlyingTypeApplier = + MsTypeApplier getUnmodifiedUnderlyingTypeApplier() { + MsTypeApplier thisUnderlyingTypeApplier = applicator.getTypeApplier(((AbstractPointerMsType) msType).getUnderlyingRecordNumber()); // TODO: does not recurse below one level of modifiers... consider doing a recursion. @@ -91,7 +81,7 @@ public class PointerTypeApplier extends AbstractMsTypeApplier { } private DataType applyAbstractPointerMsType(AbstractPointerMsType type) { - AbstractMsTypeApplier underlyingApplier = + MsTypeApplier underlyingApplier = applicator.getTypeApplier(type.getUnderlyingRecordNumber()); if (underlyingApplier instanceof ProcedureTypeApplier) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java index 9ea7c26dc9..2deab63405 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PrimitiveTypeApplier.java @@ -17,49 +17,36 @@ package ghidra.app.util.pdb.pdbapplicator; import java.math.BigInteger; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType; import ghidra.program.model.data.DataType; /** * Applier for {@link PrimitiveMsType} types. */ -public class PrimitiveTypeApplier extends AbstractMsTypeApplier { - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof PrimitiveMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - PrimitiveTypeApplier.class.getSimpleName()); - } - return type; - } +public class PrimitiveTypeApplier extends MsTypeApplier { /** * Constructor for primitive type applier, for transforming a primitive into a - * Ghidra DataType. + * Ghidra DataType. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link PrimitiveMsType} to process. - * @throws IllegalArgumentException Upon invalid arguments. */ - public PrimitiveTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); + public PrimitiveTypeApplier(PdbApplicator applicator, PrimitiveMsType msType) { + super(applicator, msType); apply(); // Only apply in constructor for primitives } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.valueOf(((PrimitiveMsType) msType).getTypeSize()); } @Override - public void apply() { + void apply() { dataType = applyPrimitiveMsType((PrimitiveMsType) msType); } - public boolean isNoType() { + boolean isNoType() { return (((PrimitiveMsType) msType).getNumber() == 0); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java index 5d59900bb0..c21e51b9d8 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ProcedureTypeApplier.java @@ -19,7 +19,8 @@ import java.math.BigInteger; 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.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractProcedureMsType; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.CallingConvention; import ghidra.program.model.data.DataType; import ghidra.util.exception.CancelledException; @@ -28,30 +29,20 @@ import ghidra.util.exception.CancelledException; */ public class ProcedureTypeApplier extends AbstractFunctionTypeApplier { - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractProcedureMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - ProcedureTypeApplier.class.getSimpleName()); - } - return type; - } - /** * Constructor for the applicator that applies {@link AbstractProcedureMsType}, - * transforming it into a Ghidra {@link DataType}. + * transforming it into a Ghidra {@link DataType}. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractProcedureMsType} to processes. * @throws IllegalArgumentException Upon invalid arguments. */ - public ProcedureTypeApplier(PdbApplicator applicator, AbstractMsType msType) + public ProcedureTypeApplier(PdbApplicator applicator, AbstractProcedureMsType msType) throws IllegalArgumentException { - super(applicator, validateType(msType)); + super(applicator, msType); } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @@ -76,7 +67,7 @@ public class ProcedureTypeApplier extends AbstractFunctionTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { applyFunction(getCallingConvention(), hasThisPointer()); // AbstractProcedureMsType procType = (AbstractProcedureMsType) msType; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java index 4805f4f0f3..b1a53f5f6c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java @@ -18,25 +18,28 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.List; 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.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; import ghidra.program.model.symbol.Symbol; -import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractPublicMsSymbol} symbols. */ -public class PublicSymbolApplier extends AbstractMsSymbolApplier { +public class PublicSymbolApplier extends MsSymbolApplier { private AbstractPublicMsSymbol symbol; private Address symbolAddress = null; private Address existingSymbolAddress = null; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public PublicSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -48,14 +51,14 @@ public class PublicSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing. } @Override - public void apply() throws CancelledException, PdbException { + void apply() throws CancelledException, PdbException { - symbolAddress = applicator.reladdr(symbol); + symbolAddress = applicator.getAddress(symbol); if (!Address.NO_ADDRESS.equals(symbolAddress)) { if (getName().startsWith("?")) { // mangled... should be unique @@ -79,9 +82,7 @@ public class PublicSymbolApplier extends AbstractMsSymbolApplier { } } else { - String message = "Could not apply symbol at NO_ADDRESS: " + symbol.getName(); - Msg.info(this, message); - PdbLog.message(message); + pdbLogAndInfoMessage(this, "Could not apply symbol at NO_ADDRESS: " + symbol.getName()); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java index 038b6b090c..279a965aae 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ReferenceSymbolApplier.java @@ -25,10 +25,15 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractReferenceMsSymbol} symbols. */ -public class ReferenceSymbolApplier extends AbstractMsSymbolApplier { +public class ReferenceSymbolApplier extends MsSymbolApplier { private AbstractReferenceMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public ReferenceSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -40,12 +45,12 @@ public class ReferenceSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing. } @Override - public void apply() throws CancelledException, PdbException { + void apply() throws CancelledException, PdbException { // Potential recursive call via applicator.procSym(). AbstractMsSymbolIterator refIter = getInitializedReferencedSymbolGroup().iterator(); applicator.procSym(refIter); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java index a11e642686..891216278d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/RegisterRelativeSymbolApplier.java @@ -18,7 +18,6 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.Objects; 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.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractRegisterRelativeAddressMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; @@ -26,16 +25,20 @@ import ghidra.program.model.data.DataType; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.SourceType; -import ghidra.util.Msg; import ghidra.util.exception.*; /** * Applier for {@link AbstractRegisterRelativeAddressMsSymbol} symbols. */ -public class RegisterRelativeSymbolApplier extends AbstractMsSymbolApplier { +public class RegisterRelativeSymbolApplier extends MsSymbolApplier { private AbstractRegisterRelativeAddressMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public RegisterRelativeSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -47,15 +50,13 @@ public class RegisterRelativeSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void apply() throws PdbException, CancelledException { - String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; - Msg.info(this, message); - PdbLog.message(message); + void apply() throws PdbException, CancelledException { + pdbLogAndInfoMessage(this, + "Cannot apply " + this.getClass().getSimpleName() + " directly to program"); } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) - throws PdbException, CancelledException { + void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException { if (!applicator.getPdbApplicatorOptions().applyFunctionVariables()) { return; } @@ -103,7 +104,7 @@ public class RegisterRelativeSymbolApplier extends AbstractMsSymbolApplier { // } int offset = (int) (relativeOffset & 0xffffffffL); - AbstractMsTypeApplier dataTypeApplier = + MsTypeApplier dataTypeApplier = applicator.getTypeApplier(symbol.getTypeRecordNumber()); DataType dt = dataTypeApplier.getDataType(); if (dt != null) { @@ -144,7 +145,7 @@ public class RegisterRelativeSymbolApplier extends AbstractMsSymbolApplier { } } } - catch (Exception e) { + catch (InvalidInputException | DuplicateNameException e) { applicator.appendLogMsg("Unable to create stack variable " + symbol.getName() + " at offset " + offset + " in " + function.getName()); return false; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java index 7c873bb350..e5296b3f92 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java @@ -15,7 +15,8 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import java.util.*; +import java.util.ArrayList; +import java.util.List; import ghidra.app.cmd.comments.SetCommentCmd; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; @@ -31,7 +32,7 @@ import ghidra.util.exception.CancelledException; */ // TODO: Need to evaluate relationship to function symbols. // TODO: Need to create anonymous name for this as a function? -public class SeparatedCodeSymbolApplier extends AbstractMsSymbolApplier { +public class SeparatedCodeSymbolApplier extends MsSymbolApplier { private SeparatedCodeFromCompilerSupportMsSymbol symbol; @@ -43,7 +44,7 @@ public class SeparatedCodeSymbolApplier extends AbstractMsSymbolApplier { private int symbolBlockNestingLevel; private Address currentBlockAddress; - private List allAppliers = new ArrayList<>(); + private List allAppliers = new ArrayList<>(); private static AbstractMsSymbolIterator validateSymbol(AbstractMsSymbolIterator iter) { if (!(iter.peek() instanceof SeparatedCodeFromCompilerSupportMsSymbol)) { @@ -52,13 +53,19 @@ public class SeparatedCodeSymbolApplier extends AbstractMsSymbolApplier { return iter; } + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + * @throws CancelledException upon user cancellation + */ public SeparatedCodeSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) - throws CancelledException, NoSuchElementException { + throws CancelledException { super(applicator, validateSymbol(iter)); symbol = (SeparatedCodeFromCompilerSupportMsSymbol) iter.next(); - specifiedAddress = applicator.reladdr(symbol); + specifiedAddress = applicator.getAddress(symbol); // Make up name. TODO: decide if need better anonymous name craftedName = String.format("CompilerSeparatedCode%s", specifiedAddress); @@ -72,7 +79,7 @@ public class SeparatedCodeSymbolApplier extends AbstractMsSymbolApplier { while (notDone()) { applicator.checkCanceled(); - AbstractMsSymbolApplier applier = applicator.getSymbolApplier(iter); + MsSymbolApplier applier = applicator.getSymbolApplier(iter); if (!(applier instanceof EndSymbolApplier)) { Msg.info(this, "Unexpected applier in " + getClass().getSimpleName() + ": " + applier.getClass().getSimpleName()); @@ -83,17 +90,17 @@ public class SeparatedCodeSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + void manageBlockNesting(MsSymbolApplier applierParam) { beginBlock(specifiedAddress); } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing. } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { // DO NOTHING FOR NOW. TODO: should we have a configuration option? // Note: these comments can be noise in the decompiler an code browser setComments(false); @@ -119,7 +126,7 @@ public class SeparatedCodeSymbolApplier extends AbstractMsSymbolApplier { return (symbolBlockNestingLevel > 0) && iter.hasNext(); } - public int endBlock() { + int endBlock() { if (--symbolBlockNestingLevel < 0) { applicator.appendLogMsg("Block Nesting went negative at " + specifiedAddress); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierFactory.java similarity index 98% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierParser.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierFactory.java index 34008f3304..672e3d7d89 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierParser.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolApplierFactory.java @@ -15,17 +15,19 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import java.util.NoSuchElementException; - import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.util.exception.CancelledException; -public class SymbolApplierParser { +/** + * Pseudo-factory for creating the {@link MsSymbolApplier} for the {@link AbstractMsSymbol} + * indicated by the {@link AbstractMsSymbolIterator}. + */ +public class SymbolApplierFactory { private PdbApplicator applicator; - SymbolApplierParser(PdbApplicator applicator) { + SymbolApplierFactory(PdbApplicator applicator) { this.applicator = applicator; } @@ -34,15 +36,14 @@ public class SymbolApplierParser { // the AbstractMsSymbol (do one for AbstractMsType as well)? Symbols are different in that // we are using SymbolGroup as a member instead of MsType. - AbstractMsSymbolApplier getSymbolApplier(AbstractMsSymbolIterator iter) - throws CancelledException, NoSuchElementException { + MsSymbolApplier getSymbolApplier(AbstractMsSymbolIterator iter) throws CancelledException { AbstractMsSymbol symbol = iter.peek(); if (symbol == null) { applicator.appendLogMsg("PDB Warning: No AbstractMsSymbol"); return null; } - AbstractMsSymbolApplier applier = null; + MsSymbolApplier applier = null; switch (symbol.getPdbId()) { // // 0x0000 block diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java index 70dae55db4..8d6e47a1a9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SymbolGroup.java @@ -23,8 +23,8 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; /** * This class represents a particular group of Symbols that came from the same PDB stream. This - * wraps the internal structure and offers mechanisms for accessing records. It does not map - * directly to an MSFT structure. + * wraps the internal structure and offers mechanisms for accessing records. It does not map + * directly to an MSFT structure. */ public class SymbolGroup { @@ -37,7 +37,7 @@ public class SymbolGroup { * Constructor. The starting offset is set to zero. * @param symbolsByOffset the Map used to initialize the constructor. * @param moduleNumber The Module number corresponding to the initializing Map - * (0 for public/global Map). + * (0 for public/global Map). */ public SymbolGroup(Map symbolsByOffset, int moduleNumber) { this(symbolsByOffset, moduleNumber, 0); @@ -47,7 +47,7 @@ public class SymbolGroup { * Constructor. * @param symbolsByOffset the Map used to initialize the constructor. * @param moduleNumber The Module number corresponding to the initializing Map - * (0 for public/global Map). + * (0 for public/global Map). * @param offset the offset location to start. */ public SymbolGroup(Map symbolsByOffset, int moduleNumber, long offset) { @@ -60,7 +60,7 @@ public class SymbolGroup { * Returns the list of symbols. These may not be in the order that they were seen. * @return the list of symbols. */ - public List getSymbols() { + List getSymbols() { return new ArrayList<>(symbolsByOffset.values()); } @@ -68,7 +68,7 @@ public class SymbolGroup { * Returns the module number. * @return the module number. */ - public int getModuleNumber() { + int getModuleNumber() { return moduleNumber; } @@ -77,7 +77,7 @@ public class SymbolGroup { * Returns the number of symbols. * @return the number of symbols. */ - public int size() { + int size() { return symbolsByOffset.size(); } @@ -85,7 +85,7 @@ public class SymbolGroup { * Returns the list of symbol offsets in the order they were seen. * @return the list of symbol offsets. */ - public List getOrderedOffsets() { + List getOrderedOffsets() { return new ArrayList<>(symbolsByOffset.keySet()); } @@ -93,7 +93,7 @@ public class SymbolGroup { * Returns the set of symbol offsets. * @return the set of symbol offsets. */ - public Set getOffsets() { + Set getOffsets() { return symbolsByOffset.keySet(); } @@ -101,7 +101,7 @@ public class SymbolGroup { * Returns the list of symbols in the order they were seen. * @return the list of symbols. */ - public List getOrderedSymbols() { + List getOrderedSymbols() { List symbols = new ArrayList<>(); for (long offset : offsets) { symbols.add(symbolsByOffset.get(offset)); @@ -144,6 +144,10 @@ public class SymbolGroup { } //============================================================================================== + /** + * Iterator for {@link SymbolGroup} that iterates through {@link AbstractMsSymbol + * AbstractMsSymbols} + */ class AbstractMsSymbolIterator implements Iterator { private int currentIndex; @@ -163,9 +167,10 @@ public class SymbolGroup { } /** - * Peeks at and returns the next symbol without incrementing to the next. If none are left, then throws NoSuchElementException and - * reinitializes the state for a new iteration. - * @see #initGet() + * Peeks at and returns the next symbol without incrementing to the next. If none are + * left, then throws NoSuchElementException and reinitializes the state for a new + * iteration. + * @see #initGet() * @return the next symbol * @throws NoSuchElementException if there are no more elements */ @@ -192,12 +197,12 @@ public class SymbolGroup { /** * Returns the next symbol. If none are left, then throws NoSuchElementException and - * reinitializes the state for a new iteration. - * @see #initGet() + * reinitializes the state for a new iteration. + * @see #initGet() * @return the next symbol * @throws NoSuchElementException if there are no more elements */ - public long getCurrentOffset() { + long getCurrentOffset() { return currentOffset; } @@ -205,7 +210,7 @@ public class SymbolGroup { * Initialized the mechanism for requesting the symbols in sequence. * @see #hasNext() */ - public void initGet() { + void initGet() { currentIndex = 0; } @@ -214,7 +219,7 @@ public class SymbolGroup { * @param offset the offset to which to initialize the mechanism. * @see #hasNext() */ - public void initGetByOffset(long offset) { + void initGetByOffset(long offset) { int index = indexByOffset.get(offset); if (index < 0) { index = 0; @@ -228,7 +233,7 @@ public class SymbolGroup { * Returns the module number. * @return the module number. */ - public int getModuleNumber() { + int getModuleNumber() { return moduleNumber; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java index e267864a89..071aa38239 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java @@ -30,10 +30,15 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link TrampolineMsSymbol} symbols. */ -public class TrampolineSymbolApplier extends AbstractMsSymbolApplier { +public class TrampolineSymbolApplier extends MsSymbolApplier { private TrampolineMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public TrampolineSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -45,16 +50,16 @@ public class TrampolineSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing. } @Override - public void apply() throws CancelledException, PdbException { + void apply() throws CancelledException, PdbException { // We know the size of this trampoline, so use it to restrict the disassembly. - Address symbolAddress = applicator.reladdr(symbol); + Address symbolAddress = applicator.getAddress(symbol); Address targetAddress = - applicator.reladdr(symbol.getSegmentTarget(), symbol.getOffsetTarget()); + applicator.getAddress(symbol.getSegmentTarget(), symbol.getOffsetTarget()); Function target = createNewFunction(targetAddress, 1); Function thunk = createNewFunction(symbolAddress, symbol.getSizeOfThunk()); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierParser.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java similarity index 78% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierParser.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java index e06b1a49a5..dc373dd4d9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierParser.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypeApplierFactory.java @@ -18,23 +18,29 @@ package ghidra.app.util.pdb.pdbapplicator; import java.util.HashMap; import java.util.Map; -import ghidra.app.util.bin.format.pdb2.pdbreader.*; +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.*; -public class TypeApplierParser { +/** + * Pseudo-factory for creating the {@link MsTypeApplier} for the {@link AbstractMsType} + * indicated by the AbstractMsType and also its {@link RecordNumber}. This class also performs + * caching of the applier by its RecordNumber. + */ +public class TypeApplierFactory { private PdbApplicator applicator; - private Map appliersByRecordNumber; + private Map appliersByRecordNumber; - TypeApplierParser(PdbApplicator applicator) { + TypeApplierFactory(PdbApplicator applicator) { this.applicator = applicator; appliersByRecordNumber = new HashMap<>(); } //============================================================================================== - AbstractMsTypeApplier getApplierSpec(RecordNumber recordNumber, - Class expected) throws PdbException { - AbstractMsTypeApplier applier = getTypeApplier(recordNumber); + MsTypeApplier getApplierSpec(RecordNumber recordNumber, Class expected) + throws PdbException { + MsTypeApplier applier = getTypeApplier(recordNumber); if (!expected.isInstance(applier)) { throw new PdbException(applier.getClass().getSimpleName() + " seen where " + expected.getSimpleName() + " expected for record number " + recordNumber); @@ -42,9 +48,9 @@ public class TypeApplierParser { return applier; } - AbstractMsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber, - Class expected) throws PdbException { - AbstractMsTypeApplier applier = getTypeApplier(recordNumber); + MsTypeApplier getApplierOrNoTypeSpec(RecordNumber recordNumber, + Class expected) throws PdbException { + MsTypeApplier applier = getTypeApplier(recordNumber); if (!expected.isInstance(applier)) { if (!(applier instanceof PrimitiveTypeApplier && ((PrimitiveTypeApplier) applier).isNoType())) { @@ -55,8 +61,8 @@ public class TypeApplierParser { return applier; } - AbstractMsTypeApplier getTypeApplier(RecordNumber recordNumber) { - AbstractMsTypeApplier applier = appliersByRecordNumber.get(recordNumber); + MsTypeApplier getTypeApplier(RecordNumber recordNumber) { + MsTypeApplier applier = appliersByRecordNumber.get(recordNumber); if (applier == null) { applier = getTypeApplier(applicator.getPdb().getTypeRecord(recordNumber)); appliersByRecordNumber.put(recordNumber, applier); @@ -65,48 +71,49 @@ public class TypeApplierParser { } //============================================================================================== - AbstractMsTypeApplier getTypeApplier(AbstractMsType type) { + MsTypeApplier getTypeApplier(AbstractMsType type) { if (type == null) { applicator.appendLogMsg("PDB Warning: No AbstractMsType for getTypeApplier"); return null; } - AbstractMsTypeApplier applier = null; + MsTypeApplier applier = null; try { switch (type.getPdbId()) { - case -1: - applier = new PrimitiveTypeApplier(applicator, type); + case -1: // must be careful, as we chose the -1 for PrimitiveMsType + applier = new PrimitiveTypeApplier(applicator, (PrimitiveMsType) type); break; // 0x0000 block case Modifier16MsType.PDB_ID: - applier = new ModifierTypeApplier(applicator, type); + applier = new ModifierTypeApplier(applicator, (Modifier16MsType) type); break; case Pointer16MsType.PDB_ID: - applier = new PointerTypeApplier(applicator, type); + applier = new PointerTypeApplier(applicator, (Pointer16MsType) type); break; case Array16MsType.PDB_ID: - applier = new ArrayTypeApplier(applicator, type); + applier = new ArrayTypeApplier(applicator, (Array16MsType) type); break; case Class16MsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (Class16MsType) type); break; case Structure16MsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (Structure16MsType) type); break; case Union16MsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (Union16MsType) type); break; case Enum16MsType.PDB_ID: - applier = new EnumTypeApplier(applicator, type); + applier = new EnumTypeApplier(applicator, (Enum16MsType) type); break; case Procedure16MsType.PDB_ID: - applier = new ProcedureTypeApplier(applicator, type); + applier = new ProcedureTypeApplier(applicator, (Procedure16MsType) type); break; case MemberFunction16MsType.PDB_ID: - applier = new MemberFunctionTypeApplier(applicator, type); + applier = + new MemberFunctionTypeApplier(applicator, (MemberFunction16MsType) type); break; case VtShapeMsType.PDB_ID: - applier = new VtShapeTypeApplier(applicator, type); + applier = new VtShapeTypeApplier(applicator, (VtShapeMsType) type); break; // case Cobol016MsType.PDB_ID: // // Not evaluated/implemented yet. @@ -150,7 +157,8 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case ArgumentsList16MsType.PDB_ID: - applier = new ArgumentsListTypeApplier(applicator, type); + applier = + new ArgumentsListTypeApplier(applicator, (ArgumentsList16MsType) type); break; // case DefaultArguments16MsType.PDB_ID: // // Not evaluated/implemented yet. @@ -165,7 +173,7 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case Bitfield16MsType.PDB_ID: - applier = new BitfieldTypeApplier(applicator, type); + applier = new BitfieldTypeApplier(applicator, (Bitfield16MsType) type); break; // case MethodList16MsType.PDB_ID: // // Not evaluated/implemented yet. @@ -182,9 +190,9 @@ public class TypeApplierParser { // case DimensionedArrayVarBoundsLowerUpper16MsType.PDB_ID: // // Not evaluated/implemented yet. // break; - case ReferencedSymbolMsType.PDB_ID: - // Not evaluated/implemented yet. - break; +// case ReferencedSymbolMsType.PDB_ID: +// // Not evaluated/implemented yet. +// break; // 0x400 block case BaseClass16MsType.PDB_ID: @@ -197,7 +205,7 @@ public class TypeApplierParser { applier = new BaseClassTypeApplier(applicator, type); break; case EnumerateStMsType.PDB_ID: - applier = new EnumerateTypeApplier(applicator, type); + applier = new EnumerateTypeApplier(applicator, (EnumerateStMsType) type); break; // case FriendFunction16MsType.PDB_ID: // // Not evaluated/implemented yet. @@ -206,7 +214,7 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case Member16MsType.PDB_ID: - applier = new MemberTypeApplier(applicator, type); + applier = new MemberTypeApplier(applicator, (Member16MsType) type); break; // case StaticMember16MsType.PDB_ID: // // Not evaluated/implemented yet. @@ -234,31 +242,32 @@ public class TypeApplierParser { // 0x1000 block case ModifierMsType.PDB_ID: - applier = new ModifierTypeApplier(applicator, type); + applier = new ModifierTypeApplier(applicator, (ModifierMsType) type); break; case PointerMsType.PDB_ID: - applier = new PointerTypeApplier(applicator, type); + applier = new PointerTypeApplier(applicator, (PointerMsType) type); break; case ArrayStMsType.PDB_ID: - applier = new ArrayTypeApplier(applicator, type); + applier = new ArrayTypeApplier(applicator, (ArrayStMsType) type); break; case ClassStMsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (ClassStMsType) type); break; case StructureStMsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (StructureStMsType) type); break; case UnionStMsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (UnionStMsType) type); break; case EnumStMsType.PDB_ID: - applier = new EnumTypeApplier(applicator, type); + applier = new EnumTypeApplier(applicator, (EnumStMsType) type); break; case ProcedureMsType.PDB_ID: - applier = new ProcedureTypeApplier(applicator, type); + applier = new ProcedureTypeApplier(applicator, (ProcedureMsType) type); break; case MemberFunctionMsType.PDB_ID: - applier = new MemberFunctionTypeApplier(applicator, type); + applier = + new MemberFunctionTypeApplier(applicator, (MemberFunctionMsType) type); break; // case Cobol0MsType.PDB_ID: // // Not evaluated/implemented yet. @@ -290,7 +299,7 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case ArgumentsListMsType.PDB_ID: - applier = new ArgumentsListTypeApplier(applicator, type); + applier = new ArgumentsListTypeApplier(applicator, (ArgumentsListMsType) type); break; // case DefaultArgumentsStMsType.PDB_ID: // // Not evaluated/implemented yet. @@ -302,7 +311,7 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case BitfieldMsType.PDB_ID: - applier = new BitfieldTypeApplier(applicator, type); + applier = new BitfieldTypeApplier(applicator, (BitfieldMsType) type); break; // case MethodListMsType.PDB_ID: // // Not evaluated/implemented yet. @@ -337,7 +346,7 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case MemberStMsType.PDB_ID: - applier = new MemberTypeApplier(applicator, type); + applier = new MemberTypeApplier(applicator, (MemberStMsType) type); break; // case StaticMemberStMsType.PDB_ID: // // Not evaluated/implemented yet. @@ -377,22 +386,22 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case EnumerateMsType.PDB_ID: - applier = new EnumerateTypeApplier(applicator, type); + applier = new EnumerateTypeApplier(applicator, (EnumerateMsType) type); break; case ArrayMsType.PDB_ID: - applier = new ArrayTypeApplier(applicator, type); + applier = new ArrayTypeApplier(applicator, (ArrayMsType) type); break; case ClassMsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (ClassMsType) type); break; case StructureMsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (StructureMsType) type); break; case UnionMsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (UnionMsType) type); break; case EnumMsType.PDB_ID: - applier = new EnumTypeApplier(applicator, type); + applier = new EnumTypeApplier(applicator, (EnumMsType) type); break; // case DimensionedArrayMsType.PDB_ID: // // Not evaluated/implemented yet. @@ -410,7 +419,7 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case MemberMsType.PDB_ID: - applier = new MemberTypeApplier(applicator, type); + applier = new MemberTypeApplier(applicator, (MemberMsType) type); break; // case StaticMemberMsType.PDB_ID: // // Not evaluated/implemented yet. @@ -448,7 +457,7 @@ public class TypeApplierParser { // // Not evaluated/implemented yet. // break; case InterfaceMsType.PDB_ID: - applier = new CompositeTypeApplier(applicator, type); + applier = new CompositeTypeApplier(applicator, (InterfaceMsType) type); break; // case BaseInterfaceMsType.PDB_ID: // // Not evaluated/implemented yet. @@ -511,7 +520,7 @@ public class TypeApplierParser { String message = "GhidraException on " + msg + " with PdbId " + type.getPdbId() + ": " + e.getMessage(); applicator.appendLogMsg(message); - PdbLog.message(message); + applicator.pdbLogAndInfoMessage(this, message); } return applier; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java index 5472e23c8b..269feb66da 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java @@ -28,11 +28,16 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractUserDefinedTypeMsSymbol} symbols. */ -public class TypedefSymbolApplier extends AbstractMsSymbolApplier { +public class TypedefSymbolApplier extends MsSymbolApplier { DataType resolvedDataType = null; AbstractUserDefinedTypeMsSymbol udtSymbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public TypedefSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -44,12 +49,12 @@ public class TypedefSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { resolvedDataType = applyUserDefinedTypeMsSymbol(udtSymbol); } @@ -57,7 +62,7 @@ public class TypedefSymbolApplier extends AbstractMsSymbolApplier { * Returns the name. * @return Name. */ - public String getName() { + String getName() { return udtSymbol.getName(); } @@ -65,11 +70,11 @@ public class TypedefSymbolApplier extends AbstractMsSymbolApplier { * Returns the type record number. * @return Type record number. */ - public RecordNumber getTypeRecordNumber() { + RecordNumber getTypeRecordNumber() { return udtSymbol.getTypeRecordNumber(); } - public DataType getResolvedDataType() throws PdbException { + DataType getResolvedDataType() throws PdbException { if (resolvedDataType == null) { throw new PdbException("Data type not resolved"); } @@ -81,7 +86,7 @@ public class TypedefSymbolApplier extends AbstractMsSymbolApplier { String name = symbol.getName(); - AbstractMsTypeApplier applier = applicator.getTypeApplier(symbol.getTypeRecordNumber()); + MsTypeApplier applier = applicator.getTypeApplier(symbol.getTypeRecordNumber()); // TODO:... NOT SURE IF WILL ALWAYS BE A DATATYPE OR WILL BE A VARIABLE OR ???? if (applier == null) { return null; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java index 39a58761f9..420d153bbd 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java @@ -24,9 +24,9 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractBaseClassMsType}, {@link AbstractVirtualBaseClassMsType}, and - * {@link AbstractIndirectVirtualBaseClassMsType} types. + * {@link AbstractIndirectVirtualBaseClassMsType} types. */ -public class UdtSourceLineTypeApplier extends AbstractMsTypeApplier { +public class UdtSourceLineTypeApplier extends MsTypeApplier { private static AbstractMsType validateType(AbstractMsType type) throws IllegalArgumentException { @@ -56,7 +56,7 @@ public class UdtSourceLineTypeApplier extends AbstractMsTypeApplier { // For here, we are only reporting what "we" have, not what the underlying sizes are. // ...and a value of zero is our "don't know" and "not represented" value. @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.ZERO; } @@ -64,7 +64,7 @@ public class UdtSourceLineTypeApplier extends AbstractMsTypeApplier { * Returns the offset of the Base Class within the inheriting class. * @return the offset. */ - public int getLineNumber() { + int getLineNumber() { if (msType instanceof UserDefinedTypeSourceAndLineMsType) { return ((UserDefinedTypeSourceAndLineMsType) msType).getLineNumber(); } @@ -75,7 +75,7 @@ public class UdtSourceLineTypeApplier extends AbstractMsTypeApplier { * Returns the source file name. * @return the source file name. null if problem recovering name. */ - public String getSourceFileName() { + String getSourceFileName() { if (msType instanceof UserDefinedTypeSourceAndLineMsType) { return ((UserDefinedTypeSourceAndLineMsType) msType).getSourceFileName(); } @@ -86,7 +86,7 @@ public class UdtSourceLineTypeApplier extends AbstractMsTypeApplier { * Returns the record number of the UDT. * @return the record number of the UDT. */ - public RecordNumber getUdtRecordNumber() { + RecordNumber getUdtRecordNumber() { if (msType instanceof UserDefinedTypeSourceAndLineMsType) { return ((UserDefinedTypeSourceAndLineMsType) msType).getUdtRecordNumber(); } @@ -94,11 +94,11 @@ public class UdtSourceLineTypeApplier extends AbstractMsTypeApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { String filename = getSourceFileName(); int lineNumber = getLineNumber(); RecordNumber udtRecordNumber = getUdtRecordNumber(); - AbstractMsTypeApplier typeApplier = applicator.getTypeApplier(udtRecordNumber); + MsTypeApplier typeApplier = applicator.getTypeApplier(udtRecordNumber); // do nothing at the moment. applicator.putRecordNumberByFileName(udtRecordNumber, filename); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java index 19f4c3ccda..7efd71a9d6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java @@ -25,9 +25,9 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractVirtualFunctionTablePointerMsType} and - * {@link AbstractVirtualFunctionTablePointerWithOffsetMsType} types. + * {@link AbstractVirtualFunctionTablePointerWithOffsetMsType} types. */ -public class VirtualFunctionTablePointerTypeApplier extends AbstractMsTypeApplier { +public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier { DataType vtShape = null; @@ -44,18 +44,19 @@ public class VirtualFunctionTablePointerTypeApplier extends AbstractMsTypeApplie /** * Constructor for enum type applier, for transforming a enum into a - * Ghidra DataType. + * Ghidra DataType. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link AbstractVirtualFunctionTablePointerMsType} or * {@link AbstractVirtualFunctionTablePointerWithOffsetMsType} to process. * @throws IllegalArgumentException Upon invalid arguments. */ - public VirtualFunctionTablePointerTypeApplier(PdbApplicator applicator, AbstractMsType msType) throws IllegalArgumentException { + public VirtualFunctionTablePointerTypeApplier(PdbApplicator applicator, AbstractMsType msType) + throws IllegalArgumentException { super(applicator, validateType(msType)); } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.valueOf(applicator.getDataOrganization().getPointerSize()); } @@ -63,7 +64,7 @@ public class VirtualFunctionTablePointerTypeApplier extends AbstractMsTypeApplie * Returns the offset of the Virtual Function Table Pointer. * @return Name of the nested type. */ - public int getOffset() { + int getOffset() { if (msType instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType) { return ((AbstractVirtualFunctionTablePointerWithOffsetMsType) msType).getOffset(); } @@ -74,12 +75,12 @@ public class VirtualFunctionTablePointerTypeApplier extends AbstractMsTypeApplie * Returns the name to use. * @return Name of the pointer type. */ - public String getMemberName() { + String getMemberName() { return "VFTablePtr" + getOffset(); } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { if (msType instanceof AbstractVirtualFunctionTablePointerMsType) { dataType = applyPointer( ((AbstractVirtualFunctionTablePointerMsType) msType).getPointerTypeRecordNumber()); @@ -90,9 +91,8 @@ public class VirtualFunctionTablePointerTypeApplier extends AbstractMsTypeApplie } } -// private DataType applyPointer(int pointerTypeIndex) throws PdbException { private DataType applyPointer(RecordNumber pointerTypeRecordNumber) { - AbstractMsTypeApplier rawApplier = applicator.getTypeApplier(pointerTypeRecordNumber); + MsTypeApplier rawApplier = applicator.getTypeApplier(pointerTypeRecordNumber); if (rawApplier instanceof PointerTypeApplier) { return rawApplier.getDataType(); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java index ed541e9dfa..b85b472540 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VtShapeTypeApplier.java @@ -21,7 +21,8 @@ import java.util.List; import ghidra.app.util.bin.format.pdb.DefaultCompositeMember; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.VtShapeDescriptorMsProperty; +import ghidra.app.util.bin.format.pdb2.pdbreader.type.VtShapeMsType; import ghidra.program.model.data.*; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; @@ -29,31 +30,19 @@ import ghidra.util.exception.CancelledException; /** * Applier for {@link VtShapeMsType} types. */ -public class VtShapeTypeApplier extends AbstractMsTypeApplier { - - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof VtShapeMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - VtShapeTypeApplier.class.getSimpleName()); - } - return type; - } +public class VtShapeTypeApplier extends MsTypeApplier { /** * Constructor for vtshape type applier. * @param applicator {@link PdbApplicator} for which this class is working. * @param msType {@link VtShapeMsType} to process. - * @throws IllegalArgumentException Upon invalid arguments. */ - public VtShapeTypeApplier(PdbApplicator applicator, AbstractMsType msType) - throws IllegalArgumentException { - super(applicator, validateType(msType)); + public VtShapeTypeApplier(PdbApplicator applicator, VtShapeMsType msType) { + super(applicator, msType); } @Override - public BigInteger getSize() { + BigInteger getSize() { return BigInteger.valueOf(applicator.getDataOrganization().getPointerSize() * ((VtShapeMsType) msType).getCount()); } @@ -62,12 +51,12 @@ public class VtShapeTypeApplier extends AbstractMsTypeApplier { * Returns the name. * @return the name. */ - public String getName() { + String getName() { return "vtshape_" + index; } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { dataType = createVtShape((VtShapeMsType) msType); } @@ -78,7 +67,7 @@ public class VtShapeTypeApplier extends AbstractMsTypeApplier { // TODO: what are correct/appropriate CategoryPath and name StructureDataType shape = new StructureDataType(applicator.getAnonymousTypesCategory(), "vtshape" + index, 0, applicator.getDataTypeManager()); - List members = new ArrayList<>(); + List members = new ArrayList<>(); int offset = 0; for (VtShapeDescriptorMsProperty descriptor : list) { switch (descriptor) { @@ -90,8 +79,8 @@ public class VtShapeTypeApplier extends AbstractMsTypeApplier { case NEAR32: case FAR32: Pointer pointer = new PointerDataType(applicator.getDataTypeManager()); - Default2PdbMember member = - new Default2PdbMember(applicator, "", pointer, offset); + DefaultPdbUniversalMember member = + new DefaultPdbUniversalMember(applicator, "", pointer, offset); offset += pointer.getLength(); members.add(member); break; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java index d8d00577f8..524fc8e150 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/WithSymbolApplier.java @@ -16,24 +16,27 @@ package ghidra.app.util.pdb.pdbapplicator; 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.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractWithMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; -import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; /** * Applier for {@link AbstractWithMsSymbol} symbols. This is not fully implemented - * because we do not know its usage or have examples, but we have implemented - * the block management portion. + * because we do not know its usage or have examples, but we have implemented + * the block management portion. */ -public class WithSymbolApplier extends AbstractMsSymbolApplier { +public class WithSymbolApplier extends MsSymbolApplier { private AbstractWithMsSymbol symbol; + /** + * Constructor + * @param applicator the {@link PdbApplicator} for which we are working. + * @param iter the Iterator containing the symbol sequence being processed + */ public WithSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); AbstractMsSymbol abstractSymbol = iter.next(); @@ -45,23 +48,22 @@ public class WithSymbolApplier extends AbstractMsSymbolApplier { } @Override - public void apply() throws PdbException, CancelledException { + void apply() throws PdbException, CancelledException { // TODO: We do not know if this can be applied to a program or not. We have no examples. - String message = "Cannot apply " + this.getClass().getSimpleName() + " directly to program"; - Msg.info(this, message); - PdbLog.message(message); + pdbLogAndInfoMessage(this, + "Cannot apply " + this.getClass().getSimpleName() + " directly to program"); } @Override - public void applyTo(AbstractMsSymbolApplier applyToApplier) { + void applyTo(MsSymbolApplier applyToApplier) { // Do nothing } @Override - public void manageBlockNesting(AbstractMsSymbolApplier applierParam) { + void manageBlockNesting(MsSymbolApplier applierParam) { if (applierParam instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; - Address address = applicator.reladdr(symbol); + Address address = applicator.getAddress(symbol); // TODO: not sure if getExpression() is correct, but there is no "name." functionSymbolApplier.beginBlock(address, symbol.getExpression(), symbol.getLength()); } diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java index 5fefcebdac..74d8b61922 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java @@ -52,8 +52,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { private static VbtManager vbtManager32; private static VbtManager vbtManager64; // Note: Currently all test have expected results based on up the COMPLEX layout. - private static CompositeLayoutMode layoutOptions = - CompositeLayoutMode.COMPLEX; + private static CompositeLayoutMode layoutOptions = CompositeLayoutMode.COMPLEX; static { BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl(); @@ -277,6 +276,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { preparer32.addIntegers(new int[] { 0, 12 }); preparer64.addIntegers(new int[] { 0, 20 }); + // TODO: do not delete... these are for future use. // vbtSymbols.add("??_8GX1@@7B@"); // preparer32.addIntegers(new int[] { 0, 4 }); // preparer64.addIntegers(new int[] { 0, 8}); @@ -500,8 +500,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { builder.append('V'); break; default: - Msg.error(null, "Cannot handle type during testing" + type); - assert false; + String msg = "Cannot handle type during testing" + type; + Msg.error(null, msg); + throw new AssertException(msg); } builder.append(className); builder.append("@@"); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java index b2d43790cb..17b855a6a4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/SymbolPathParser.java @@ -47,6 +47,8 @@ public class SymbolPathParser { } // if (name.indexOf(Namespace.DELIMITER) == -1) { // following is temporary kludge due to struct (blah). TODO: figure/fix + // This particular test for starting with the open parenthesis is to work around a type + // seen in "Rust." if (name.startsWith("(") || name.indexOf(Namespace.DELIMITER) == -1) { List list = new ArrayList<>(); list.add(name); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockStub.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockStub.java index 83fec861ba..72f4471bb6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockStub.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlockStub.java @@ -28,6 +28,17 @@ import ghidra.util.exception.DuplicateNameException; * be overridden so it can provide its own test implementation and return value. */ public class MemoryBlockStub implements MemoryBlock { + Address start; + Address end; + + public MemoryBlockStub() { + this(Address.NO_ADDRESS, Address.NO_ADDRESS); + } + + public MemoryBlockStub(Address start, Address end) { + this.start = start; + this.end = end; + } @Override public int compareTo(MemoryBlock o) { @@ -51,12 +62,12 @@ public class MemoryBlockStub implements MemoryBlock { @Override public Address getStart() { - throw new UnsupportedOperationException(); + return start; } @Override public Address getEnd() { - throw new UnsupportedOperationException(); + return end; } @Override @@ -131,7 +142,7 @@ public class MemoryBlockStub implements MemoryBlock { @Override public boolean isOverlay() { - throw new UnsupportedOperationException(); + return false; } @Override @@ -176,7 +187,7 @@ public class MemoryBlockStub implements MemoryBlock { @Override public MemoryBlockType getType() { - throw new UnsupportedOperationException(); + return MemoryBlockType.DEFAULT; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryStub.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryStub.java index b0a30f33fe..2e2d008d4d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryStub.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryStub.java @@ -32,21 +32,22 @@ import ghidra.util.task.TaskMonitor; * for all methods in the Memory interface. Any method that is needed for your test can then * be overridden so it can provide its own test implementation and return value. */ -public class MemoryStub implements Memory { +public class MemoryStub extends AddressSet implements Memory { + byte[] myMemoryBytes; + MemoryBlock myMemoryBlock; - @Override - public boolean contains(Address addr) { - throw new UnsupportedOperationException(); + public MemoryStub() { + this(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }); } - @Override - public boolean contains(Address start, Address end) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean contains(AddressSetView rangeSet) { - throw new UnsupportedOperationException(); + public MemoryStub(byte[] bytes) { + super(); + this.myMemoryBytes = bytes; + AddressSpace space = new GenericAddressSpace("Mem", 32, AddressSpace.TYPE_RAM, 0); + Address start = space.getAddress(0); + Address end = space.getAddress(bytes.length - 1); + addRange(start, end); + myMemoryBlock = new MemoryBlockStub(start, end); } @Override @@ -124,36 +125,11 @@ public class MemoryStub implements Memory { throw new UnsupportedOperationException(); } - @Override - public AddressSet intersect(AddressSetView view) { - throw new UnsupportedOperationException(); - } - - @Override - public AddressSet intersectRange(Address start, Address end) { - throw new UnsupportedOperationException(); - } - - @Override - public AddressSet union(AddressSetView addrSet) { - throw new UnsupportedOperationException(); - } - - @Override - public AddressSet subtract(AddressSetView addrSet) { - throw new UnsupportedOperationException(); - } - @Override public AddressSet xor(AddressSetView addrSet) { throw new UnsupportedOperationException(); } - @Override - public boolean hasSameAddresses(AddressSetView view) { - throw new UnsupportedOperationException(); - } - @Override public AddressRange getFirstRange() { throw new UnsupportedOperationException(); @@ -241,9 +217,8 @@ public class MemoryStub implements Memory { @Override public MemoryBlock createByteMappedBlock(String name, Address start, Address mappedAddress, - long length, ByteMappingScheme byteMappingScheme, boolean overlay) - throws LockException, MemoryConflictException, AddressOverflowException, - IllegalArgumentException { + long length, ByteMappingScheme byteMappingScheme, boolean overlay) throws LockException, + MemoryConflictException, AddressOverflowException, IllegalArgumentException { throw new UnsupportedOperationException(); } From 368476097dbc60926128ddf228587738e0e6ba00 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Sun, 6 Sep 2020 18:35:28 -0400 Subject: [PATCH 03/15] GT-3112 - PDB Universal - caches for unique symbols at address and primary symbols for performance work-around --- .../pdb/pdbapplicator/DataSymbolApplier.java | 11 +- .../pdbapplicator/FunctionSymbolApplier.java | 5 +- .../pdb/pdbapplicator/LabelSymbolApplier.java | 9 +- .../pdb/pdbapplicator/PdbAddressManager.java | 126 +++++++++++-- .../util/pdb/pdbapplicator/PdbApplicator.java | 172 +++++++++++++++++- .../PeCoffGroupSymbolApplier.java | 15 +- .../pdbapplicator/PublicSymbolApplier.java | 65 ++++--- 7 files changed, 339 insertions(+), 64 deletions(-) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java index c97e17e8b6..9acbb9578a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -77,11 +77,12 @@ public class DataSymbolApplier extends MsSymbolApplier { Address symbolAddress = applicator.getAddress(symbol); Address remapAddress = applicator.getRemapAddressByAddress(symbolAddress); RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); - boolean forcePrimary = applicator.shouldForcePrimarySymbol(remapAddress, true); - String name = symbol.getName(); - if (!applicator.createSymbol(remapAddress, name, forcePrimary)) { - applicator.appendLogMsg("Unable to create symbol " + name + " at " + remapAddress); - } +// boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, true); +// String name = symbol.getName(); +// if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { +// applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); +// } + applicator.createSymbolNew(symbolAddress, symbol.getName(), true); createData(remapAddress, typeRecordNumber); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 8207022f71..d06ce3c71e 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -235,8 +235,9 @@ public class FunctionSymbolApplier extends MsSymbolApplier { private boolean applyFunction(Program program, Address address, TaskMonitor monitor) { Listing listing = program.getListing(); - boolean forcePrimary = applicator.shouldForcePrimarySymbol(address, true); - applicator.createSymbol(address, getName(), forcePrimary); +// boolean forcePrimary = applicator.shouldForcePrimarySymbol(address, true); +// applicator.createSymbol(address, getName(), forcePrimary); + applicator.createSymbolNew(address, getName(), true); function = listing.getFunctionAt(address); if (function == null) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java index e815af5a0d..aeac102d78 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java @@ -66,10 +66,11 @@ public class LabelSymbolApplier extends MsSymbolApplier { name = NamespaceUtils.getNamespaceQualifiedName(f, name, true); } } - boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); - if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { - applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); - } +// boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); +// if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { +// applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); +// } + applicator.createSymbolNew(symbolAddress, symbol.getName(), false); } @Override diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index fec645aea0..b1cca8def3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -23,6 +23,8 @@ import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolIterator; import ghidra.util.exception.CancelledException; /** @@ -38,6 +40,20 @@ public class PdbAddressManager { private List memoryGroupRefinement; private List memorySectionRefinement; private List allSegmentsInfo; + + // Map of Address by symbol name... if a name has appeared more than once, then the Address + // is written with Address.NO_ADDRESS to indicate that the name is found at more than one + // address (not unique from the perspective we need of being able to map PDB addresses to + // possibly different addresses (possibly from an application of another PDB with accurate + // public or "unique" symbols). Originally, we were only going to use symbols with mangled + // names, but opened this up to a wider field of symbol names. + private Map addressByPreExistingSymbolName; + // Since we are already visiting all existing symbols, and since it will be quicker to do in + // one pass than to continually request the primary symbol at a particular address (as we + // are also adding more symbols), we will get an initial snapshot of what symbol is primary + // at any particular address before we start adding more. + private Map primarySymbolByAddress; + private Map remapAddressByAddress; private PdbApplicator applicator; @@ -61,9 +77,12 @@ public class PdbAddressManager { memoryGroupRefinement = new ArrayList<>(); memorySectionRefinement = new ArrayList<>(); allSegmentsInfo = new ArrayList<>(); + addressByPreExistingSymbolName = new HashMap<>(); + primarySymbolByAddress = new HashMap<>(); remapAddressByAddress = new HashMap<>(); determineMemoryBlocks(); + mapPreExistingSymbols(); } /** @@ -101,23 +120,29 @@ public class PdbAddressManager { } /** - * Write the mapped address for a query address, where where the mapping is - * derived by using a the address of a PDB symbol as the key and finding the address of - * a symbol in the program of the same "unique" name. This is accomplished using public - * mangled symbols. If the program symbol came from the PDB, then it maps to itself. - * @param address the query address - * @param remapAddress the mapped address + * Returns the primary symbol for the address, as determined at the start of PDB processing + * before apply any PDB symbols. + * @param address the {@link Address} + * @return the primary symbol */ - void putRemapAddressByAddress(Address address, Address remapAddress) { - Address lookup = remapAddressByAddress.get(address); - if (lookup == null) { - remapAddressByAddress.put(address, remapAddress); - } - else if (!lookup.equals(remapAddress) && lookup != badAddress) { - applicator.appendLogMsg("Trying to map a mapped address to a new address... key: " + - address + ", currentMap: " + lookup + ", newMap: " + remapAddress); - remapAddressByAddress.put(address, badAddress); - } + Symbol getPrimarySymbol(Address address) { + return primarySymbolByAddress.get(address); + } + + /** + * Indicate to the {@link PdbAddressManager} that a new symbol with the given name has the + * associated address. This allows the PdbAddressManager to create and organize the + * re-mapped address and supply them. Also returns the address of the pre-existing symbol + * of the same name if the name was unique, otherwise null if it didn't exist or wasn't + * unique. + * @param name the symbol name + * @param address its associated address + * @return the {@link Address} of existing symbol or null + */ + Address witnessSymbolNameAtAddress(String name, Address address) { + Address existingAddress = getAddressByPreExistingSymbolName(name); + putRemapAddressByAddress(address, existingAddress); + return existingAddress; } /** @@ -219,6 +244,75 @@ public class PdbAddressManager { } } + //============================================================================================== + //============================================================================================== + /** + * Filling in the maps as indicated by their descriptions. + * @throws PdbException If Program is null; + */ + private void mapPreExistingSymbols() throws PdbException { + Program program = applicator.getProgram(); + if (program == null) { + throw new PdbException("Program may not be null"); + } + SymbolIterator iter = program.getSymbolTable().getAllSymbols(false); + while (iter.hasNext()) { + Symbol symbol = iter.next(); + String name = symbol.getName(); + Address address = symbol.getAddress(); + Address existingAddress = addressByPreExistingSymbolName.get(name); + if (existingAddress == null) { + addressByPreExistingSymbolName.put(name, address); + } + else if (!existingAddress.equals(address)) { + addressByPreExistingSymbolName.put(name, Address.NO_ADDRESS); + } + if (symbol.isPrimary()) { + primarySymbolByAddress.put(address, symbol); + } + } + } + + /** + * Returns the address for the symbol name. If the symbol name did not exist within the + * program when the list was being populated or if the name was seen at more than one address, + * then null is returned + * @param name the name of the symbol + * @return the address for that name or null + */ + private Address getAddressByPreExistingSymbolName(String name) { + Address address = addressByPreExistingSymbolName.get(name); + // Thin the list of map values we no longer need. This method should only be + // used after the list has been completely populated, and the NO_ADDRESS marker + // was only being used during the method that populated the list to indicate that a + // name was not unique for our needs. + if (address != null && address.equals(Address.NO_ADDRESS)) { + addressByPreExistingSymbolName.remove(name); + return null; + } + return address; + } + + /** + * Write the mapped address for a query address, where where the mapping is + * derived by using a the address of a PDB symbol as the key and finding the address of + * a symbol in the program of the same "unique" name. This is accomplished using public + * mangled symbols. If the program symbol came from the PDB, then it maps to itself. + * @param address the query address + * @param remapAddress the mapped address + */ + private void putRemapAddressByAddress(Address address, Address remapAddress) { + Address lookup = remapAddressByAddress.get(address); + if (lookup == null) { + remapAddressByAddress.put(address, remapAddress); + } + else if (!lookup.equals(remapAddress) && lookup != badAddress) { + applicator.appendLogMsg("Trying to map a mapped address to a new address... key: " + + address + ", currentMap: " + lookup + ", newMap: " + remapAddress); + remapAddressByAddress.put(address, badAddress); + } + } + //============================================================================================== //============================================================================================== /** diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java index f30b6ea142..dae0ed475d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -97,6 +97,8 @@ public class PdbApplicator { } } + long primarySymbolCallCount; + //============================================================================================== private String pdbFilename; private AbstractPdb pdb; @@ -177,6 +179,8 @@ public class PdbApplicator { Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, TaskMonitor monitorParam, MessageLog logParam) throws PdbException, CancelledException { + primarySymbolCallCount = 0; + initializeApplyTo(programParam, dataTypeManagerParam, imageBaseParam, applicatorOptionsParam, monitorParam, logParam); @@ -198,6 +202,7 @@ public class PdbApplicator { String applicatorMetrics = pdbApplicatorMetrics.getPostProcessingReport(); Msg.info(this, applicatorMetrics); PdbLog.message(applicatorMetrics); + Msg.info(this, "Primary Symbol Call Count: " + primarySymbolCallCount); Msg.info(this, "PDB Terminated Normally"); } @@ -798,16 +803,30 @@ public class PdbApplicator { return pdbAddressManager.getAddress(segment, offset); } +// /** +// * Write the mapped address for a query address, where where the mapping is +// * derived by using a the address of a PDB symbol as the key and finding the address of +// * a symbol in the program of the same "unique" name. This is accomplished using public +// * mangled symbols. If the program symbol came from the PDB, then it maps to itself. +// * @param address the query address +// * @param remapAddress the mapped address +// */ +// void putRemapAddressByAddress(Address address, Address remapAddress) { +// pdbAddressManager.putRemapAddressByAddress(address, remapAddress); +// } +// /** - * Write the mapped address for a query address, where where the mapping is - * derived by using a the address of a PDB symbol as the key and finding the address of - * a symbol in the program of the same "unique" name. This is accomplished using public - * mangled symbols. If the program symbol came from the PDB, then it maps to itself. - * @param address the query address - * @param remapAddress the mapped address + * Indicate to the {@link PdbAddressManager} that a new symbol with the given name has the + * associated address. This allows the PdbAddressManager to create and organize the + * re-mapped address and supply them. Also returns the address of the pre-existing symbol + * of the same name if the name was unique, otherwise null if it didn't exist or wasn't + * unique. + * @param name the symbol name + * @param address its associated address + * @return the {@link Address} of existing symbol or null */ - void putRemapAddressByAddress(Address address, Address remapAddress) { - pdbAddressManager.putRemapAddressByAddress(address, remapAddress); + Address witnessSymbolNameAtAddress(String name, Address address) { + return pdbAddressManager.witnessSymbolNameAtAddress(name, address); } /** @@ -1294,6 +1313,7 @@ public class PdbApplicator { //============================================================================================== boolean shouldForcePrimarySymbol(Address address, boolean forceIfMangled) { Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address); + primarySymbolCallCount++; if (primarySymbol != null) { if (primarySymbol.getName().startsWith("?") && forceIfMangled && @@ -1350,4 +1370,140 @@ public class PdbApplicator { return false; } + //============================================================================================== + private static class PrimarySymbolInfo { + private Symbol symbol; + private boolean isNewSymbol; + + private PrimarySymbolInfo(Symbol symbol, boolean isNewSymbol) { + this.symbol = symbol; + this.isNewSymbol = isNewSymbol; + } + + private Symbol getSymbol() { + return symbol; + } + + private boolean canBePrimaryForceOverriddenBy(String newName) { + if (getSource().isLowerPriorityThan(SourceType.IMPORTED)) { + return true; + } + if (isMangled() && !PdbApplicator.isMangled(newName)) { + return true; + } + if (isNewSymbol()) { + return false; + } + return false; + } + + private SourceType getSource() { + return symbol.getSource(); + } + + private boolean isMangled() { + return symbol.getName().startsWith("?"); + } + + private boolean isNewSymbol() { + return isNewSymbol; + } + +// private PrimarySymbolType getPrimaryType() { +// return primaryType; +// } + } + + private Map primarySymbolInfoByAddress = new HashMap<>(); + + //============================================================================================== + Symbol createSymbolNew(Address address, String symbolPathString, + boolean forcePrimaryIfExistingIsMangled) { + + // Must get existing info before creating new symbol, as we do not want "existing" + // to include the new one + PrimarySymbolInfo existingPrimarySymbolInfo = getExistingPrimarySymbolInfo(address); + Symbol newSymbol = createSymbol(address, symbolPathString); + if (newSymbol == null) { + return null; + } + + boolean forcePrimary = false; + if (existingPrimarySymbolInfo != null) { + if (existingPrimarySymbolInfo.canBePrimaryForceOverriddenBy(symbolPathString) && + forcePrimaryIfExistingIsMangled && + applicatorOptions.allowDemotePrimaryMangledSymbol()) { + forcePrimary = true; + } + } + + boolean forcePrimarySucceeded = false; + if (forcePrimary) { + SetLabelPrimaryCmd cmd = new SetLabelPrimaryCmd(address, newSymbol.getName(), + newSymbol.getParentNamespace()); + if (cmd.applyTo(program)) { + forcePrimarySucceeded = true; + } + } + + if (existingPrimarySymbolInfo == null || forcePrimarySucceeded) { + PrimarySymbolInfo primarySymbolInfo = new PrimarySymbolInfo(newSymbol, true); + setExistingPrimarySymbolInfo(address, primarySymbolInfo); + } + + return newSymbol; + } + + private static boolean isMangled(String name) { + return name.startsWith("?"); + } + + private void setExistingPrimarySymbolInfo(Address address, PrimarySymbolInfo info) { + primarySymbolInfoByAddress.put(address, info); + } + + private PrimarySymbolInfo getExistingPrimarySymbolInfo(Address address) { + PrimarySymbolInfo info = primarySymbolInfoByAddress.get(address); + if (info != null) { + return info; + } + //Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address); + Symbol primarySymbol = pdbAddressManager.getPrimarySymbol(address); + + primarySymbolCallCount++; + if (primarySymbol == null || + primarySymbol.getSource().isLowerPriorityThan(SourceType.IMPORTED)) { + return null; + } + info = new PrimarySymbolInfo(primarySymbol, false); + primarySymbolInfoByAddress.put(address, info); + return info; + } + + private Symbol createSymbol(Address address, String symbolPathString) { + Symbol symbol = null; + 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 = SymbolUtilities.createPreferredLabelOrFunctionSymbol(program, address, + namespace, name, SourceType.IMPORTED); + } + catch (InvalidInputException e) { + appendLogMsg("Unable to create symbol " + symbolPathString + " at " + address); + } + return symbol; + } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java index 69e2bc01fa..5efc7793a9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java @@ -50,13 +50,14 @@ public class PeCoffGroupSymbolApplier extends MsSymbolApplier { applicator.addMemoryGroupRefinement(symbol); Address symbolAddress = applicator.getAddress(symbol); if (!Address.NO_ADDRESS.equals(symbolAddress)) { - boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); - String name = symbol.getName(); - symbol.getLength(); - symbol.getCharacteristics(); - if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { - applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); - } +// boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); +// String name = symbol.getName(); +// symbol.getLength(); +// symbol.getCharacteristics(); +// if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { +// applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); +// } + applicator.createSymbolNew(symbolAddress, symbol.getName(), false); } else { // monitor.setMessage("Skipping NO_ADDRESS symbol " + symb.getName() + "..."); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java index b1a53f5f6c..a38469693e 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java @@ -15,14 +15,11 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import java.util.List; - import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.program.model.address.Address; -import ghidra.program.model.symbol.Symbol; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -60,26 +57,50 @@ public class PublicSymbolApplier extends MsSymbolApplier { symbolAddress = applicator.getAddress(symbol); if (!Address.NO_ADDRESS.equals(symbolAddress)) { - - if (getName().startsWith("?")) { // mangled... should be unique - List existingSymbols = - applicator.getProgram().getSymbolTable().getGlobalSymbols(getName()); - if (existingSymbols.size() == 1) { - existingSymbolAddress = existingSymbols.get(0).getAddress(); - applicator.putRemapAddressByAddress(symbolAddress, existingSymbolAddress); - } - else if (existingSymbols.size() == 0) { - String name = symbol.getName(); - if (!applicator.createSymbol(symbolAddress, name, true)) { - applicator.appendLogMsg( - "Unable to create symbol " + name + " at " + symbolAddress); - } - } - else { - applicator.appendLogMsg( - "Unexpected multiple mangled symbols of same name: " + getName()); - } + String name = symbol.getName(); + existingSymbolAddress = applicator.witnessSymbolNameAtAddress(getName(), symbolAddress); + // TODO: Consider... could add restriction of not putting down symbol if it is mangled, + // as this would violate the uniqueness of the symbol... but we would also want to + // know that this situation was being presented. + if (!symbolAddress.equals(existingSymbolAddress)) { +// if (!applicator.createSymbol(symbolAddress, name, true)) { +// applicator.appendLogMsg( +// "Unable to create symbol " + name + " at " + symbolAddress); +// } + // Note: the following does not work because thunks and thunked functions + // end up getting the same name with the way names are currently propagated. + // TODO; consider putting this back in if thunks take into account the fact + // that mangled names should be unique. +// if (name.startsWith("?") && existingSymbolAddress != null) { +// applicator.appendLogMsg("Mangled symbol exists elsewhere. Not placing: " + +// symbolAddress + " " + name); +// } +// else { +// applicator.createSymbolNew(symbolAddress, symbol.getName(), true); +// } + // Just do this instead of the commented-out code trying to avoid duplicate + // mangled names + applicator.createSymbolNew(symbolAddress, symbol.getName(), true); } +// if (name.startsWith("?")) { // mangled... should be unique +// List existingSymbols = +// applicator.getProgram().getSymbolTable().getGlobalSymbols(getName()); +// if (existingSymbols.size() == 1) { +// existingSymbolAddress = existingSymbols.get(0).getAddress(); +// applicator.putRemapAddressByAddress(symbolAddress, existingSymbolAddress); +// } +// else if (existingSymbols.size() == 0) { +// if (!applicator.createSymbol(symbolAddress, name, true)) { +// applicator.appendLogMsg( +// "Unable to create symbol " + name + " at " + symbolAddress); +// } +//// applicator.createSymbolNew(symbolAddress, symbol.getName(), true); +// } +// else { +// applicator.appendLogMsg( +// "Unexpected multiple mangled symbols of same name: " + getName()); +// } +// } } else { pdbLogAndInfoMessage(this, "Could not apply symbol at NO_ADDRESS: " + symbol.getName()); From 9a901ff195da5a02d30c9064b8d50ecb3d881431 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Tue, 8 Sep 2020 12:17:12 -0400 Subject: [PATCH 04/15] GT-3112 - PDB Universal - clean-up from last change. --- .../pdb/pdbapplicator/DataSymbolApplier.java | 7 +-- .../pdbapplicator/FunctionSymbolApplier.java | 4 +- .../pdb/pdbapplicator/LabelSymbolApplier.java | 6 +-- .../pdb/pdbapplicator/PdbAddressManager.java | 2 +- .../util/pdb/pdbapplicator/PdbApplicator.java | 48 +++---------------- .../PeCoffGroupSymbolApplier.java | 9 +--- .../pdbapplicator/PublicSymbolApplier.java | 42 ++-------------- 7 files changed, 15 insertions(+), 103 deletions(-) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java index 9acbb9578a..ed9d544652 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -77,12 +77,7 @@ public class DataSymbolApplier extends MsSymbolApplier { Address symbolAddress = applicator.getAddress(symbol); Address remapAddress = applicator.getRemapAddressByAddress(symbolAddress); RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); -// boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, true); -// String name = symbol.getName(); -// if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { -// applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); -// } - applicator.createSymbolNew(symbolAddress, symbol.getName(), true); + applicator.createSymbol(symbolAddress, symbol.getName(), true); createData(remapAddress, typeRecordNumber); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index d06ce3c71e..95d79a87ac 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -235,9 +235,7 @@ public class FunctionSymbolApplier extends MsSymbolApplier { private boolean applyFunction(Program program, Address address, TaskMonitor monitor) { Listing listing = program.getListing(); -// boolean forcePrimary = applicator.shouldForcePrimarySymbol(address, true); -// applicator.createSymbol(address, getName(), forcePrimary); - applicator.createSymbolNew(address, getName(), true); + applicator.createSymbol(address, getName(), true); function = listing.getFunctionAt(address); if (function == null) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java index aeac102d78..b6884d88ba 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java @@ -66,11 +66,7 @@ public class LabelSymbolApplier extends MsSymbolApplier { name = NamespaceUtils.getNamespaceQualifiedName(f, name, true); } } -// boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); -// if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { -// applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); -// } - applicator.createSymbolNew(symbolAddress, symbol.getName(), false); + applicator.createSymbol(symbolAddress, symbol.getName(), false); } @Override diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index b1cca8def3..c705714710 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -267,7 +267,7 @@ public class PdbAddressManager { else if (!existingAddress.equals(address)) { addressByPreExistingSymbolName.put(name, Address.NO_ADDRESS); } - if (symbol.isPrimary()) { + if (primarySymbolByAddress.get(address) == null && symbol.isPrimary()) { primarySymbolByAddress.put(address, symbol); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java index dae0ed475d..e134e972eb 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -61,6 +61,9 @@ import ghidra.util.task.TaskMonitor; */ public class PdbApplicator { + private static final String THUNK_NAME_PREFIX = "[thunk]:"; + + //============================================================================================== /** * Returns integer value of BigInteger or Integer.MAX_VALUE if does not fit. * @param myApplicator PdbApplicator for which we are working. @@ -97,8 +100,6 @@ public class PdbApplicator { } } - long primarySymbolCallCount; - //============================================================================================== private String pdbFilename; private AbstractPdb pdb; @@ -179,8 +180,6 @@ public class PdbApplicator { Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, TaskMonitor monitorParam, MessageLog logParam) throws PdbException, CancelledException { - primarySymbolCallCount = 0; - initializeApplyTo(programParam, dataTypeManagerParam, imageBaseParam, applicatorOptionsParam, monitorParam, logParam); @@ -202,7 +201,6 @@ public class PdbApplicator { String applicatorMetrics = pdbApplicatorMetrics.getPostProcessingReport(); Msg.info(this, applicatorMetrics); PdbLog.message(applicatorMetrics); - Msg.info(this, "Primary Symbol Call Count: " + primarySymbolCallCount); Msg.info(this, "PDB Terminated Normally"); } @@ -746,15 +744,6 @@ public class PdbApplicator { //============================================================================================== //============================================================================================== DataType resolve(DataType dataType) { - if ("Cr_z_internal_state".equals(dataType.getName())) { - int a = 1; - a = a + 1; - } - if ("z_stream_s".equals(dataType.getName())) { - int a = 1; - a = a + 1; - } - DataType resolved = getDataTypeManager().resolve(dataType, DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER); resolveCount++; @@ -803,18 +792,6 @@ public class PdbApplicator { return pdbAddressManager.getAddress(segment, offset); } -// /** -// * Write the mapped address for a query address, where where the mapping is -// * derived by using a the address of a PDB symbol as the key and finding the address of -// * a symbol in the program of the same "unique" name. This is accomplished using public -// * mangled symbols. If the program symbol came from the PDB, then it maps to itself. -// * @param address the query address -// * @param remapAddress the mapped address -// */ -// void putRemapAddressByAddress(Address address, Address remapAddress) { -// pdbAddressManager.putRemapAddressByAddress(address, remapAddress); -// } -// /** * Indicate to the {@link PdbAddressManager} that a new symbol with the given name has the * associated address. This allows the PdbAddressManager to create and organize the @@ -1313,7 +1290,6 @@ public class PdbApplicator { //============================================================================================== boolean shouldForcePrimarySymbol(Address address, boolean forceIfMangled) { Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address); - primarySymbolCallCount++; if (primarySymbol != null) { if (primarySymbol.getName().startsWith("?") && forceIfMangled && @@ -1331,9 +1307,8 @@ public class PdbApplicator { } //============================================================================================== - private static final String THUNK_NAME_PREFIX = "[thunk]:"; - - boolean createSymbol(Address address, String symbolPathString, boolean forcePrimary) { + @SuppressWarnings("unused") // For method not being called. In process of removing this version + boolean createSymbolOld(Address address, String symbolPathString, boolean forcePrimary) { // storeLabelByAddress(address, symbolPathString); @@ -1380,10 +1355,6 @@ public class PdbApplicator { this.isNewSymbol = isNewSymbol; } - private Symbol getSymbol() { - return symbol; - } - private boolean canBePrimaryForceOverriddenBy(String newName) { if (getSource().isLowerPriorityThan(SourceType.IMPORTED)) { return true; @@ -1408,16 +1379,12 @@ public class PdbApplicator { private boolean isNewSymbol() { return isNewSymbol; } - -// private PrimarySymbolType getPrimaryType() { -// return primaryType; -// } } private Map primarySymbolInfoByAddress = new HashMap<>(); //============================================================================================== - Symbol createSymbolNew(Address address, String symbolPathString, + Symbol createSymbol(Address address, String symbolPathString, boolean forcePrimaryIfExistingIsMangled) { // Must get existing info before creating new symbol, as we do not want "existing" @@ -1467,10 +1434,7 @@ public class PdbApplicator { if (info != null) { return info; } - //Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address); Symbol primarySymbol = pdbAddressManager.getPrimarySymbol(address); - - primarySymbolCallCount++; if (primarySymbol == null || primarySymbol.getSource().isLowerPriorityThan(SourceType.IMPORTED)) { return null; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java index 5efc7793a9..1400e889bf 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java @@ -50,14 +50,7 @@ public class PeCoffGroupSymbolApplier extends MsSymbolApplier { applicator.addMemoryGroupRefinement(symbol); Address symbolAddress = applicator.getAddress(symbol); if (!Address.NO_ADDRESS.equals(symbolAddress)) { -// boolean forcePrimary = applicator.shouldForcePrimarySymbol(symbolAddress, false); -// String name = symbol.getName(); -// symbol.getLength(); -// symbol.getCharacteristics(); -// if (!applicator.createSymbol(symbolAddress, name, forcePrimary)) { -// applicator.appendLogMsg("Unable to create symbol " + name + " at " + symbolAddress); -// } - applicator.createSymbolNew(symbolAddress, symbol.getName(), false); + applicator.createSymbol(symbolAddress, symbol.getName(), false); } else { // monitor.setMessage("Skipping NO_ADDRESS symbol " + symb.getName() + "..."); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java index a38469693e..e53764c595 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java @@ -57,50 +57,16 @@ public class PublicSymbolApplier extends MsSymbolApplier { symbolAddress = applicator.getAddress(symbol); if (!Address.NO_ADDRESS.equals(symbolAddress)) { - String name = symbol.getName(); existingSymbolAddress = applicator.witnessSymbolNameAtAddress(getName(), symbolAddress); // TODO: Consider... could add restriction of not putting down symbol if it is mangled, // as this would violate the uniqueness of the symbol... but we would also want to // know that this situation was being presented. if (!symbolAddress.equals(existingSymbolAddress)) { -// if (!applicator.createSymbol(symbolAddress, name, true)) { -// applicator.appendLogMsg( -// "Unable to create symbol " + name + " at " + symbolAddress); -// } - // Note: the following does not work because thunks and thunked functions - // end up getting the same name with the way names are currently propagated. - // TODO; consider putting this back in if thunks take into account the fact - // that mangled names should be unique. -// if (name.startsWith("?") && existingSymbolAddress != null) { -// applicator.appendLogMsg("Mangled symbol exists elsewhere. Not placing: " + -// symbolAddress + " " + name); -// } -// else { -// applicator.createSymbolNew(symbolAddress, symbol.getName(), true); -// } - // Just do this instead of the commented-out code trying to avoid duplicate - // mangled names - applicator.createSymbolNew(symbolAddress, symbol.getName(), true); + // Note: there might be issues of thunk functions getting the same mangled name + // as thunked functions, which violates the thesis of their being unique. + // TODO: investigate this. + applicator.createSymbol(symbolAddress, symbol.getName(), true); } -// if (name.startsWith("?")) { // mangled... should be unique -// List existingSymbols = -// applicator.getProgram().getSymbolTable().getGlobalSymbols(getName()); -// if (existingSymbols.size() == 1) { -// existingSymbolAddress = existingSymbols.get(0).getAddress(); -// applicator.putRemapAddressByAddress(symbolAddress, existingSymbolAddress); -// } -// else if (existingSymbols.size() == 0) { -// if (!applicator.createSymbol(symbolAddress, name, true)) { -// applicator.appendLogMsg( -// "Unable to create symbol " + name + " at " + symbolAddress); -// } -//// applicator.createSymbolNew(symbolAddress, symbol.getName(), true); -// } -// else { -// applicator.appendLogMsg( -// "Unexpected multiple mangled symbols of same name: " + getName()); -// } -// } } else { pdbLogAndInfoMessage(this, "Could not apply symbol at NO_ADDRESS: " + symbol.getName()); From 630eb6e32eada851b59a01822e17baae20a237e0 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Tue, 8 Sep 2020 12:24:59 -0400 Subject: [PATCH 05/15] GT-3112 - PDB Universal - signature dump in hex --- .../ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java index 3fe420406f..8b8e54e34a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/AbstractPdb.java @@ -619,7 +619,7 @@ public abstract class AbstractPdb implements AutoCloseable { builder.append("\nversionNumber: "); builder.append(versionNumber); builder.append("\nsignature: "); - builder.append(signature); + builder.append(Integer.toHexString(signature)); builder.append("\nage: "); builder.append(age); return builder.toString(); From 6d0d66640b4b0f093c6b7a8b0d561922446bd5e7 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Tue, 8 Sep 2020 19:47:28 -0400 Subject: [PATCH 06/15] GT-3112 - PDB Universal - more review changes --- .../core/analysis/PdbUniversalAnalyzer.java | 43 +- .../AbstractFunctionTypeApplier.java | 6 +- .../pdbapplicator/CompositeTypeApplier.java | 2 +- .../pdb/pdbapplicator/CppCompositeType.java | 53 +- .../pdb/pdbapplicator/NoSymbolApplier.java | 2 +- ...de.java => ObjectOrientedClassLayout.java} | 6 +- ...a => ObjectOrientedClassLayoutChoice.java} | 27 +- .../pdb/pdbapplicator/PdbAddressManager.java | 2 +- .../util/pdb/pdbapplicator/PdbApplicator.java | 4 +- .../pdbapplicator/PdbApplicatorOptions.java | 84 +- .../util/pdb/pdbapplicator/PdbVbtManager.java | 4 +- .../pdbapplicator/TypedefSymbolApplier.java | 4 +- .../UdtSourceLineTypeApplier.java | 22 +- .../util/pdb/pdbapplicator/VbtManager.java | 6 +- ...irtualFunctionTablePointerTypeApplier.java | 2 - .../format/pdb2/pdbreader/PdbByteWriter.java | 7 +- .../pdb2/pdbreader/msf/MsfReaderUnitTest.java | 30 +- .../pdb2/pdbreader/symbol/SymbolsTest.java | 6 +- .../format/pdb2/pdbreader/type/TypesTest.java | 6 +- .../pdbapplicator/CppCompositeTypeTest.java | 865 ++++++++++-------- 20 files changed, 633 insertions(+), 548 deletions(-) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/{OoComponentLayoutMode.java => ObjectOrientedClassLayout.java} (74%) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/{CompositeLayoutMode.java => ObjectOrientedClassLayoutChoice.java} (51%) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java index a15e40590c..8d9e579318 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java @@ -181,11 +181,11 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { "If checked, attempts to apply function parameters and local variables for program functions."; private boolean applyFunctionVariables; - // Sets the composite layout mode. + // Sets the composite layout choice. // Legacy // - similar to existing DIA-based PDB Analyzer, only placing current composite direct // members (none from parent classes. - // Warning: the remaining experimental layout modes may not be kept and are not guaranteed + // Warning: the remaining experimental layout choices may not be kept and are not guaranteed // to result in data types that will be compatible with future Ghidra releases: // Complex with Basic Fallback // - Performs Complex layout, but if the current class has no parent classes, it will not @@ -196,11 +196,11 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { // Complex // - Puts all current class members and 'direct' parents' 'direct' components into an // encapsulating 'direct' container - private static final String OPTION_NAME_COMPOSITE_LAYOUT_MODE = "Composite Layout Mode"; - private static final String OPTION_DESCRIPTION_COMPOSITE_LAYOUT_MODE = - "Legacy mode like original PDB Analyzer. Warning: other modes have no compatibility" + + private static final String OPTION_NAME_COMPOSITE_LAYOUT_CHOICE = "Composite Layout Choice"; + private static final String OPTION_DESCRIPTION_COMPOSITE_LAYOUT_CHOICE = + "Legacy layout like original PDB Analyzer. Warning: other choices have no compatibility" + " guarantee with future Ghidra releases or minor PDB Analyzer changes"; - private CompositeLayoutMode compositeLayoutMode; + private ObjectOrientedClassLayoutChoice compositeLayoutChoice; //============================================================================================== // Additional instance data @@ -397,8 +397,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { OPTION_DESCRIPTION_ALLOW_DEMOTE_MANGLED_PRIMARY); options.registerOption(OPTION_NAME_APPLY_FUNCTION_VARIABLES, applyFunctionVariables, null, OPTION_DESCRIPTION_APPLY_FUNCTION_VARIABLES); - options.registerOption(OPTION_NAME_COMPOSITE_LAYOUT_MODE, compositeLayoutMode, null, - OPTION_DESCRIPTION_COMPOSITE_LAYOUT_MODE); + options.registerOption(OPTION_NAME_COMPOSITE_LAYOUT_CHOICE, compositeLayoutChoice, null, + OPTION_DESCRIPTION_COMPOSITE_LAYOUT_CHOICE); } } @@ -464,8 +464,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { OPTION_NAME_ALLOW_DEMOTE_MANGLED_PRIMARY, allowDemotePrimaryMangledSymbol); applyFunctionVariables = options.getBoolean(OPTION_NAME_APPLY_FUNCTION_VARIABLES, applyFunctionVariables); - compositeLayoutMode = - options.getEnum(OPTION_NAME_COMPOSITE_LAYOUT_MODE, compositeLayoutMode); + compositeLayoutChoice = + options.getEnum(OPTION_NAME_COMPOSITE_LAYOUT_CHOICE, compositeLayoutChoice); } setPdbApplicatorOptions(); } @@ -555,16 +555,17 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { } private void getPdbApplicatorOptions() { - applyCodeScopeBlockComments = pdbApplicatorOptions.applyCodeScopeBlockComments(); - applyDataTypesOnly = pdbApplicatorOptions.applyDataTypesOnly(); - applyPublicSymbolsOnly = pdbApplicatorOptions.applyPublicSymbolsOnly(); + applyCodeScopeBlockComments = PdbApplicatorOptions.DEFAULT_APPLY_CODE_SCOPE_BLOCK_COMMENTS; + applyDataTypesOnly = PdbApplicatorOptions.DEFAULT_APPLY_DATA_TYPES_ONLY; + applyPublicSymbolsOnly = PdbApplicatorOptions.DEFAULT_APPLY_PUBLIC_SYMBOLS_ONLY; - applyInstructionLabels = pdbApplicatorOptions.applyInstructionLabels(); + applyInstructionLabels = PdbApplicatorOptions.DEFAULT_APPLY_INSTRUCTION_LABELS; remapAddressUsingExistingPublicMangledSymbols = - pdbApplicatorOptions.remapAddressUsingExistingPublicMangledSymbols(); - allowDemotePrimaryMangledSymbol = pdbApplicatorOptions.allowDemotePrimaryMangledSymbol(); - applyFunctionVariables = pdbApplicatorOptions.applyFunctionVariables(); - compositeLayoutMode = pdbApplicatorOptions.getCompositeLayoutMode(); + PdbApplicatorOptions.DEFAULT_REMAP_ADDRESSES_USING_EXISTING_SYMBOLS; + allowDemotePrimaryMangledSymbol = + PdbApplicatorOptions.DEFAULT_ALLOW_DEMOTE_PRIMARY_MANGLED_SYMBOLS; + applyFunctionVariables = PdbApplicatorOptions.DEFAULT_APPLY_FUNCTION_VARIABLES; + compositeLayoutChoice = PdbApplicatorOptions.DEFAULT_CLASS_LAYOUT_CHOICE; } private void setPdbApplicatorOptions() { @@ -573,11 +574,11 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { pdbApplicatorOptions.setApplyCodeScopeBlockComments(applyCodeScopeBlockComments); pdbApplicatorOptions.setApplyInstructionLabels(applyInstructionLabels); - pdbApplicatorOptions.setRemapAddressUsingExistingPublicMangledSymbols( + pdbApplicatorOptions.setRemapAddressUsingExistingPublicSymbols( remapAddressUsingExistingPublicMangledSymbols); - pdbApplicatorOptions.setAllowDemotePrimaryMangledSymbol(allowDemotePrimaryMangledSymbol); + pdbApplicatorOptions.setAllowDemotePrimaryMangledSymbols(allowDemotePrimaryMangledSymbol); pdbApplicatorOptions.setApplyFunctionVariables(applyFunctionVariables); - pdbApplicatorOptions.setCompositeLayoutMode(compositeLayoutMode); + pdbApplicatorOptions.setClassLayoutChoice(compositeLayoutChoice); } private boolean confirmDirectory(File path) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java index 009174ddb0..e5e7c459ab 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java @@ -30,9 +30,9 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier { private FunctionDefinitionDataType functionDefinition; private MsTypeApplier returnApplier; - ArgumentsListTypeApplier argsListApplier; - CallingConvention callingConvention; - boolean hasThisPointer; + private ArgumentsListTypeApplier argsListApplier; + private CallingConvention callingConvention; + private boolean hasThisPointer; /** * Constructor for the applicator that applies a "function" type, transforming it into a diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java index 12278282a4..130daaba15 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java @@ -330,7 +330,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { // TODO: Investigate. We should do this check for some classes somewhere. Should // we do it here. Set breakpoint here to investigate. } - classType.createLayout(applicator.getPdbApplicatorOptions().getCompositeLayoutMode(), + classType.createLayout(applicator.getPdbApplicatorOptions().getClassLayoutChoice(), applicator.getVbtManager(), applicator.getCancelOnlyWrappingMonitor()); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java index dab32bcbfa..df7247a2b1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java @@ -51,7 +51,7 @@ public class CppCompositeType { private Composite composite; private CategoryPath categoryPath; - private OoComponentLayoutMode layoutMode = OoComponentLayoutMode.UNKNOWN; + private ObjectOrientedClassLayout classLayout = ObjectOrientedClassLayout.UNKNOWN; private List memberData; @@ -583,30 +583,31 @@ public class CppCompositeType { return builder.toString(); } - public OoComponentLayoutMode getLayoutMode(CompositeLayoutMode layoutOptions) { - if (layoutMode == OoComponentLayoutMode.UNKNOWN) { - layoutMode = determineLayoutMode(layoutOptions); + public ObjectOrientedClassLayout getLayout(ObjectOrientedClassLayoutChoice layoutOptions) { + if (classLayout == ObjectOrientedClassLayout.UNKNOWN) { + classLayout = determineClassLayout(layoutOptions); } - return layoutMode; + return classLayout; } - private OoComponentLayoutMode determineLayoutMode(CompositeLayoutMode layoutOptions) { - OoComponentLayoutMode initialModeDetermination; - if (layoutOptions.getLayoutMode() == OoComponentLayoutMode.MEMBERS_ONLY) { - return OoComponentLayoutMode.MEMBERS_ONLY; + private ObjectOrientedClassLayout determineClassLayout( + ObjectOrientedClassLayoutChoice layoutOptions) { + ObjectOrientedClassLayout initialLayoutDetermination; + if (layoutOptions.getClassLayout() == ObjectOrientedClassLayout.MEMBERS_ONLY) { + return ObjectOrientedClassLayout.MEMBERS_ONLY; } else if (getNumLayoutBaseClasses() == 0) { - initialModeDetermination = OoComponentLayoutMode.BASIC; + initialLayoutDetermination = ObjectOrientedClassLayout.BASIC; } else if (getNumLayoutVirtualBaseClasses() == 0) { - initialModeDetermination = OoComponentLayoutMode.SIMPLE; + initialLayoutDetermination = ObjectOrientedClassLayout.SIMPLE; } else { - initialModeDetermination = OoComponentLayoutMode.COMPLEX; + initialLayoutDetermination = ObjectOrientedClassLayout.COMPLEX; } - OoComponentLayoutMode optionsMode = layoutOptions.getLayoutMode(); - return optionsMode.compareTo(initialModeDetermination) >= 0 ? optionsMode - : initialModeDetermination; + ObjectOrientedClassLayout classLyoutOption = layoutOptions.getClassLayout(); + return classLyoutOption.compareTo(initialLayoutDetermination) >= 0 ? classLyoutOption + : initialLayoutDetermination; } boolean isZeroSize() { @@ -628,7 +629,7 @@ public class CppCompositeType { //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- - public void createLayout(CompositeLayoutMode layoutOptions, VbtManager vbtManager, + public void createLayout(ObjectOrientedClassLayoutChoice layoutOptions, VbtManager vbtManager, TaskMonitor monitor) throws PdbException, CancelledException { if (vbtManager instanceof PdbVbtManager) { // Information from PDB/program symbols // TODO: both same for now @@ -642,11 +643,11 @@ public class CppCompositeType { //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- - public void createVbtBasedLayout(CompositeLayoutMode layoutOptions, VbtManager vbtManager, - TaskMonitor monitor) throws PdbException, CancelledException { + public void createVbtBasedLayout(ObjectOrientedClassLayoutChoice layoutOptions, + VbtManager vbtManager, TaskMonitor monitor) throws PdbException, CancelledException { CategoryPath cn; hasDirect = false; - switch (getLayoutMode(layoutOptions)) { + switch (getLayout(layoutOptions)) { case MEMBERS_ONLY: addLayoutPdbMembers(memberData, layoutMembers); break; @@ -697,7 +698,7 @@ public class CppCompositeType { } directClassLength = getCompositeLength(directDataType); } - if (getLayoutMode(layoutOptions) == OoComponentLayoutMode.SIMPLE) { + if (getLayout(layoutOptions) == ObjectOrientedClassLayout.SIMPLE) { // Not using the dummy/direct type (only used it to get the // directClassLength), so remove it and add the members to the main // type instead. @@ -767,8 +768,8 @@ public class CppCompositeType { //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- - public void createSpeculativeLayout(CompositeLayoutMode layoutOptions, VbtManager vbtManager, - TaskMonitor monitor) throws PdbException, CancelledException { + public void createSpeculativeLayout(ObjectOrientedClassLayoutChoice layoutOptions, + VbtManager vbtManager, TaskMonitor monitor) throws PdbException, CancelledException { // Speculative Layout uses recursion to try to know the order of members. However, MSFT // rearranges the order of the Base Class records such that they are not necessarily in // the order that the class was declared, and it seems that the member order follows the @@ -778,7 +779,7 @@ public class CppCompositeType { // get moved. CategoryPath cn; hasDirect = false; - switch (getLayoutMode(layoutOptions)) { + switch (getLayout(layoutOptions)) { case MEMBERS_ONLY: addLayoutPdbMembers(memberData, layoutMembers); break; @@ -833,7 +834,7 @@ public class CppCompositeType { } directClassLength = getCompositeLength(directDataType); } - if (getLayoutMode(layoutOptions) == OoComponentLayoutMode.SIMPLE) { + if (getLayout(layoutOptions) == ObjectOrientedClassLayout.SIMPLE) { // Not using the dummy/direct type (only used it to get the // directClassLength), so remove it and add the members to the main // type instead. @@ -1348,8 +1349,8 @@ public class CppCompositeType { return attributes; } - OoComponentLayoutMode getLayoutMode(CompositeLayoutMode layoutOptions) { - return baseClassType.getLayoutMode(layoutOptions); + ObjectOrientedClassLayout getLayoutMode(ObjectOrientedClassLayoutChoice layoutOptions) { + return baseClassType.getLayout(layoutOptions); } DataTypePath getDataTypePath() { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java index 4acb99eaca..f12f6a1178 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NoSymbolApplier.java @@ -25,7 +25,7 @@ import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; */ public class NoSymbolApplier extends MsSymbolApplier { - AbstractMsSymbol symbol; + private AbstractMsSymbol symbol; /** * Constructor diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayout.java similarity index 74% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayout.java index f75c0c3fb4..9fc06a52af 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/OoComponentLayoutMode.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayout.java @@ -16,8 +16,10 @@ package ghidra.app.util.pdb.pdbapplicator; /** - * Mode for {@link CppCompositeType} class layout. + * Algorithm layout mechanism being used for a particular {@link CppCompositeType}. An initial + * value gets passed in to the algorithm but can be changed by the algorithm, based on class + * internal data. */ -enum OoComponentLayoutMode { +enum ObjectOrientedClassLayout { UNKNOWN, MEMBERS_ONLY, BASIC, SIMPLE, COMPLEX } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayoutChoice.java similarity index 51% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayoutChoice.java index cfef2c60f9..feea4956c3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeLayoutMode.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayoutChoice.java @@ -19,37 +19,38 @@ import java.util.HashMap; import java.util.Map; /** - * PDB Analyzer Options Mode for performing object-oriented structure layout. + * PDB Analyzer user algorithmic choice for performing object oriented class layout. */ -public enum CompositeLayoutMode { - MEMBERS_ONLY("Legacy", 0, OoComponentLayoutMode.MEMBERS_ONLY), - BASIC_SIMPLE_COMPLEX("Complex with Basic Fallback", 1, OoComponentLayoutMode.BASIC), - SIMPLE_COMPLEX("Complex with Simple Fallback", 2, OoComponentLayoutMode.SIMPLE), - COMPLEX("Complex Always", 3, OoComponentLayoutMode.COMPLEX); +public enum ObjectOrientedClassLayoutChoice { + MEMBERS_ONLY("Legacy", 0, ObjectOrientedClassLayout.MEMBERS_ONLY), + BASIC_SIMPLE_COMPLEX("Complex with Basic Fallback", 1, ObjectOrientedClassLayout.BASIC), + SIMPLE_COMPLEX("Complex with Simple Fallback", 2, ObjectOrientedClassLayout.SIMPLE), + COMPLEX("Complex Always", 3, ObjectOrientedClassLayout.COMPLEX); - private static final Map BY_VALUE = new HashMap<>(); + private static final Map BY_VALUE = new HashMap<>(); static { - for (CompositeLayoutMode val : values()) { + for (ObjectOrientedClassLayoutChoice val : values()) { BY_VALUE.put(val.value, val); } } private final String label; private final int value; - private OoComponentLayoutMode layoutMode; + private ObjectOrientedClassLayout classLayout; @Override public String toString() { return label; } - private CompositeLayoutMode(String label, int value, OoComponentLayoutMode layoutMode) { + private ObjectOrientedClassLayoutChoice(String label, int value, + ObjectOrientedClassLayout classLayout) { this.label = label; this.value = value; - this.layoutMode = layoutMode; + this.classLayout = classLayout; } - OoComponentLayoutMode getLayoutMode() { - return layoutMode; + ObjectOrientedClassLayout getClassLayout() { + return classLayout; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index c705714710..4453964378 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -155,7 +155,7 @@ public class PdbAddressManager { */ Address getRemapAddressByAddress(Address address) { if (!Address.NO_ADDRESS.equals(address) && - applicator.getPdbApplicatorOptions().remapAddressUsingExistingPublicMangledSymbols()) { + applicator.getPdbApplicatorOptions().remapAddressUsingExistingPublicSymbols()) { return remapAddressByAddress.getOrDefault(address, address); } return address; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java index e134e972eb..a00fffc254 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -1293,7 +1293,7 @@ public class PdbApplicator { if (primarySymbol != null) { if (primarySymbol.getName().startsWith("?") && forceIfMangled && - applicatorOptions.allowDemotePrimaryMangledSymbol()) { + applicatorOptions.allowDemotePrimaryMangledSymbols()) { return true; } @@ -1399,7 +1399,7 @@ public class PdbApplicator { if (existingPrimarySymbolInfo != null) { if (existingPrimarySymbolInfo.canBePrimaryForceOverriddenBy(symbolPathString) && forcePrimaryIfExistingIsMangled && - applicatorOptions.allowDemotePrimaryMangledSymbol()) { + applicatorOptions.allowDemotePrimaryMangledSymbols()) { forcePrimary = true; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java index f3a650a0c9..44d71d276b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java @@ -24,24 +24,24 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb; */ public class PdbApplicatorOptions { - private static final boolean defaultApplyCodeScopeBlockComments = false; - private static final boolean defaultApplyInstructionLabels = false; - private static final boolean defaultApplyDataTypesOnly = false; - private static final boolean defaultApplyPublicSymbolsOnly = false; - private static final boolean defaultRemapAddressesUsingExistingPublicSymbols = false; - private static final boolean defaultAllowDemotePrimaryMangledSymbol = true; + public static final boolean DEFAULT_APPLY_CODE_SCOPE_BLOCK_COMMENTS = false; + public static final boolean DEFAULT_APPLY_INSTRUCTION_LABELS = false; + public static final boolean DEFAULT_APPLY_DATA_TYPES_ONLY = false; + public static final boolean DEFAULT_APPLY_PUBLIC_SYMBOLS_ONLY = false; + public static final boolean DEFAULT_REMAP_ADDRESSES_USING_EXISTING_SYMBOLS = false; + public static final boolean DEFAULT_ALLOW_DEMOTE_PRIMARY_MANGLED_SYMBOLS = true; // TODO: set the following to true if we come up with a reasonably good solution - private static final boolean defaultApplyFunctionVariables = false; + public static final boolean DEFAULT_APPLY_FUNCTION_VARIABLES = false; - private static final CompositeLayoutMode defaultCompositeLayoutMode = - CompositeLayoutMode.MEMBERS_ONLY; -// private static final CompositeLayoutMode defaultCompositeLayoutMode = -// CompositeLayoutMode.BASIC_SIMPLE_COMPLEX; -// private static final CompositeLayoutMode defaultCompositeLayoutMode = -// CompositeLayoutMode.SIMPLE_COMPLEX; -// private static final CompositeLayoutMode defaultCompositeLayoutMode = -// CompositeLayoutMode.COMPLEX; + public static final ObjectOrientedClassLayoutChoice DEFAULT_CLASS_LAYOUT_CHOICE = + ObjectOrientedClassLayoutChoice.MEMBERS_ONLY; +// public static final OjbectOrientedClassLayoutChoice DEFAULT_CLASS_LAYOUT_CHOICE = +// OjbectOrientedClassLayoutChoice.BASIC_SIMPLE_COMPLEX; +// public static final OjbectOrientedClassLayoutChoice DEFAULT_CLASS_LAYOUT_CHOICE = +// OjbectOrientedClassLayoutChoice.SIMPLE_COMPLEX; +// public static final OjbectOrientedClassLayoutChoice DEFAULT_CLASS_LAYOUT_CHOICE = +// OjbectOrientedClassLayoutChoice.COMPLEX; //============================================================================================== private boolean applyCodeScopeBlockComments; @@ -49,11 +49,11 @@ public class PdbApplicatorOptions { private boolean applyDataTypesOnly; private boolean applyPublicSymbolsOnly; private boolean remapAddressesUsingExistingPublicSymbols; - private boolean allowDemotePrimaryMangledSymbol; + private boolean allowDemotePrimaryMangledSymbols; private boolean applyFunctionVariables; // investigation. might produce bad results. - private CompositeLayoutMode compositeLayoutMode; + private ObjectOrientedClassLayoutChoice classLayoutChoice; /** * Constructor @@ -66,14 +66,14 @@ public class PdbApplicatorOptions { * Set the options back to their default values */ public void setDefaults() { - applyCodeScopeBlockComments = defaultApplyCodeScopeBlockComments; - applyInstructionLabels = defaultApplyInstructionLabels; - applyDataTypesOnly = defaultApplyDataTypesOnly; - applyPublicSymbolsOnly = defaultApplyPublicSymbolsOnly; - remapAddressesUsingExistingPublicSymbols = defaultRemapAddressesUsingExistingPublicSymbols; - allowDemotePrimaryMangledSymbol = defaultAllowDemotePrimaryMangledSymbol; - applyFunctionVariables = defaultApplyFunctionVariables; - compositeLayoutMode = defaultCompositeLayoutMode; + applyCodeScopeBlockComments = DEFAULT_APPLY_CODE_SCOPE_BLOCK_COMMENTS; + applyInstructionLabels = DEFAULT_APPLY_INSTRUCTION_LABELS; + applyDataTypesOnly = DEFAULT_APPLY_DATA_TYPES_ONLY; + applyPublicSymbolsOnly = DEFAULT_APPLY_PUBLIC_SYMBOLS_ONLY; + remapAddressesUsingExistingPublicSymbols = DEFAULT_REMAP_ADDRESSES_USING_EXISTING_SYMBOLS; + allowDemotePrimaryMangledSymbols = DEFAULT_ALLOW_DEMOTE_PRIMARY_MANGLED_SYMBOLS; + applyFunctionVariables = DEFAULT_APPLY_FUNCTION_VARIABLES; + classLayoutChoice = DEFAULT_CLASS_LAYOUT_CHOICE; } /** @@ -146,7 +146,7 @@ public class PdbApplicatorOptions { * (typically public symbols). * @param enable {@code true} to turn remapAddressesUsingExistingPublicSymbols on */ - public void setRemapAddressUsingExistingPublicMangledSymbols(boolean enable) { + public void setRemapAddressUsingExistingPublicSymbols(boolean enable) { this.remapAddressesUsingExistingPublicSymbols = enable; } @@ -154,7 +154,7 @@ public class PdbApplicatorOptions { * Returns {@code true} if remapAddressesUsingExistingPublicSymbols is "on." * @return {@code true} if remapAddressesUsingExistingPublicSymbols is "on." */ - public boolean remapAddressUsingExistingPublicMangledSymbols() { + public boolean remapAddressUsingExistingPublicSymbols() { return remapAddressesUsingExistingPublicSymbols; } @@ -163,18 +163,18 @@ public class PdbApplicatorOptions { * primary symbol is a mangled symbol, regardless of the Symbol SourceType. This is * typically used when we can get better data type information from the PDB record than * we can from the demangler. - * @param enable {@code true} to turn allowDemotePrimaryMangledSymbol on + * @param enable {@code true} to turn allowDemotePrimaryMangledSymbols on */ - public void setAllowDemotePrimaryMangledSymbol(boolean enable) { - this.allowDemotePrimaryMangledSymbol = enable; + public void setAllowDemotePrimaryMangledSymbols(boolean enable) { + this.allowDemotePrimaryMangledSymbols = enable; } /** - * Returns {@code true} if allowDemotePrimaryMangledSymbol is "on." - * @return {@code true} if allowDemotePrimaryMangledSymbol is "on." + * Returns {@code true} if allowDemotePrimaryMangledSymbols is "on." + * @return {@code true} if allowDemotePrimaryMangledSymbols is "on." */ - public boolean allowDemotePrimaryMangledSymbol() { - return allowDemotePrimaryMangledSymbol; + public boolean allowDemotePrimaryMangledSymbols() { + return allowDemotePrimaryMangledSymbols; } /** @@ -195,19 +195,19 @@ public class PdbApplicatorOptions { } /** - * Set the CompositeLayoutMode. - * @param compositeLayoutMode composite layout mode + * Set the class layout. + * @param classLayoutChoice composite layout choice */ - public void setCompositeLayoutMode(CompositeLayoutMode compositeLayoutMode) { - this.compositeLayoutMode = compositeLayoutMode; + public void setClassLayoutChoice(ObjectOrientedClassLayoutChoice classLayoutChoice) { + this.classLayoutChoice = classLayoutChoice; } /** - * Returns the mode for physically layout out composites. - * @return the layout mode. + * Returns the choice for physically layout out classes. + * @return the class layout. */ - public CompositeLayoutMode getCompositeLayoutMode() { - return compositeLayoutMode; + public ObjectOrientedClassLayoutChoice getClassLayoutChoice() { + return classLayoutChoice; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java index ae8bd95b84..9b15d2d24b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java @@ -35,8 +35,8 @@ import ghidra.util.task.TaskMonitor; */ public class PdbVbtManager extends VbtManager { - Map addressByMangledName; - Memory memory; + private Map addressByMangledName; + private Memory memory; private static Memory getMemory(PdbApplicator applicator) throws PdbException { Program program = applicator.getProgram(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java index 269feb66da..91b79724f6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TypedefSymbolApplier.java @@ -30,8 +30,8 @@ import ghidra.util.exception.CancelledException; */ public class TypedefSymbolApplier extends MsSymbolApplier { - DataType resolvedDataType = null; - AbstractUserDefinedTypeMsSymbol udtSymbol; + private DataType resolvedDataType = null; + private AbstractUserDefinedTypeMsSymbol udtSymbol; /** * Constructor diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java index 420d153bbd..14ef2af0f5 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/UdtSourceLineTypeApplier.java @@ -28,17 +28,6 @@ import ghidra.util.exception.CancelledException; */ public class UdtSourceLineTypeApplier extends MsTypeApplier { - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof UserDefinedTypeSourceAndLineMsType) && - !(type instanceof UserDefinedTypeModuleSourceAndLineMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - UdtSourceLineTypeApplier.class.getSimpleName()); - } - return type; - } - /** * Constructor for base class applier. * @param applicator {@link PdbApplicator} for which this class is working. @@ -109,4 +98,15 @@ public class UdtSourceLineTypeApplier extends MsTypeApplier { } } + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof UserDefinedTypeSourceAndLineMsType) && + !(type instanceof UserDefinedTypeModuleSourceAndLineMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + UdtSourceLineTypeApplier.class.getSimpleName()); + } + return type; + } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VbtManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VbtManager.java index 3ba310a56e..4b4d83180d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VbtManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VbtManager.java @@ -29,9 +29,9 @@ import ghidra.util.Msg; */ public class VbtManager { - DataTypeManager dtm; - PointerDataType fallbackVbptr; - Map vbtByAddress; + private DataTypeManager dtm; + private PointerDataType fallbackVbptr; + protected Map vbtByAddress; /** * Virtual Base Table Lookup Manager diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java index 7efd71a9d6..c096a6e7b6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java @@ -29,8 +29,6 @@ import ghidra.util.exception.CancelledException; */ public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier { - DataType vtShape = null; - private static AbstractMsType validateType(AbstractMsType type) throws IllegalArgumentException { if (!(type instanceof AbstractVirtualFunctionTablePointerMsType) && diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java index 0a21f15221..cbb7e39c73 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java @@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import ghidra.util.LittleEndianDataConverter; +import ghidra.util.Msg; import ghidra.util.exception.AssertException; /** @@ -250,7 +251,11 @@ public class PdbByteWriter { * @param data4 A byte[8], as fourth constituent piece. */ public void putGUID(int data1, short data2, short data3, byte[] data4) { - assert data4.length == 8; + if (data4.length != 8) { + String msg = "GUID invalid byte[] size... terminating"; + Msg.error(null, msg); + throw new AssertException(msg); + } putInt(data1); putShort(data2); putShort(data3); diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java index ad8a69dda4..79847bd733 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java @@ -26,6 +26,7 @@ import generic.test.AbstractGenericTest; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbByteWriter; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbReaderOptions; import ghidra.util.Msg; +import ghidra.util.exception.AssertException; import ghidra.util.task.TaskMonitor; public class MsfReaderUnitTest extends AbstractGenericTest { @@ -271,7 +272,11 @@ public class MsfReaderUnitTest extends AbstractGenericTest { } void reservePage(int pageNumber) { - assert freePage[pageNumber]; + if (!freePage[pageNumber]) { + String msg = "Page already free... terminating"; + Msg.error(null, msg); + throw new AssertException(msg); + } freePage[pageNumber] = false; } @@ -303,8 +308,9 @@ public class MsfReaderUnitTest extends AbstractGenericTest { return i; } } - assert false; - return -1; + String msg = "Unexpected algorithm flow"; + Msg.error(null, msg); + throw new AssertException(msg); } private byte[] serializedFreePageMap200() { @@ -521,7 +527,11 @@ public class MsfReaderUnitTest extends AbstractGenericTest { else { ds = new DirectoryStream(this); } - assert ds.streamNum == 0; + if (ds.streamNum != 0) { + String msg = "Stream 0 expected... terminating"; + Msg.error(null, msg); + throw new AssertException(msg); + } header.init(); fpm.init(); st.init(); @@ -549,8 +559,16 @@ public class MsfReaderUnitTest extends AbstractGenericTest { } void fillPages(byte[] inputBuffer, List pageList) { - assert outputBuffer != null; - assert pageList.size() > 0; + if (outputBuffer == null) { + String msg = "Output buffer is null... terminating"; + Msg.error(null, msg); + throw new AssertException(msg); + } + if (pageList.size() <= 0) { + String msg = "Invalid page list size... terminating"; + Msg.error(null, msg); + throw new AssertException(msg); + } int outputIndex; int inputIndex = 0; for (int i = 0; i < pageList.size() - 1; i++) { diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java index 72743de643..0256333492 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java @@ -27,6 +27,7 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.DummyMsType; import ghidra.util.Msg; +import ghidra.util.exception.AssertException; public class SymbolsTest extends AbstractGenericTest { @@ -62,8 +63,9 @@ public class SymbolsTest extends AbstractGenericTest { dummyPdb700.setItemRecord(4096, item); } catch (Exception e) { - Msg.error(null, "Error in initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } } diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java index 6deb7a858d..eef52c1238 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/TypesTest.java @@ -26,6 +26,7 @@ import generic.test.AbstractGenericTest; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.RegisterMsSymbol; import ghidra.util.Msg; +import ghidra.util.exception.AssertException; //TODO: not sure if ST variety should get putPadding() or putAlign() @@ -99,8 +100,9 @@ public class TypesTest extends AbstractGenericTest { substringListMsType1 = dummyPdb700.addItemRecord(item); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } } diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java index 74d8b61922..c30c5c8fdb 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java @@ -52,7 +52,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { private static VbtManager vbtManager32; private static VbtManager vbtManager64; // Note: Currently all test have expected results based on up the COMPLEX layout. - private static CompositeLayoutMode layoutOptions = CompositeLayoutMode.COMPLEX; + private static ObjectOrientedClassLayoutChoice classLayoutChoice = + ObjectOrientedClassLayoutChoice.COMPLEX; static { BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl(); @@ -745,14 +746,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } D_struct.addDirectBaseClass(C_struct, 0); D_struct.addMember("d1", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return D_struct; } @@ -773,14 +775,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } D_struct.addDirectBaseClass(C_struct, 0); D_struct.addMember("d1", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return D_struct; } @@ -834,19 +837,20 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } F_struct.addDirectBaseClass(C_struct, 0); F_struct.addDirectBaseClass(E_struct, 4); F_struct.addMember("f1", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return F_struct; } @@ -868,19 +872,20 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } F_struct.addDirectBaseClass(C_struct, 0); F_struct.addDirectBaseClass(E_struct, 4); F_struct.addMember("f1", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return F_struct; } @@ -907,8 +912,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { G_struct.addMember("g1", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return G_struct; } @@ -922,14 +928,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } G_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 1); G_struct.addMember("g1", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return G_struct; } @@ -950,14 +957,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } G_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 1); G_struct.addMember("g1", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return G_struct; } @@ -984,8 +992,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { H_struct.addMember("h1", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return H_struct; } @@ -999,14 +1008,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } H_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 1); H_struct.addMember("h1", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return H_struct; } @@ -1027,14 +1037,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } H_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 1); H_struct.addMember("h1", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return H_struct; } @@ -1065,8 +1076,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { G1_struct.addMember("g11", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return G1_struct; } @@ -1081,19 +1093,20 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } G1_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 1); G1_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr32, 2); G1_struct.addMember("g11", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return G1_struct; } @@ -1115,19 +1128,20 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } G1_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 1); G1_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr64, 2); G1_struct.addMember("g11", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return G1_struct; } @@ -1158,8 +1172,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { H1_struct.addMember("h11", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return H1_struct; } @@ -1174,19 +1189,20 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } H1_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr32, 1); H1_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr32, 2); H1_struct.addMember("h11", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return H1_struct; } @@ -1208,19 +1224,20 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } H1_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr64, 1); H1_struct.addDirectVirtualBaseClass(C_struct, 0, vbptr64, 2); H1_struct.addMember("h11", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return H1_struct; } @@ -1247,8 +1264,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { GG1_struct.addMember("gg11", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG1_struct; } @@ -1262,14 +1280,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (CC1_struct == null) { CC1_struct = createCC1_struct32(vbtManager); - CC1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } GG1_struct.addDirectVirtualBaseClass(CC1_struct, 0, vbptr32, 1); GG1_struct.addMember("gg11", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG1_struct; } @@ -1290,14 +1309,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (CC1_struct == null) { CC1_struct = createCC1_struct64(vbtManager); - CC1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } GG1_struct.addDirectVirtualBaseClass(CC1_struct, 0, vbptr64, 1); GG1_struct.addMember("gg11", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG1_struct; } @@ -1324,8 +1344,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { GG2_struct.addMember("gg21", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG2_struct; } @@ -1339,14 +1360,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (CC2_struct == null) { CC2_struct = createCC2_struct32(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } GG2_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbptr32, 1); GG2_struct.addMember("gg21", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG2_struct; } @@ -1367,14 +1389,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (CC2_struct == null) { CC2_struct = createCC2_struct64(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } GG2_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbptr64, 1); GG2_struct.addMember("gg21", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG2_struct; } @@ -1401,8 +1424,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { GG3_struct.addMember("gg31", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG3_struct; } @@ -1416,14 +1440,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (CC2_struct == null) { CC2_struct = createCC2_struct32(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } GG3_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbptr32, 1); GG3_struct.addMember("gg31", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG3_struct; } @@ -1444,14 +1469,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (CC2_struct == null) { CC2_struct = createCC2_struct64(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } GG3_struct.addDirectVirtualBaseClass(CC2_struct, 0, vbptr64, 1); GG3_struct.addMember("gg31", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG3_struct; } @@ -1472,14 +1498,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (CC3_struct == null) { CC3_struct = createCC3_struct32(vbtManager); - CC3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } GG4_struct.addDirectVirtualBaseClass(CC3_struct, 0, vbptr32, 1); GG4_struct.addMember("gg41", u4, false, 4); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG4_struct; } @@ -1500,14 +1527,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (CC3_struct == null) { CC3_struct = createCC3_struct64(vbtManager); - CC3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } GG4_struct.addDirectVirtualBaseClass(CC3_struct, 0, vbptr64, 1); GG4_struct.addMember("gg41", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return GG4_struct; } @@ -1542,8 +1570,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I_struct.addMember("i1", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I_struct; } @@ -1558,16 +1587,16 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } // Could be problem if only one of G or H is null: won't have same C. if (G_struct == null) { G_struct = createG_struct32(vbtManager, C_struct); - G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (H_struct == null) { H_struct = createH_struct32(vbtManager, C_struct); - H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } I_struct.addDirectBaseClass(G_struct, 0); I_struct.addDirectBaseClass(H_struct, 8); @@ -1575,8 +1604,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I_struct.addMember("i1", u4, false, 16); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I_struct; } @@ -1598,16 +1628,16 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } // Could be problem if only one of G or H is null: won't have same C. if (G_struct == null) { G_struct = createG_struct64(vbtManager, C_struct); - G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (H_struct == null) { H_struct = createH_struct64(vbtManager, C_struct); - H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } I_struct.addDirectBaseClass(G_struct, 0); I_struct.addDirectBaseClass(H_struct, 16); @@ -1615,8 +1645,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I_struct.addMember("i1", u4, false, 32); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I_struct; } @@ -1638,19 +1669,19 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (G1_struct == null) { G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (H_struct == null) { H_struct = createH_struct32(vbtManager, C_struct); - H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } I1_struct.addDirectBaseClass(G1_struct, 0); I1_struct.addDirectBaseClass(H_struct, 8); @@ -1659,8 +1690,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I1_struct.addMember("i11", u4, false, 16); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I1_struct; } @@ -1682,19 +1714,19 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (G1_struct == null) { G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (H_struct == null) { H_struct = createH_struct64(vbtManager, C_struct); - H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } I1_struct.addDirectBaseClass(G1_struct, 0); I1_struct.addDirectBaseClass(H_struct, 16); @@ -1703,8 +1735,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I1_struct.addMember("i11", u4, false, 32); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I1_struct; } @@ -1726,19 +1759,19 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (G_struct == null) { G_struct = createG_struct32(vbtManager, C_struct); - G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (H1_struct == null) { H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); - H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } I2_struct.addDirectBaseClass(G_struct, 0); I2_struct.addDirectBaseClass(H1_struct, 8); @@ -1747,8 +1780,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I2_struct.addMember("i21", u4, false, 16); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I2_struct; } @@ -1770,19 +1804,19 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (G_struct == null) { G_struct = createG_struct64(vbtManager, C_struct); - G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (H1_struct == null) { H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); - H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } I2_struct.addDirectBaseClass(G_struct, 0); I2_struct.addDirectBaseClass(H1_struct, 16); @@ -1791,8 +1825,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I2_struct.addMember("i21", u4, false, 32); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I2_struct; } @@ -1830,8 +1865,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I3_struct.addMember("i31", u4, false, 0); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I3_struct; } @@ -1846,19 +1882,19 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (G1_struct == null) { G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (H1_struct == null) { H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); - H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } I3_struct.addDirectBaseClass(G1_struct, 0); I3_struct.addDirectBaseClass(H1_struct, 8); @@ -1867,8 +1903,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I3_struct.addMember("i31", u4, false, 16); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I3_struct; } @@ -1890,19 +1927,19 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (G1_struct == null) { G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (H1_struct == null) { H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); - H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } I3_struct.addDirectBaseClass(G1_struct, 0); I3_struct.addDirectBaseClass(H1_struct, 16); @@ -1911,8 +1948,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I3_struct.addMember("i31", u4, false, 32); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I3_struct; } @@ -1934,15 +1972,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (G1_struct == null) { G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } I4_struct.addDirectBaseClass(G1_struct, 0); I4_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr32, 2); @@ -1950,8 +1988,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I4_struct.addMember("i41", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I4_struct; } @@ -1973,15 +2012,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (G1_struct == null) { G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } I4_struct.addDirectBaseClass(G1_struct, 0); I4_struct.addDirectVirtualBaseClass(E_struct, 0, vbptr64, 2); @@ -1989,8 +2028,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I4_struct.addMember("i41", u4, false, 16); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I4_struct; } @@ -2012,15 +2052,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (G1_struct == null) { G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } I5_struct.addDirectBaseClass(G1_struct, 0); I5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr32, 2); // check this and I4...TODO @@ -2028,8 +2068,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I5_struct.addMember("i51", u4, false, 8); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I5_struct; } @@ -2051,15 +2092,15 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (G1_struct == null) { G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } I5_struct.addDirectBaseClass(G1_struct, 0); I5_struct.addIndirectVirtualBaseClass(E_struct, 0, vbptr64, 2); // check this and I4...TODO @@ -2067,8 +2108,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { I5_struct.addMember("i51", u4, false, 16); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return I5_struct; } @@ -2090,27 +2132,27 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I1_struct == null) { CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); I1_struct = createI1_struct32(vbtManager, G1_struct, H_struct, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I2_struct == null) { CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); I2_struct = createI2_struct32(vbtManager, G_struct, H1_struct, C_struct, E_struct); - G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } J1_struct.addDirectBaseClass(I1_struct, 0); J1_struct.addDirectBaseClass(I2_struct, 20); @@ -2119,8 +2161,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J1_struct.addMember("j11", u4, false, 40); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J1_struct; } @@ -2143,27 +2186,27 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I1_struct == null) { CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); I1_struct = createI1_struct64(vbtManager, G1_struct, H_struct, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I2_struct == null) { CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); I2_struct = createI2_struct64(vbtManager, G_struct, H1_struct, C_struct, E_struct); - G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } J1_struct.addDirectBaseClass(I1_struct, 0); J1_struct.addDirectBaseClass(I2_struct, 40); @@ -2172,8 +2215,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J1_struct.addMember("j11", u4, false, 80); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J1_struct; } @@ -2195,27 +2239,27 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I2_struct == null) { CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); I2_struct = createI2_struct32(vbtManager, G_struct, H1_struct, C_struct, E_struct); - G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I1_struct == null) { CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); I1_struct = createI1_struct32(vbtManager, G1_struct, H_struct, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } J2_struct.addDirectBaseClass(I2_struct, 0); J2_struct.addDirectBaseClass(I1_struct, 20); @@ -2224,8 +2268,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J2_struct.addMember("j21", u4, false, 40); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J2_struct; } @@ -2247,27 +2292,27 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I2_struct == null) { CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); I2_struct = createI2_struct64(vbtManager, G_struct, H1_struct, C_struct, E_struct); - G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I1_struct == null) { CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); I1_struct = createI1_struct64(vbtManager, G1_struct, H_struct, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } J2_struct.addDirectBaseClass(I2_struct, 0); J2_struct.addDirectBaseClass(I1_struct, 40); @@ -2276,8 +2321,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J2_struct.addMember("j21", u4, false, 80); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J2_struct; } @@ -2300,31 +2346,31 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I2_struct == null) { CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); I2_struct = createI2_struct32(vbtManager, G_struct, H1_struct, C_struct, E_struct); - G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I1_struct == null) { CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); I1_struct = createI1_struct32(vbtManager, G1_struct, H_struct, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (A_struct == null) { A_struct = createA_struct32(vbtManager); - A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } J3_struct.addDirectBaseClass(I2_struct, 0); J3_struct.addDirectBaseClass(I1_struct, 20); @@ -2334,8 +2380,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J3_struct.addMember("j31", u4, false, 48); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J3_struct; } @@ -2358,31 +2405,31 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I2_struct == null) { CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); I2_struct = createI2_struct64(vbtManager, G_struct, H1_struct, C_struct, E_struct); - G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I1_struct == null) { CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); I1_struct = createI1_struct32(vbtManager, G1_struct, H_struct, C_struct, E_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (A_struct == null) { A_struct = createA_struct64(vbtManager); - A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } J3_struct.addDirectBaseClass(I2_struct, 0); J3_struct.addDirectBaseClass(I1_struct, 40); @@ -2392,8 +2439,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J3_struct.addMember("j31", u4, false, 88); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J3_struct; } @@ -2418,51 +2466,51 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (A_struct == null) { A_struct = createA_struct32(vbtManager); - A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (CC1_struct == null) { CC1_struct = createCC1_struct32(vbtManager); - CC1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (CC2_struct == null) { CC2_struct = createCC2_struct32(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I3_struct == null) { CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); I3_struct = createI3_struct32(vbtManager, G1_struct, H1_struct, E_struct, C_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (GG1_struct == null) { GG1_struct = createGG1_struct32(vbtManager, CC1_struct); - GG1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I_struct == null) { CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); I_struct = createI_struct32(vbtManager, G_struct, H_struct, C_struct); - G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (GG2_struct == null) { GG2_struct = createGG2_struct32(vbtManager, CC2_struct); - GG2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (GG3_struct == null) { GG3_struct = createGG3_struct32(vbtManager, CC2_struct); - GG3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } J4_struct.addDirectBaseClass(I3_struct, 0); J4_struct.addDirectBaseClass(GG1_struct, 20); @@ -2477,8 +2525,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J4_struct.addMember("j41", u4, false, 56); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J4_struct; } @@ -2503,51 +2552,51 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (A_struct == null) { A_struct = createA_struct64(vbtManager); - A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (CC1_struct == null) { CC1_struct = createCC1_struct64(vbtManager); - CC1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (CC2_struct == null) { CC2_struct = createCC2_struct64(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I3_struct == null) { CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); I3_struct = createI3_struct32(vbtManager, G1_struct, H1_struct, E_struct, C_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (GG1_struct == null) { GG1_struct = createGG1_struct64(vbtManager, CC1_struct); - GG1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I_struct == null) { CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); I_struct = createI_struct32(vbtManager, G_struct, H_struct, C_struct); - G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (GG2_struct == null) { GG2_struct = createGG2_struct64(vbtManager, CC2_struct); - GG2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (GG3_struct == null) { GG3_struct = createGG3_struct64(vbtManager, CC2_struct); - GG3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } J4_struct.addDirectBaseClass(I3_struct, 0); J4_struct.addDirectBaseClass(GG1_struct, 40); @@ -2562,8 +2611,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J4_struct.addMember("j41", u4, false, 104); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J4_struct; } @@ -2633,8 +2683,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J5_struct.addMember("j51", u4, false, 0); // TODO nned syntactic without index } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J5_struct; } @@ -2659,51 +2710,51 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (A_struct == null) { A_struct = createA_struct32(vbtManager); - A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct32(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct32(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (CC1_struct == null) { CC1_struct = createCC1_struct32(vbtManager); - CC1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (CC2_struct == null) { CC2_struct = createCC2_struct32(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I3_struct == null) { CppCompositeType G1_struct = createG1_struct32(vbtManager, C_struct, E_struct); CppCompositeType H1_struct = createH1_struct32(vbtManager, E_struct, C_struct); I3_struct = createI3_struct32(vbtManager, G1_struct, H1_struct, E_struct, C_struct); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (GG1_struct == null) { GG1_struct = createGG1_struct32(vbtManager, CC1_struct); - GG1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (I_struct == null) { CppCompositeType G_struct = createG_struct32(vbtManager, C_struct); CppCompositeType H_struct = createH_struct32(vbtManager, C_struct); I_struct = createI_struct32(vbtManager, G_struct, H_struct, C_struct); - G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); - I_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); + I_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (GG2_struct == null) { GG2_struct = createGG2_struct32(vbtManager, CC2_struct); - GG2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (GG3_struct == null) { GG3_struct = createGG3_struct32(vbtManager, CC2_struct); - GG3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } J5_struct.addDirectBaseClass(I3_struct, 0); J5_struct.addDirectBaseClass(GG1_struct, 20); @@ -2718,8 +2769,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J5_struct.addMember("j51", u4, false, 56); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J5_struct; } @@ -2744,51 +2796,51 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (A_struct == null) { A_struct = createA_struct64(vbtManager); - A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (C_struct == null) { C_struct = createC_struct64(vbtManager); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (E_struct == null) { E_struct = createE_struct64(vbtManager); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (CC1_struct == null) { CC1_struct = createCC1_struct64(vbtManager); - CC1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (CC2_struct == null) { CC2_struct = createCC2_struct64(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I3_struct == null) { CppCompositeType G1_struct = createG1_struct64(vbtManager, C_struct, E_struct); CppCompositeType H1_struct = createH1_struct64(vbtManager, E_struct, C_struct); I3_struct = createI3_struct32(vbtManager, G1_struct, H1_struct, E_struct, C_struct); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (GG1_struct == null) { GG1_struct = createGG1_struct32(vbtManager, CC1_struct); - GG1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (I_struct == null) { CppCompositeType G_struct = createG_struct64(vbtManager, C_struct); CppCompositeType H_struct = createH_struct64(vbtManager, C_struct); I_struct = createI_struct32(vbtManager, G_struct, H_struct, C_struct); - G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); - I_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); + I_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (GG2_struct == null) { GG2_struct = createGG2_struct64(vbtManager, CC2_struct); - GG2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (GG3_struct == null) { GG3_struct = createGG3_struct64(vbtManager, CC2_struct); - GG3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } J5_struct.addDirectBaseClass(I3_struct, 0); J5_struct.addDirectBaseClass(GG1_struct, 40); @@ -2803,8 +2855,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J5_struct.addMember("j51", u4, false, 104); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J5_struct; } @@ -2827,23 +2880,23 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (A_struct == null) { A_struct = createA_struct32(vbtManager); - A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (CC2_struct == null) { CC2_struct = createCC2_struct32(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (CC3_struct == null) { CC3_struct = createCC3_struct32(vbtManager); - CC3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (GG4_struct == null) { GG4_struct = createGG4_struct32(vbtManager, CC3_struct); - GG4_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG4_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } if (GG3_struct == null) { GG3_struct = createGG3_struct32(vbtManager, CC2_struct); - GG3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); } J6_struct.addDirectBaseClass(A_struct, 0); J6_struct.addDirectVirtualBaseClass(GG4_struct, 8, vbptr32, 2); @@ -2853,8 +2906,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J6_struct.addMember("j61", u4, false, 12); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J6_struct; } @@ -2877,23 +2931,23 @@ public class CppCompositeTypeTest extends AbstractGenericTest { try { if (A_struct == null) { A_struct = createA_struct64(vbtManager); - A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (CC2_struct == null) { CC2_struct = createCC2_struct64(vbtManager); - CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (CC3_struct == null) { CC3_struct = createCC3_struct64(vbtManager); - CC3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (GG4_struct == null) { GG4_struct = createGG4_struct64(vbtManager, CC3_struct); - GG4_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG4_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } if (GG3_struct == null) { GG3_struct = createGG3_struct64(vbtManager, CC2_struct); - GG3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); } J6_struct.addDirectBaseClass(A_struct, 0); J6_struct.addDirectVirtualBaseClass(GG4_struct, 8, vbptr64, 2); @@ -2903,8 +2957,9 @@ public class CppCompositeTypeTest extends AbstractGenericTest { J6_struct.addMember("j61", u4, false, 16); } catch (Exception e) { - Msg.error(null, "Error in static initialization of test", e); - assert false; + String msg = "Error in static initialization of testt: " + e; + Msg.error(null, msg); + throw new AssertException(msg); } return J6_struct; } @@ -2930,7 +2985,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testA_32_vbt() throws Exception { CppCompositeType A_struct = createA_struct32(pdbVbtManager32); - A_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = A_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedA_32(), composite, true); } @@ -2938,7 +2993,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testA_32_speculative() throws Exception { CppCompositeType A_struct = createA_struct32(vbtManager32); - A_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = A_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedA_32(), composite, true); } @@ -2986,7 +3041,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testA_64_vbt() throws Exception { CppCompositeType A_struct = createA_struct64(pdbVbtManager64); - A_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = A_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedA_64(), composite, true); } @@ -2994,7 +3049,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testA_64_speculative() throws Exception { CppCompositeType A_struct = createA_struct64(vbtManager64); - A_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + A_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = A_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedA_64(), composite, true); } @@ -3040,7 +3095,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testC_32_vbt() throws Exception { CppCompositeType C_struct = createC_struct32(pdbVbtManager32); - C_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = C_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedC_32(), composite, true); } @@ -3048,7 +3103,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testC_32_speculative() throws Exception { CppCompositeType C_struct = createC_struct32(vbtManager32); - C_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = C_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedC_32(), composite, true); } @@ -3093,7 +3148,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testC_64_vbt() throws Exception { CppCompositeType C_struct = createC_struct64(pdbVbtManager64); - C_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = C_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedC_64(), composite, true); } @@ -3101,7 +3156,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testC_64_speculative() throws Exception { CppCompositeType C_struct = createC_struct64(vbtManager64); - C_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + C_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = C_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedC_64(), composite, true); } @@ -3146,7 +3201,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC1_32_vbt() throws Exception { CppCompositeType CC1_struct = createCC1_struct32(pdbVbtManager32); - CC1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = CC1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedCC1_32(), composite, true); } @@ -3154,7 +3209,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC1_32_speculative() throws Exception { CppCompositeType CC1_struct = createCC1_struct32(vbtManager32); - CC1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = CC1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC1_32(), composite, true); } @@ -3199,7 +3254,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC1_64_vbt() throws Exception { CppCompositeType CC1_struct = createCC1_struct64(pdbVbtManager64); - CC1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = CC1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedCC1_64(), composite, true); } @@ -3207,7 +3262,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC1_64_speculative() throws Exception { CppCompositeType CC1_struct = createCC1_struct64(vbtManager64); - CC1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = CC1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC1_64(), composite, true); } @@ -3252,7 +3307,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC2_32_vbt() throws Exception { CppCompositeType CC2_struct = createCC2_struct32(pdbVbtManager32); - CC2_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = CC2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedCC2_32(), composite, true); } @@ -3260,7 +3315,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC2_32_speculative() throws Exception { CppCompositeType CC2_struct = createCC2_struct32(vbtManager32); - CC2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = CC2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC2_32(), composite, true); } @@ -3305,7 +3360,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC2_64_vbt() throws Exception { CppCompositeType CC2_struct = createCC2_struct64(pdbVbtManager64); - CC2_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = CC2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedCC2_64(), composite, true); } @@ -3313,7 +3368,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC2_64_speculative() throws Exception { CppCompositeType CC2_struct = createCC2_struct64(vbtManager64); - CC2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = CC2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC2_64(), composite, true); } @@ -3356,7 +3411,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC3_32_vbt() throws Exception { CppCompositeType CC3_struct = createCC3_struct32(pdbVbtManager32); - CC3_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + CC3_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = CC3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedCC3_32(), composite, true); } @@ -3364,7 +3419,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC3_32_speculative() throws Exception { CppCompositeType CC3_struct = createCC3_struct32(vbtManager32); - CC3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + CC3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = CC3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC3_32(), composite, true); } @@ -3400,7 +3455,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC3_64_vbt() throws Exception { CppCompositeType CC3_struct = createCC3_struct64(pdbVbtManager64); - CC3_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + CC3_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = CC3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedCC3_64(), composite, true); } @@ -3408,7 +3463,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testCC3_64_speculative() throws Exception { CppCompositeType CC3_struct = createCC3_struct64(vbtManager64); - CC3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + CC3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = CC3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedCC3_64(), composite, true); } @@ -3449,7 +3504,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testD_32_vbt() throws Exception { CppCompositeType D_struct = createD_struct32(pdbVbtManager32); - D_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + D_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = D_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedD_32(), composite, true); } @@ -3457,7 +3512,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testD_32_speculative() throws Exception { CppCompositeType D_struct = createD_struct32(vbtManager32); - D_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + D_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = D_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedD_32(), composite, true); } @@ -3512,7 +3567,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testD_64_vbt() throws Exception { CppCompositeType D_struct = createD_struct64(pdbVbtManager64); - D_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + D_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = D_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedD_64(), composite, true); } @@ -3520,7 +3575,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testD_64_speculative() throws Exception { CppCompositeType D_struct = createD_struct64(vbtManager64); - D_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + D_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = D_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedD_64(), composite, true); } @@ -3572,7 +3627,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testE_32_vbt() throws Exception { CppCompositeType E_struct = createE_struct32(pdbVbtManager32); - E_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = E_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedE_32(), composite, true); } @@ -3580,7 +3635,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testE_32_speculative() throws Exception { CppCompositeType E_struct = createE_struct32(vbtManager32); - E_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = E_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedE_32(), composite, true); } @@ -3625,7 +3680,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testE_64_vbt() throws Exception { CppCompositeType E_struct = createE_struct64(pdbVbtManager64); - E_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = E_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedE_64(), composite, true); } @@ -3633,7 +3688,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testE_64_speculative() throws Exception { CppCompositeType E_struct = createE_struct64(vbtManager64); - E_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + E_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = E_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedE_64(), composite, true); } @@ -3684,7 +3739,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testF_32_vbt() throws Exception { CppCompositeType F_struct = createF_struct32(pdbVbtManager32); - F_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + F_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = F_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedF_32(), composite, true); } @@ -3692,7 +3747,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testF_32_speculative() throws Exception { CppCompositeType F_struct = createF_struct32(vbtManager32); - F_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + F_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = F_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedF_32(), composite, true); } @@ -3757,7 +3812,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testF_64_vbt() throws Exception { CppCompositeType F_struct = createF_struct64(pdbVbtManager64); - F_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + F_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = F_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedF_64(), composite, true); } @@ -3765,7 +3820,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testF_64_speculative() throws Exception { CppCompositeType F_struct = createF_struct64(vbtManager64); - F_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + F_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = F_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedF_64(), composite, true); } @@ -3834,7 +3889,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testG_32_vbt() throws Exception { CppCompositeType G_struct = createG_struct32(pdbVbtManager32); - G_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = G_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedG_32(), composite, true); } @@ -3842,7 +3897,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testG_32_speculative() throws Exception { CppCompositeType G_struct = createG_struct32(vbtManager32); - G_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = G_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedG_32(), composite, true); } @@ -3906,7 +3961,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testG_64_vbt() throws Exception { CppCompositeType G_struct = createG_struct64(pdbVbtManager64); - G_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = G_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedG_64(), composite, true); } @@ -3914,7 +3969,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testG_64_speculative() throws Exception { CppCompositeType G_struct = createG_struct64(vbtManager64); - G_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = G_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedG_64(), composite, true); } @@ -3977,7 +4032,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testH_32_vbt() throws Exception { CppCompositeType H_struct = createH_struct32(pdbVbtManager32); - H_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = H_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedH_32(), composite, true); } @@ -3985,7 +4040,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testH_32_speculative() throws Exception { CppCompositeType H_struct = createH_struct32(vbtManager32); - H_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = H_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedH_32(), composite, true); } @@ -4049,7 +4104,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testH_64_vbt() throws Exception { CppCompositeType H_struct = createH_struct64(pdbVbtManager64); - H_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = H_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedH_64(), composite, true); } @@ -4057,7 +4112,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testH_64_speculative() throws Exception { CppCompositeType H_struct = createH_struct64(vbtManager64); - H_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = H_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedH_64(), composite, true); } @@ -4125,7 +4180,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testG1_32_vbt() throws Exception { CppCompositeType G1_struct = createG1_struct32(pdbVbtManager32); - G1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = G1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedG1_32(), composite, true); } @@ -4133,7 +4188,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testG1_32_speculative() throws Exception { CppCompositeType G1_struct = createG1_struct32(vbtManager32); - G1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = G1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedG1_32(), composite, true); } @@ -4209,7 +4264,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testG1_64_vbt() throws Exception { CppCompositeType G1_struct = createG1_struct64(pdbVbtManager64); - G1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = G1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedG1_64(), composite, true); } @@ -4217,7 +4272,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testG1_64_speculative() throws Exception { CppCompositeType G1_struct = createG1_struct64(vbtManager64); - G1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + G1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = G1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedG1_64(), composite, true); } @@ -4292,7 +4347,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testH1_32_vbt() throws Exception { CppCompositeType H1_struct = createH1_struct32(pdbVbtManager32); - H1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = H1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedH1_32(), composite, true); } @@ -4300,7 +4355,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testH1_32_speculative() throws Exception { CppCompositeType H1_struct = createH1_struct32(vbtManager32); - H1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = H1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedH1_32(), composite, true); } @@ -4376,7 +4431,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testH1_64_vbt() throws Exception { CppCompositeType H1_struct = createH1_struct64(pdbVbtManager64); - H1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = H1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedH1_64(), composite, true); } @@ -4384,7 +4439,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testH1_64_speculative() throws Exception { CppCompositeType H1_struct = createH1_struct64(vbtManager64); - H1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + H1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = H1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedH1_64(), composite, true); } @@ -4454,7 +4509,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG1_32_vbt() throws Exception { CppCompositeType GG1_struct = createGG1_struct32(pdbVbtManager32); - GG1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + GG1_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = GG1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedGG1_32(), composite, true); } @@ -4462,7 +4517,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG1_32_speculative() throws Exception { CppCompositeType GG1_struct = createGG1_struct32(vbtManager32); - GG1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = GG1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG1_32(), composite, true); } @@ -4526,7 +4581,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG1_64_vbt() throws Exception { CppCompositeType GG1_struct = createGG1_struct64(pdbVbtManager64); - GG1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + GG1_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = GG1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedGG1_64(), composite, true); } @@ -4534,7 +4589,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG1_64_speculative() throws Exception { CppCompositeType GG1_struct = createGG1_struct64(vbtManager64); - GG1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = GG1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG1_64(), composite, true); } @@ -4597,7 +4652,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG2_32_vbt() throws Exception { CppCompositeType GG2_struct = createGG2_struct32(pdbVbtManager32); - GG2_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + GG2_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = GG2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedGG2_32(), composite, true); } @@ -4605,7 +4660,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG2_32_speculative() throws Exception { CppCompositeType GG2_struct = createGG2_struct32(vbtManager32); - GG2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = GG2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG2_32(), composite, true); } @@ -4669,7 +4724,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG2_64_vbt() throws Exception { CppCompositeType GG2_struct = createGG2_struct64(pdbVbtManager64); - GG2_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + GG2_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = GG2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedGG2_64(), composite, true); } @@ -4677,7 +4732,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG2_64_speculative() throws Exception { CppCompositeType GG2_struct = createGG2_struct64(vbtManager64); - GG2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = GG2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG2_64(), composite, true); } @@ -4740,7 +4795,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG3_32_vbt() throws Exception { CppCompositeType GG3_struct = createGG3_struct32(pdbVbtManager32); - GG3_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = GG3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedGG3_32(), composite, true); } @@ -4748,7 +4803,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG3_32_speculative() throws Exception { CppCompositeType GG3_struct = createGG3_struct32(vbtManager32); - GG3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = GG3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG3_32(), composite, true); } @@ -4812,7 +4867,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG3_64_vbt() throws Exception { CppCompositeType GG3_struct = createGG3_struct64(pdbVbtManager64); - GG3_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = GG3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedGG3_64(), composite, true); } @@ -4820,7 +4875,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG3_64_speculative() throws Exception { CppCompositeType GG3_struct = createGG3_struct64(vbtManager64); - GG3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = GG3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG3_64(), composite, true); } @@ -4886,7 +4941,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG4_32_vbt() throws Exception { CppCompositeType GG4_struct = createGG4_struct32(pdbVbtManager32); - GG4_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + GG4_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = GG4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedGG4_32(), composite, true); } @@ -4894,7 +4949,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG4_32_speculative() throws Exception { CppCompositeType GG4_struct = createGG4_struct32(vbtManager32); - GG4_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + GG4_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = GG4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG4_32(), composite, true); } @@ -4954,7 +5009,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG4_64_vbt() throws Exception { CppCompositeType GG4_struct = createGG4_struct64(pdbVbtManager64); - GG4_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + GG4_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = GG4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedGG4_64(), composite, true); } @@ -4962,7 +5017,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testGG4_64_speculative() throws Exception { CppCompositeType GG4_struct = createGG4_struct64(vbtManager64); - GG4_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + GG4_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = GG4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedGG4_64(), composite, true); } @@ -5030,7 +5085,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI_32_vbt() throws Exception { CppCompositeType I_struct = createI_struct32(pdbVbtManager32); - I_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + I_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = I_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI_32(), composite, true); } @@ -5038,7 +5093,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI_32_speculative() throws Exception { CppCompositeType I_struct = createI_struct32(vbtManager32); - I_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = I_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI_32(), composite, true); } @@ -5132,7 +5187,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI_64_vbt() throws Exception { CppCompositeType I_struct = createI_struct64(pdbVbtManager64); - I_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + I_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = I_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI_64(), composite, true); } @@ -5140,7 +5195,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI_64_speculative() throws Exception { CppCompositeType I_struct = createI_struct64(vbtManager64); - I_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = I_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI_64(), composite, true); } @@ -5234,7 +5289,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI1_32_vbt() throws Exception { CppCompositeType I1_struct = createI1_struct32(pdbVbtManager32); - I1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = I1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI1_32(), composite, true); } @@ -5242,7 +5297,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI1_32_speculative() throws Exception { CppCompositeType I1_struct = createI1_struct32(vbtManager32); - I1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = I1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI1_32(), composite, true); } @@ -5347,7 +5402,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI1_64_vbt() throws Exception { CppCompositeType I1_struct = createI1_struct64(pdbVbtManager64); - I1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = I1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI1_64(), composite, true); } @@ -5355,7 +5410,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI1_64_speculative() throws Exception { CppCompositeType I1_struct = createI1_struct64(vbtManager64); - I1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = I1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI1_64(), composite, true); } @@ -5457,7 +5512,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI2_32_vbt() throws Exception { CppCompositeType I2_struct = createI2_struct32(pdbVbtManager32); - I2_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = I2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI2_32(), composite, true); } @@ -5465,7 +5520,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI2_32_speculative() throws Exception { CppCompositeType I2_struct = createI2_struct32(vbtManager32); - I2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = I2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI2_32(), composite, true); } @@ -5571,7 +5626,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI2_64_vbt() throws Exception { CppCompositeType I2_struct = createI2_struct64(pdbVbtManager64); - I2_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = I2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI2_64(), composite, true); } @@ -5579,7 +5634,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI2_64_speculative() throws Exception { CppCompositeType I2_struct = createI2_struct64(vbtManager64); - I2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = I2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI2_64(), composite, true); } @@ -5681,7 +5736,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI3_32_vbt() throws Exception { CppCompositeType I3_struct = createI3_struct32(pdbVbtManager32); - I3_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + I3_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = I3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI3_32(), composite, true); } @@ -5689,7 +5744,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI3_32_speculative() throws Exception { CppCompositeType I3_struct = createI3_struct32(vbtManager32); - I3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = I3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI3_32(), composite, true); } @@ -5794,7 +5849,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI3_64_vbt() throws Exception { CppCompositeType I3_struct = createI3_struct64(pdbVbtManager64); - I3_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + I3_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = I3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI3_64(), composite, true); } @@ -5802,7 +5857,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI3_64_speculative() throws Exception { CppCompositeType I3_struct = createI3_struct64(vbtManager64); - I3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = I3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI3_64(), composite, true); } @@ -5895,7 +5950,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI4_32_vbt() throws Exception { CppCompositeType I4_struct = createI4_struct32(pdbVbtManager32); - I4_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + I4_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = I4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI4_32(), composite, true); } @@ -5903,7 +5958,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI4_32_speculative() throws Exception { CppCompositeType I4_struct = createI4_struct32(vbtManager32); - I4_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I4_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = I4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI4_32(), composite, true); } @@ -5990,7 +6045,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI4_64_vbt() throws Exception { CppCompositeType I4_struct = createI4_struct64(pdbVbtManager64); - I4_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + I4_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = I4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI4_64(), composite, true); } @@ -5998,7 +6053,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI4_64_speculative() throws Exception { CppCompositeType I4_struct = createI4_struct64(vbtManager64); - I4_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I4_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = I4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI4_64(), composite, true); } @@ -6083,7 +6138,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI5_32_vbt() throws Exception { CppCompositeType I5_struct = createI5_struct32(pdbVbtManager32); - I5_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + I5_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = I5_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedtI5_32(), composite, true); } @@ -6091,7 +6146,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI5_32_speculative() throws Exception { CppCompositeType I5_struct = createI5_struct32(vbtManager32); - I5_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + I5_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = I5_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedtI5_32(), composite, true); } @@ -6220,7 +6275,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI5_64_vbt() throws Exception { CppCompositeType I5_struct = createI5_struct64(pdbVbtManager64); - I5_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + I5_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = I5_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedI5_64(), composite, true); } @@ -6228,7 +6283,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testI5_64_speculative() throws Exception { CppCompositeType I5_struct = createI5_struct64(vbtManager64); - I5_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + I5_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = I5_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedI5_64(), composite, true); } @@ -6387,7 +6442,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ1_32_vbt() throws Exception { CppCompositeType J1_struct = createJ1_struct32(pdbVbtManager32); - J1_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + J1_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = J1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ1_32(), composite, true); } @@ -6395,7 +6450,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ1_32_speculative() throws Exception { CppCompositeType J1_struct = createJ1_struct32(vbtManager32); - J1_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + J1_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = J1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ1_32(), composite, true); } @@ -6559,7 +6614,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ1_64_vbt() throws Exception { CppCompositeType J1_struct = createJ1_struct64(pdbVbtManager64); - J1_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + J1_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = J1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ1_64(), composite, true); } @@ -6567,7 +6622,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ1_64_speculative() throws Exception { CppCompositeType J1_struct = createJ1_struct64(vbtManager64); - J1_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + J1_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = J1_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ1_64(), composite, true); } @@ -6722,7 +6777,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ2_32_vbt() throws Exception { CppCompositeType J2_struct = createJ2_struct32(pdbVbtManager32); - J2_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + J2_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = J2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ2_32(), composite, true); } @@ -6730,7 +6785,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ2_32_speculative() throws Exception { CppCompositeType J2_struct = createJ2_struct32(vbtManager32); - J2_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + J2_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = J2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ2_32(), composite, true); } @@ -6894,7 +6949,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ2_64_vbt() throws Exception { CppCompositeType J2_struct = createJ2_struct64(pdbVbtManager64); - J2_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + J2_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = J2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ2_64(), composite, true); } @@ -6902,7 +6957,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ2_64_speculative() throws Exception { CppCompositeType J2_struct = createJ2_struct64(vbtManager64); - J2_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + J2_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = J2_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ2_64(), composite, true); } @@ -7062,7 +7117,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ3_32_vbt() throws Exception { CppCompositeType J3_struct = createJ3_struct32(pdbVbtManager32); - J3_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + J3_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = J3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ3_32(), composite, true); } @@ -7070,7 +7125,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ3_32_speculative() throws Exception { CppCompositeType J3_struct = createJ3_struct32(vbtManager32); - J3_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + J3_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = J3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ3_32(), composite, true); } @@ -7247,7 +7302,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ3_64_vbt() throws Exception { CppCompositeType J3_struct = createJ3_struct64(pdbVbtManager64); - J3_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + J3_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = J3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ3_64(), composite, true); } @@ -7255,7 +7310,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ3_64_speculative() throws Exception { CppCompositeType J3_struct = createJ3_struct64(vbtManager64); - J3_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + J3_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = J3_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ3_64(), composite, true); } @@ -7460,7 +7515,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ4_32_vbt() throws Exception { CppCompositeType J4_struct = createJ4_struct32(pdbVbtManager32); - J4_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + J4_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = J4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ4_32(), composite, true); } @@ -7468,7 +7523,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ4_32_speculative() throws Exception { CppCompositeType J4_struct = createJ4_struct32(vbtManager32); - J4_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + J4_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = J4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ4_32(), composite, true); } @@ -7727,7 +7782,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ4_64_vbt() throws Exception { CppCompositeType J4_struct = createJ4_struct64(pdbVbtManager64); - J4_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + J4_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = J4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ4_64(), composite, true); } @@ -7735,7 +7790,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ4_64_speculative() throws Exception { CppCompositeType J4_struct = createJ4_struct64(vbtManager64); - J4_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + J4_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = J4_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ4_64(), composite, true); } @@ -7978,7 +8033,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ5_32_vbt() throws Exception { CppCompositeType J5_struct = createJ5_struct32(pdbVbtManager32); - J5_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + J5_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = J5_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ5_32(), composite, true); } @@ -7988,7 +8043,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { // @Test public void testJ5_32_speculative() throws Exception { CppCompositeType J5_struct = createJ5_struct32(vbtManager32); - J5_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + J5_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = J5_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ5_32(), composite, true); } @@ -8253,7 +8308,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ5_64_vbt() throws Exception { CppCompositeType J5_struct = createJ5_struct64(pdbVbtManager64); - J5_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + J5_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = J5_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ5_64(), composite, true); } @@ -8263,7 +8318,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { // @Test public void testJ5_64_speculative() throws Exception { CppCompositeType J5_struct = createJ5_struct64(vbtManager64); - J5_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + J5_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = J5_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ5_64(), composite, true); } @@ -8458,7 +8513,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ6_32_vbt() throws Exception { CppCompositeType J6_struct = createJ6_struct32(pdbVbtManager32); - J6_struct.createLayout(layoutOptions, pdbVbtManager32, TaskMonitor.DUMMY); + J6_struct.createLayout(classLayoutChoice, pdbVbtManager32, TaskMonitor.DUMMY); Composite composite = J6_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ6_32(), composite, true); } @@ -8468,7 +8523,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { // @Test public void testJ6_32_speculative() throws Exception { CppCompositeType J6_struct = createJ6_struct32(vbtManager32); - J6_struct.createLayout(layoutOptions, vbtManager32, TaskMonitor.DUMMY); + J6_struct.createLayout(classLayoutChoice, vbtManager32, TaskMonitor.DUMMY); Composite composite = J6_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ6_32(), composite, true); } @@ -8594,7 +8649,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { @Test public void testJ6_64_vbt() throws Exception { CppCompositeType J6_struct = createJ6_struct64(pdbVbtManager64); - J6_struct.createLayout(layoutOptions, pdbVbtManager64, TaskMonitor.DUMMY); + J6_struct.createLayout(classLayoutChoice, pdbVbtManager64, TaskMonitor.DUMMY); Composite composite = J6_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getExpectedJ6_64(), composite, true); } @@ -8604,7 +8659,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest { // @Test public void testJ6_64_speculative() throws Exception { CppCompositeType J6_struct = createJ6_struct64(vbtManager64); - J6_struct.createLayout(layoutOptions, vbtManager64, TaskMonitor.DUMMY); + J6_struct.createLayout(classLayoutChoice, vbtManager64, TaskMonitor.DUMMY); Composite composite = J6_struct.getComposite(); CompositeTestUtils.assertExpectedComposite(this, getSpeculatedJ6_64(), composite, true); } From 9a4e870875ba9bf4cdbc5fd13975ed7af16e2854 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Wed, 9 Sep 2020 09:46:02 -0400 Subject: [PATCH 07/15] GT-3112 - PDB Universal Reader/Analyzer - 116 commits --- .../core/analysis/PdbUniversalAnalyzer.java | 19 +++---- .../pdbapplicator/BaseClassTypeApplier.java | 24 ++++---- .../pdbapplicator/CompositeTypeApplier.java | 3 +- .../pdb/pdbapplicator/CppCompositeType.java | 42 +++++++------- .../pdb/pdbapplicator/NestedTypeApplier.java | 22 ++++---- .../ObjectOrientedClassLayout.java | 30 ++++++++-- .../ObjectOrientedClassLayoutChoice.java | 56 ------------------- .../pdb/pdbapplicator/PdbAddressManager.java | 6 +- .../pdbapplicator/PdbApplicatorMetrics.java | 8 +-- .../pdbapplicator/PdbApplicatorOptions.java | 32 +++++------ ...dbRegisterNameToProgramRegisterMapper.java | 4 +- .../util/pdb/pdbapplicator/PdbResearch.java | 3 +- ...irtualFunctionTablePointerTypeApplier.java | 22 ++++---- .../pdbapplicator/CppCompositeTypeTest.java | 4 +- 14 files changed, 121 insertions(+), 154 deletions(-) delete mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayoutChoice.java diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java index 8d9e579318..219a3e7ba3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java @@ -181,7 +181,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { "If checked, attempts to apply function parameters and local variables for program functions."; private boolean applyFunctionVariables; - // Sets the composite layout choice. + // Sets the composite layout. // Legacy // - similar to existing DIA-based PDB Analyzer, only placing current composite direct // members (none from parent classes. @@ -196,11 +196,11 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { // Complex // - Puts all current class members and 'direct' parents' 'direct' components into an // encapsulating 'direct' container - private static final String OPTION_NAME_COMPOSITE_LAYOUT_CHOICE = "Composite Layout Choice"; - private static final String OPTION_DESCRIPTION_COMPOSITE_LAYOUT_CHOICE = + private static final String OPTION_NAME_COMPOSITE_LAYOUT = "Composite Layout Choice"; + private static final String OPTION_DESCRIPTION_COMPOSITE_LAYOUT = "Legacy layout like original PDB Analyzer. Warning: other choices have no compatibility" + " guarantee with future Ghidra releases or minor PDB Analyzer changes"; - private ObjectOrientedClassLayoutChoice compositeLayoutChoice; + private ObjectOrientedClassLayout compositeLayout; //============================================================================================== // Additional instance data @@ -397,8 +397,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { OPTION_DESCRIPTION_ALLOW_DEMOTE_MANGLED_PRIMARY); options.registerOption(OPTION_NAME_APPLY_FUNCTION_VARIABLES, applyFunctionVariables, null, OPTION_DESCRIPTION_APPLY_FUNCTION_VARIABLES); - options.registerOption(OPTION_NAME_COMPOSITE_LAYOUT_CHOICE, compositeLayoutChoice, null, - OPTION_DESCRIPTION_COMPOSITE_LAYOUT_CHOICE); + options.registerOption(OPTION_NAME_COMPOSITE_LAYOUT, compositeLayout, null, + OPTION_DESCRIPTION_COMPOSITE_LAYOUT); } } @@ -464,8 +464,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { OPTION_NAME_ALLOW_DEMOTE_MANGLED_PRIMARY, allowDemotePrimaryMangledSymbol); applyFunctionVariables = options.getBoolean(OPTION_NAME_APPLY_FUNCTION_VARIABLES, applyFunctionVariables); - compositeLayoutChoice = - options.getEnum(OPTION_NAME_COMPOSITE_LAYOUT_CHOICE, compositeLayoutChoice); + compositeLayout = options.getEnum(OPTION_NAME_COMPOSITE_LAYOUT, compositeLayout); } setPdbApplicatorOptions(); } @@ -565,7 +564,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { allowDemotePrimaryMangledSymbol = PdbApplicatorOptions.DEFAULT_ALLOW_DEMOTE_PRIMARY_MANGLED_SYMBOLS; applyFunctionVariables = PdbApplicatorOptions.DEFAULT_APPLY_FUNCTION_VARIABLES; - compositeLayoutChoice = PdbApplicatorOptions.DEFAULT_CLASS_LAYOUT_CHOICE; + compositeLayout = PdbApplicatorOptions.DEFAULT_CLASS_LAYOUT; } private void setPdbApplicatorOptions() { @@ -578,7 +577,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { remapAddressUsingExistingPublicMangledSymbols); pdbApplicatorOptions.setAllowDemotePrimaryMangledSymbols(allowDemotePrimaryMangledSymbol); pdbApplicatorOptions.setApplyFunctionVariables(applyFunctionVariables); - pdbApplicatorOptions.setClassLayoutChoice(compositeLayoutChoice); + pdbApplicatorOptions.setClassLayout(compositeLayout); } private boolean confirmDirectory(File path) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java index b73f72eeae..696873cfda 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/BaseClassTypeApplier.java @@ -28,18 +28,6 @@ import ghidra.util.exception.CancelledException; */ public class BaseClassTypeApplier extends MsTypeApplier { - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractBaseClassMsType) && - !(type instanceof AbstractVirtualBaseClassMsType) && - !(type instanceof AbstractIndirectVirtualBaseClassMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - BaseClassTypeApplier.class.getSimpleName()); - } - return type; - } - /** * Constructor for base class applier. * @param applicator {@link PdbApplicator} for which this class is working. @@ -144,4 +132,16 @@ public class BaseClassTypeApplier extends MsTypeApplier { // do nothing at the moment. } + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractBaseClassMsType) && + !(type instanceof AbstractVirtualBaseClassMsType) && + !(type instanceof AbstractIndirectVirtualBaseClassMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + BaseClassTypeApplier.class.getSimpleName()); + } + return type; + } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java index 130daaba15..fa25c1540a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java @@ -46,7 +46,6 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { private static boolean applyBaseClasses = true; //private static boolean applyBaseClasses = false; - private boolean isDeferred = false; private CppCompositeType classType; // private final static DataType NO_TYPE_DATATYPE = @@ -330,7 +329,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { // TODO: Investigate. We should do this check for some classes somewhere. Should // we do it here. Set breakpoint here to investigate. } - classType.createLayout(applicator.getPdbApplicatorOptions().getClassLayoutChoice(), + classType.createLayout(applicator.getPdbApplicatorOptions().getClassLayout(), applicator.getVbtManager(), applicator.getCancelOnlyWrappingMonitor()); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java index df7247a2b1..13cbb5d41d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java @@ -51,7 +51,7 @@ public class CppCompositeType { private Composite composite; private CategoryPath categoryPath; - private ObjectOrientedClassLayout classLayout = ObjectOrientedClassLayout.UNKNOWN; + private ObjectOrientedClassLayout classLayout = null; private List memberData; @@ -583,30 +583,31 @@ public class CppCompositeType { return builder.toString(); } - public ObjectOrientedClassLayout getLayout(ObjectOrientedClassLayoutChoice layoutOptions) { - if (classLayout == ObjectOrientedClassLayout.UNKNOWN) { + public ObjectOrientedClassLayout getLayout( + ObjectOrientedClassLayout layoutOptions) { + if (classLayout == null) { classLayout = determineClassLayout(layoutOptions); } return classLayout; } private ObjectOrientedClassLayout determineClassLayout( - ObjectOrientedClassLayoutChoice layoutOptions) { + ObjectOrientedClassLayout layoutOptions) { ObjectOrientedClassLayout initialLayoutDetermination; - if (layoutOptions.getClassLayout() == ObjectOrientedClassLayout.MEMBERS_ONLY) { + if (layoutOptions == ObjectOrientedClassLayout.MEMBERS_ONLY) { return ObjectOrientedClassLayout.MEMBERS_ONLY; } else if (getNumLayoutBaseClasses() == 0) { - initialLayoutDetermination = ObjectOrientedClassLayout.BASIC; + initialLayoutDetermination = ObjectOrientedClassLayout.BASIC_SIMPLE_COMPLEX; } else if (getNumLayoutVirtualBaseClasses() == 0) { - initialLayoutDetermination = ObjectOrientedClassLayout.SIMPLE; + initialLayoutDetermination = ObjectOrientedClassLayout.SIMPLE_COMPLEX; } else { initialLayoutDetermination = ObjectOrientedClassLayout.COMPLEX; } - ObjectOrientedClassLayout classLyoutOption = layoutOptions.getClassLayout(); - return classLyoutOption.compareTo(initialLayoutDetermination) >= 0 ? classLyoutOption + ObjectOrientedClassLayout classLayoutOption = layoutOptions; + return classLayoutOption.compareTo(initialLayoutDetermination) >= 0 ? classLayoutOption : initialLayoutDetermination; } @@ -629,7 +630,7 @@ public class CppCompositeType { //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- - public void createLayout(ObjectOrientedClassLayoutChoice layoutOptions, VbtManager vbtManager, + public void createLayout(ObjectOrientedClassLayout layoutOptions, VbtManager vbtManager, TaskMonitor monitor) throws PdbException, CancelledException { if (vbtManager instanceof PdbVbtManager) { // Information from PDB/program symbols // TODO: both same for now @@ -643,7 +644,7 @@ public class CppCompositeType { //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- - public void createVbtBasedLayout(ObjectOrientedClassLayoutChoice layoutOptions, + public void createVbtBasedLayout(ObjectOrientedClassLayout layoutOptions, VbtManager vbtManager, TaskMonitor monitor) throws PdbException, CancelledException { CategoryPath cn; hasDirect = false; @@ -651,13 +652,13 @@ public class CppCompositeType { case MEMBERS_ONLY: addLayoutPdbMembers(memberData, layoutMembers); break; - case BASIC: + case BASIC_SIMPLE_COMPLEX: addLayoutPdbMembers(memberData, layoutMembers); insertVirtualFunctionTablePointers(memberData); break; // TODO: evaluate... not really getting difference I thought we could get... so far // BASIC and SIMPLE seem to yield the same results. I might be doing something wrong. - case SIMPLE: + case SIMPLE_COMPLEX: case COMPLEX: cn = createDirectCategoryPath(this); Composite directDataType = new StructureDataType(cn.getParent(), cn.getName(), 0, @@ -698,7 +699,8 @@ public class CppCompositeType { } directClassLength = getCompositeLength(directDataType); } - if (getLayout(layoutOptions) == ObjectOrientedClassLayout.SIMPLE) { + if (getLayout( + layoutOptions) == ObjectOrientedClassLayout.SIMPLE_COMPLEX) { // Not using the dummy/direct type (only used it to get the // directClassLength), so remove it and add the members to the main // type instead. @@ -768,7 +770,7 @@ public class CppCompositeType { //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- - public void createSpeculativeLayout(ObjectOrientedClassLayoutChoice layoutOptions, + public void createSpeculativeLayout(ObjectOrientedClassLayout layoutOptions, VbtManager vbtManager, TaskMonitor monitor) throws PdbException, CancelledException { // Speculative Layout uses recursion to try to know the order of members. However, MSFT // rearranges the order of the Base Class records such that they are not necessarily in @@ -783,14 +785,14 @@ public class CppCompositeType { case MEMBERS_ONLY: addLayoutPdbMembers(memberData, layoutMembers); break; - case BASIC: + case BASIC_SIMPLE_COMPLEX: cn = composite.getCategoryPath(); addLayoutPdbMembers(memberData, layoutMembers); insertVirtualFunctionTablePointers(memberData); break; // TODO: evaluate... not really getting difference I thought we could get... so far // BASIC and SIMPLE seem to yield the same results. I might be doing something wrong. - case SIMPLE: + case SIMPLE_COMPLEX: case COMPLEX: cn = createDirectCategoryPath(this); Composite directDataType = new StructureDataType(cn.getParent(), cn.getName(), 0, @@ -834,7 +836,8 @@ public class CppCompositeType { } directClassLength = getCompositeLength(directDataType); } - if (getLayout(layoutOptions) == ObjectOrientedClassLayout.SIMPLE) { + if (getLayout( + layoutOptions) == ObjectOrientedClassLayout.SIMPLE_COMPLEX) { // Not using the dummy/direct type (only used it to get the // directClassLength), so remove it and add the members to the main // type instead. @@ -1349,7 +1352,8 @@ public class CppCompositeType { return attributes; } - ObjectOrientedClassLayout getLayoutMode(ObjectOrientedClassLayoutChoice layoutOptions) { + ObjectOrientedClassLayout getLayoutMode( + ObjectOrientedClassLayout layoutOptions) { return baseClassType.getLayout(layoutOptions); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java index 3efb7eaf80..bffd709ee3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/NestedTypeApplier.java @@ -27,17 +27,8 @@ import ghidra.util.exception.CancelledException; * Applier for {@link AbstractNestedTypeMsType} and {@link AbstractNestedTypeExtMsType} types. */ public class NestedTypeApplier extends MsTypeApplier { - private MsTypeApplier nestedTypeDefinitionApplier = null; - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractNestedTypeMsType) && - !(type instanceof AbstractNestedTypeExtMsType)) { - throw new IllegalArgumentException("PDB Incorrectly applying " + - type.getClass().getSimpleName() + " to " + NestedTypeApplier.class.getSimpleName()); - } - return type; - } + private MsTypeApplier nestedTypeDefinitionApplier = null; /** * Constructor for nested type applier. @@ -168,4 +159,15 @@ public class NestedTypeApplier extends MsTypeApplier { MsTypeApplier getNestedTypeApplier() { return nestedTypeDefinitionApplier; } + + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractNestedTypeMsType) && + !(type instanceof AbstractNestedTypeExtMsType)) { + throw new IllegalArgumentException("PDB Incorrectly applying " + + type.getClass().getSimpleName() + " to " + NestedTypeApplier.class.getSimpleName()); + } + return type; + } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayout.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayout.java index 9fc06a52af..f53b4bd7d1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayout.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayout.java @@ -16,10 +16,30 @@ package ghidra.app.util.pdb.pdbapplicator; /** - * Algorithm layout mechanism being used for a particular {@link CppCompositeType}. An initial - * value gets passed in to the algorithm but can be changed by the algorithm, based on class - * internal data. + * PDB Analyzer user algorithmic choice for performing object oriented class layout. + *

    + * Actual algorithms determination is as follows: + * {@link #MEMBERS_ONLY} is a fixed setting. The others weigh the setting against the data + * available in the class records. They all start out as {@link #COMPLEX} but fall back to a + * more simplistic layout when the data permits: + *

    {@link #SIMPLE_COMPLEX} can fall back to "simple" and + *

    {@link #BASIC_SIMPLE_COMPLEX} can fall back to "simple" or "basic" */ -enum ObjectOrientedClassLayout { - UNKNOWN, MEMBERS_ONLY, BASIC, SIMPLE, COMPLEX +public enum ObjectOrientedClassLayout { + MEMBERS_ONLY("Legacy"), + BASIC_SIMPLE_COMPLEX("Complex with Basic Fallback"), + SIMPLE_COMPLEX("Complex with Simple Fallback"), + COMPLEX("Complex Always"); + + private final String label; + + @Override + public String toString() { + return label; + } + + private ObjectOrientedClassLayout(String label) { + this.label = label; + } + } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayoutChoice.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayoutChoice.java deleted file mode 100644 index feea4956c3..0000000000 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ObjectOrientedClassLayoutChoice.java +++ /dev/null @@ -1,56 +0,0 @@ -/* ### - * IP: GHIDRA - * - * 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. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.app.util.pdb.pdbapplicator; - -import java.util.HashMap; -import java.util.Map; - -/** - * PDB Analyzer user algorithmic choice for performing object oriented class layout. - */ -public enum ObjectOrientedClassLayoutChoice { - MEMBERS_ONLY("Legacy", 0, ObjectOrientedClassLayout.MEMBERS_ONLY), - BASIC_SIMPLE_COMPLEX("Complex with Basic Fallback", 1, ObjectOrientedClassLayout.BASIC), - SIMPLE_COMPLEX("Complex with Simple Fallback", 2, ObjectOrientedClassLayout.SIMPLE), - COMPLEX("Complex Always", 3, ObjectOrientedClassLayout.COMPLEX); - - private static final Map BY_VALUE = new HashMap<>(); - static { - for (ObjectOrientedClassLayoutChoice val : values()) { - BY_VALUE.put(val.value, val); - } - } - - private final String label; - private final int value; - private ObjectOrientedClassLayout classLayout; - - @Override - public String toString() { - return label; - } - - private ObjectOrientedClassLayoutChoice(String label, int value, - ObjectOrientedClassLayout classLayout) { - this.label = label; - this.value = value; - this.classLayout = classLayout; - } - - ObjectOrientedClassLayout getClassLayout() { - return classLayout; - } -} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index 4453964378..98f22a9dc4 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -33,7 +33,7 @@ import ghidra.util.exception.CancelledException; */ public class PdbAddressManager { - private static final Address badAddress = Address.NO_ADDRESS; // using NO_ADDRESS as a marker + private static final Address BAD_ADDRESS = Address.NO_ADDRESS; // using NO_ADDRESS as a marker //============================================================================================== private Map realAddressesBySection; @@ -306,10 +306,10 @@ public class PdbAddressManager { if (lookup == null) { remapAddressByAddress.put(address, remapAddress); } - else if (!lookup.equals(remapAddress) && lookup != badAddress) { + else if (!lookup.equals(remapAddress) && lookup != BAD_ADDRESS) { applicator.appendLogMsg("Trying to map a mapped address to a new address... key: " + address + ", currentMap: " + lookup + ", newMap: " + remapAddress); - remapAddressByAddress.put(address, badAddress); + remapAddressByAddress.put(address, BAD_ADDRESS); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java index dd90917bcc..8e0f6942c6 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java @@ -34,7 +34,7 @@ public class PdbApplicatorMetrics { * List of symbols seen (by their ID) as Global symbols. */ //@formatter:off - private static final Set expectedGlobalSymbols = Set.of( + private static final Set EXPECTED_GLOBAL_SYMBOLS = Set.of( // AbstractReferenceMsSymbol DataReferenceStMsSymbol.PDB_ID, DataReferenceMsSymbol.PDB_ID, @@ -79,7 +79,7 @@ public class PdbApplicatorMetrics { * List of symbols seen (by their ID) as Public symbols. */ //@formatter:off - private static final Set expectedLinkerSymbols = Set.of( + private static final Set EXPECTED_LINKER_SYMBOLS = Set.of( PeCoffSectionMsSymbol.PDB_ID, TrampolineMsSymbol.PDB_ID, ObjectNameMsSymbol.PDB_ID, @@ -123,7 +123,7 @@ public class PdbApplicatorMetrics { * @param symbol The symbol type witnessed. */ void witnessGlobalSymbolType(AbstractMsSymbol symbol) { - if (!expectedGlobalSymbols.contains(symbol.getPdbId())) { + if (!EXPECTED_GLOBAL_SYMBOLS.contains(symbol.getPdbId())) { unexpectedGlobalSymbols.add(symbol.getClass()); } } @@ -143,7 +143,7 @@ public class PdbApplicatorMetrics { * @param symbol The symbol type witnessed. */ void witnessLinkerSymbolType(AbstractMsSymbol symbol) { - if (!expectedLinkerSymbols.contains(symbol.getPdbId())) { + if (!EXPECTED_LINKER_SYMBOLS.contains(symbol.getPdbId())) { // do nothing for now } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java index 44d71d276b..f6463ff54f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java @@ -34,14 +34,14 @@ public class PdbApplicatorOptions { // TODO: set the following to true if we come up with a reasonably good solution public static final boolean DEFAULT_APPLY_FUNCTION_VARIABLES = false; - public static final ObjectOrientedClassLayoutChoice DEFAULT_CLASS_LAYOUT_CHOICE = - ObjectOrientedClassLayoutChoice.MEMBERS_ONLY; -// public static final OjbectOrientedClassLayoutChoice DEFAULT_CLASS_LAYOUT_CHOICE = -// OjbectOrientedClassLayoutChoice.BASIC_SIMPLE_COMPLEX; -// public static final OjbectOrientedClassLayoutChoice DEFAULT_CLASS_LAYOUT_CHOICE = -// OjbectOrientedClassLayoutChoice.SIMPLE_COMPLEX; -// public static final OjbectOrientedClassLayoutChoice DEFAULT_CLASS_LAYOUT_CHOICE = -// OjbectOrientedClassLayoutChoice.COMPLEX; + public static final ObjectOrientedClassLayout DEFAULT_CLASS_LAYOUT = + ObjectOrientedClassLayout.MEMBERS_ONLY; +// public static final OjbectOrientedClassLayout DEFAULT_CLASS_LAYOUT = +// ObjectOrientedClassLayout.BASIC_SIMPLE_COMPLEX; +// public static final OjbectOrientedClassLayout DEFAULT_CLASS_LAYOUT = +// ObjectOrientedClassLayout.SIMPLE_COMPLEX; +// public static final OjbectOrientedClassLayout DEFAULT_CLASS_LAYOUT = +// ObjectOrientedClassLayout.COMPLEX; //============================================================================================== private boolean applyCodeScopeBlockComments; @@ -53,7 +53,7 @@ public class PdbApplicatorOptions { private boolean applyFunctionVariables; // investigation. might produce bad results. - private ObjectOrientedClassLayoutChoice classLayoutChoice; + private ObjectOrientedClassLayout classLayout; /** * Constructor @@ -73,7 +73,7 @@ public class PdbApplicatorOptions { remapAddressesUsingExistingPublicSymbols = DEFAULT_REMAP_ADDRESSES_USING_EXISTING_SYMBOLS; allowDemotePrimaryMangledSymbols = DEFAULT_ALLOW_DEMOTE_PRIMARY_MANGLED_SYMBOLS; applyFunctionVariables = DEFAULT_APPLY_FUNCTION_VARIABLES; - classLayoutChoice = DEFAULT_CLASS_LAYOUT_CHOICE; + classLayout = DEFAULT_CLASS_LAYOUT; } /** @@ -196,18 +196,18 @@ public class PdbApplicatorOptions { /** * Set the class layout. - * @param classLayoutChoice composite layout choice + * @param classLayout composite layout */ - public void setClassLayoutChoice(ObjectOrientedClassLayoutChoice classLayoutChoice) { - this.classLayoutChoice = classLayoutChoice; + public void setClassLayout(ObjectOrientedClassLayout classLayout) { + this.classLayout = classLayout; } /** - * Returns the choice for physically layout out classes. + * Returns the physical layout out classes. * @return the class layout. */ - public ObjectOrientedClassLayoutChoice getClassLayoutChoice() { - return classLayoutChoice; + public ObjectOrientedClassLayout getClassLayout() { + return classLayout; } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java index 0d66a4df6f..db8676289d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbRegisterNameToProgramRegisterMapper.java @@ -30,7 +30,7 @@ public class PdbRegisterNameToProgramRegisterMapper { // Only need to map names that are different (probably not counting case, as rsp and RSP // are equivalent. //@formatter:off - private static Map registerNameMap = Map.of( + private static final Map REGISTER_NAME_MAP = Map.of( //"rsp", "RSP", "fbp", "RBP" ); @@ -49,7 +49,7 @@ public class PdbRegisterNameToProgramRegisterMapper { if (register != null) { return register; } - String registerName = registerNameMap.get(pdbRegisterName); + String registerName = REGISTER_NAME_MAP.get(pdbRegisterName); if (registerName == null) { registerName = pdbRegisterName; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java index 0a64a64229..2723897857 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java @@ -41,6 +41,7 @@ public class PdbResearch { //============================================================================================== private static Set debugIndexNumbers; + private Set developerDebugOrderIndexNumbers; //============================================================================================== /** @@ -333,8 +334,6 @@ public class PdbResearch { //============================================================================================== //============================================================================================== - private Set developerDebugOrderIndexNumbers; - private void initDeveloperOrderRecordNumbers() { developerDebugOrderIndexNumbers = new TreeSet<>(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java index c096a6e7b6..cfcfab7680 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/VirtualFunctionTablePointerTypeApplier.java @@ -29,17 +29,6 @@ import ghidra.util.exception.CancelledException; */ public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier { - private static AbstractMsType validateType(AbstractMsType type) - throws IllegalArgumentException { - if (!(type instanceof AbstractVirtualFunctionTablePointerMsType) && - !(type instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType)) { - throw new IllegalArgumentException( - "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + - VirtualFunctionTablePointerTypeApplier.class.getSimpleName()); - } - return type; - } - /** * Constructor for enum type applier, for transforming a enum into a * Ghidra DataType. @@ -99,4 +88,15 @@ public class VirtualFunctionTablePointerTypeApplier extends MsTypeApplier { return null; } + private static AbstractMsType validateType(AbstractMsType type) + throws IllegalArgumentException { + if (!(type instanceof AbstractVirtualFunctionTablePointerMsType) && + !(type instanceof AbstractVirtualFunctionTablePointerWithOffsetMsType)) { + throw new IllegalArgumentException( + "PDB Incorrectly applying " + type.getClass().getSimpleName() + " to " + + VirtualFunctionTablePointerTypeApplier.class.getSimpleName()); + } + return type; + } + } diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java index c30c5c8fdb..d1d4de31a1 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java @@ -52,8 +52,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { private static VbtManager vbtManager32; private static VbtManager vbtManager64; // Note: Currently all test have expected results based on up the COMPLEX layout. - private static ObjectOrientedClassLayoutChoice classLayoutChoice = - ObjectOrientedClassLayoutChoice.COMPLEX; + private static ObjectOrientedClassLayout classLayoutChoice = + ObjectOrientedClassLayout.COMPLEX; static { BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl(); From 71ed2524ce51063e3045f10a0a0d31955c148ba1 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Wed, 9 Sep 2020 15:02:34 -0400 Subject: [PATCH 08/15] GT-3112 - PDB Universal Reader/Analyzer - 119 commits --- .../app/plugin/core/analysis/PdbAnalyzer.java | 2 +- .../core/analysis/PdbUniversalAnalyzer.java | 16 ++++++++---- ...dbLocatorSelector.java => PdbLocator.java} | 6 ++--- .../app/util/pdb/PdbNamespaceUtils.java | 12 ++++----- .../app/util/pdb/PdbProgramAttributes.java | 12 ++++----- .../AbstractComplexTypeApplier.java | 2 +- .../DefaultPdbUniversalMember.java | 25 +++++++++++++------ .../pdb/pdbapplicator/PdbAddressManager.java | 16 ++++++------ .../pdbapplicator/PdbApplicatorOptions.java | 10 ++++---- 9 files changed, 58 insertions(+), 43 deletions(-) rename Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/{PdbLocatorSelector.java => PdbLocator.java} (99%) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java index c16df3987d..51b5f36323 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java @@ -75,7 +75,7 @@ public class PdbAnalyzer extends AbstractAnalyzer { if (pdb == null) { return false; } - Msg.info(this, "Using PDB: " + pdb.getAbsolutePath()); + Msg.info(this, getClass().getSimpleName() + " configured to use: " + pdb.getAbsolutePath()); AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program); return parsePdb(pdb, program, mgr, monitor, log); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java index 219a3e7ba3..5be73c3868 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java @@ -25,7 +25,7 @@ import ghidra.app.services.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.importer.MessageLog; import ghidra.app.util.opinion.PeLoader; -import ghidra.app.util.pdb.PdbLocatorSelector; +import ghidra.app.util.pdb.PdbLocator; import ghidra.app.util.pdb.PdbProgramAttributes; import ghidra.app.util.pdb.pdbapplicator.*; import ghidra.framework.Application; @@ -38,6 +38,7 @@ import ghidra.program.model.listing.Program; import ghidra.util.Msg; import ghidra.util.SystemUtilities; import ghidra.util.bean.opteditor.OptionsVetoException; +import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -257,7 +258,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { // against the "main" category data types. if (oldPdbAnalyzerEnabled(program)) { - log.appendMsg(getName(), "Stopped: Cannot run with other PDB Analyzer enabled"); + log.appendMsg(getName(), "Stopped: Cannot run with DIA-based PDB Analyzer enabled"); return false; } @@ -272,7 +273,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { pdbFilename = forceLoadFile.getAbsolutePath(); } else { - PdbLocatorSelector locator = new PdbLocatorSelector(symbolsRepositoryPath); + PdbLocator locator = new PdbLocator(symbolsRepositoryPath); pdbFilename = locator.findPdb(program, programAttributes, !SystemUtilities.isInHeadlessMode(), includePeSpecifiedPdbPath, monitor, log, getName()); @@ -280,7 +281,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { return false; } } - Msg.info(this, "Using PDB: " + pdbFilename); + Msg.info(this, getClass().getSimpleName() + " configured to use: " + pdbFilename); PdbLog.message( "================================================================================"); @@ -474,7 +475,10 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { String oldPdbNAME = "PDB"; // This assert is just to catch us if we change the new NAME to what the old name is // without first eliminating the call to this method and this method altogether. - assert !NAME.contentEquals(oldPdbNAME); + if (NAME.contentEquals(oldPdbNAME)) { + throw new AssertException( + "Developer error: old and new PDB analyzers were not renamed correctly"); + } Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES); // Don't have access to ghidra.app.plugin.core.analysis.PdbAnalyzer.NAME so using string. boolean isPdbEnabled = analysisOptions.getBoolean(oldPdbNAME, false); @@ -538,6 +542,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { catch (IOException e) { // Probably could not open the file. if (messageLog != null) { + messageLog.appendMsg(getClass().getSimpleName(), + "IOException when trying to open PdbLog file: "); messageLog.appendException(e); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocatorSelector.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocator.java similarity index 99% rename from Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocatorSelector.java rename to Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocator.java index 45f50682bb..73d662c396 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocatorSelector.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbLocator.java @@ -34,7 +34,7 @@ import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; /** - * Searches for and presents PDB path information if order specified by + * Searches for and presents PDB path information in order specified by * * Symbol Paths. *

    @@ -68,7 +68,7 @@ import ghidra.util.task.TaskMonitor; * *

    */ -public class PdbLocatorSelector { +public class PdbLocator { public static final File SPECIAL_PDB_LOCATION = new File("C:/WINDOWS/Symbols"); public static final boolean onWindows = @@ -80,7 +80,7 @@ public class PdbLocatorSelector { */ private Map identifiersByFilePath = new HashMap<>(); - public PdbLocatorSelector(File symbolsRepositoryPath) { + public PdbLocator(File symbolsRepositoryPath) { this.symbolsRepositoryPath = symbolsRepositoryPath; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java index db8901d521..ad526a9196 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbNamespaceUtils.java @@ -33,9 +33,9 @@ public class PdbNamespaceUtils { * * @param symbolPath the source {@link SymbolPath} * @param index the index number used be used as part of a unique tag name. - * @return the resulting ({@link SymbolPath} + * @return the resulting {@link SymbolPath} */ - public static SymbolPath getFixUpSymbolPathNameOnly(SymbolPath symbolPath, int index) { + public static SymbolPath convertToGhidraPathName(SymbolPath symbolPath, int index) { symbolPath = symbolPath.replaceInvalidChars(); return new SymbolPath(symbolPath.getParent(), fixUnnamed(symbolPath.getName(), index)); } @@ -43,9 +43,9 @@ public class PdbNamespaceUtils { /** * Fixes {@link SymbolPath} name, eliminating invalid characters * @param symbolPath the source {@link SymbolPath} - * @return the resulting ({@link SymbolPath} + * @return the resulting {@link SymbolPath} */ - public static SymbolPath getFixUpSymbolPathNameOnly(SymbolPath symbolPath) { + public static SymbolPath convertToGhidraPathName(SymbolPath symbolPath) { symbolPath = symbolPath.replaceInvalidChars(); return symbolPath; } @@ -59,9 +59,9 @@ public class PdbNamespaceUtils { * * @param symbolPath the source {@link SymbolPath} * @param index the index number used be used as part of a unique tag name. - * @return the resulting ({@link SymbolPath} + * @return the resulting {@link SymbolPath} */ - public static SymbolPath getFixUpSymbolPath(SymbolPath symbolPath, int index) { + public static SymbolPath convertToGhidraPath(SymbolPath symbolPath, int index) { symbolPath = symbolPath.replaceInvalidChars(); List modList = new ArrayList<>(); for (String str : symbolPath.asList()) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbProgramAttributes.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbProgramAttributes.java index 97c75c4778..d381ea44ff 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbProgramAttributes.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/PdbProgramAttributes.java @@ -117,22 +117,22 @@ public class PdbProgramAttributes { if (potentialPdbFilenames == null) { // Want to preserve add order while only keeping unique entries - Set setOfPotentialFilenames = new LinkedHashSet<>(); + Set set = new LinkedHashSet<>(); if (pdbFile != null) { - setOfPotentialFilenames.add(getFilename(pdbFile).toLowerCase()); - setOfPotentialFilenames.add(getFilename(pdbFile)); - setOfPotentialFilenames.add(pdbFile); + set.add(getFilename(pdbFile).toLowerCase()); + set.add(getFilename(pdbFile)); + set.add(pdbFile); } // getExecutablePath can return "unknown" if (!executablePath.equals("unknown")) { String executableFilename = getFilename(executablePath); - setOfPotentialFilenames.add( + set.add( getBinaryBasename(executableFilename).toLowerCase() + ".pdb"); } - potentialPdbFilenames = new ArrayList<>(setOfPotentialFilenames); + potentialPdbFilenames = new ArrayList<>(set); } return potentialPdbFilenames; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java index 0e6aa131ca..5273bc3643 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractComplexTypeApplier.java @@ -95,7 +95,7 @@ public abstract class AbstractComplexTypeApplier extends MsTypeApplier { return fixedSymbolPath; } - SymbolPath fixed = PdbNamespaceUtils.getFixUpSymbolPathNameOnly(symbolPath, index); + SymbolPath fixed = PdbNamespaceUtils.convertToGhidraPathName(symbolPath, index); if (symbolPath.equals(fixed)) { fixedSymbolPath = symbolPath; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java index dd77d873db..87452478b9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java @@ -79,20 +79,29 @@ public class DefaultPdbUniversalMember extends PdbMember { @Override public String toString() { - String str = "name=" + getName(); + StringBuilder builder = new StringBuilder(); + builder.append("name="); + builder.append(getName()); + DataType dt = getDataTypeInternal(); if (dt instanceof PdbBitField) { PdbBitField bfDt = (PdbBitField) dataType; - str += ", type=" + bfDt.getBaseDataType().getName(); - str += ", offset=" + getOffset(); - str += ", bitSize=" + bfDt.getDeclaredBitSize() + ", bitOffset=" + - bfDt.getBitOffsetWithinBase(); + builder.append(", type="); + builder.append(bfDt.getBaseDataType().getName()); + builder.append(", offset="); + builder.append(getOffset()); + builder.append(", bitSize="); + builder.append(bfDt.getDeclaredBitSize()); + builder.append(", bitOffset="); + builder.append(bfDt.getBitOffsetWithinBase()); } else { - str += ", type=" + dataType.getName(); - str += ", offset=" + getOffset(); + builder.append(", type="); + builder.append(dataType.getName()); + builder.append(", offset="); + builder.append(getOffset()); } - return str; + return builder.toString(); } @Override diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index 98f22a9dc4..6c87c6c84d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -42,16 +42,16 @@ public class PdbAddressManager { private List allSegmentsInfo; // Map of Address by symbol name... if a name has appeared more than once, then the Address - // is written with Address.NO_ADDRESS to indicate that the name is found at more than one - // address (not unique from the perspective we need of being able to map PDB addresses to - // possibly different addresses (possibly from an application of another PDB with accurate - // public or "unique" symbols). Originally, we were only going to use symbols with mangled - // names, but opened this up to a wider field of symbol names. + // is written with Address.NO_ADDRESS to indicate that the name is found at more than one + // address (not unique from the perspective we need of being able to map PDB addresses to + // possibly different addresses (possibly from an application of another PDB with accurate + // public or "unique" symbols). Originally, we were only going to use symbols with mangled + // names, but opened this up to a wider field of symbol names. private Map addressByPreExistingSymbolName; // Since we are already visiting all existing symbols, and since it will be quicker to do in - // one pass than to continually request the primary symbol at a particular address (as we - // are also adding more symbols), we will get an initial snapshot of what symbol is primary - // at any particular address before we start adding more. + // one pass than to continually request the primary symbol at a particular address (as we + // are also adding more symbols), we will get an initial snapshot of what symbol is primary + // at any particular address before we start adding more. private Map primarySymbolByAddress; private Map remapAddressByAddress; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java index f6463ff54f..61b951e514 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java @@ -36,11 +36,11 @@ public class PdbApplicatorOptions { public static final ObjectOrientedClassLayout DEFAULT_CLASS_LAYOUT = ObjectOrientedClassLayout.MEMBERS_ONLY; -// public static final OjbectOrientedClassLayout DEFAULT_CLASS_LAYOUT = +// public static final ObjectOrientedClassLayout DEFAULT_CLASS_LAYOUT = // ObjectOrientedClassLayout.BASIC_SIMPLE_COMPLEX; -// public static final OjbectOrientedClassLayout DEFAULT_CLASS_LAYOUT = +// public static final ObjectOrientedClassLayout DEFAULT_CLASS_LAYOUT = // ObjectOrientedClassLayout.SIMPLE_COMPLEX; -// public static final OjbectOrientedClassLayout DEFAULT_CLASS_LAYOUT = +// public static final ObjectOrientedClassLayout DEFAULT_CLASS_LAYOUT = // ObjectOrientedClassLayout.COMPLEX; //============================================================================================== @@ -59,13 +59,13 @@ public class PdbApplicatorOptions { * Constructor */ public PdbApplicatorOptions() { - setDefaults(); + restoreDefaults(); } /** * Set the options back to their default values */ - public void setDefaults() { + public void restoreDefaults() { applyCodeScopeBlockComments = DEFAULT_APPLY_CODE_SCOPE_BLOCK_COMMENTS; applyInstructionLabels = DEFAULT_APPLY_INSTRUCTION_LABELS; applyDataTypesOnly = DEFAULT_APPLY_DATA_TYPES_ONLY; From d09a5740e00ec60bb8781e7c17237230e9daaaed Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Wed, 9 Sep 2020 15:45:56 -0400 Subject: [PATCH 09/15] GT-3112 - PDB Universal Reader/Analyzer - 120 commits --- .../bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java index 79847bd733..af31beeb1d 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/msf/MsfReaderUnitTest.java @@ -16,6 +16,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader.msf; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import java.io.*; import java.util.*; @@ -273,9 +274,7 @@ public class MsfReaderUnitTest extends AbstractGenericTest { void reservePage(int pageNumber) { if (!freePage[pageNumber]) { - String msg = "Page already free... terminating"; - Msg.error(null, msg); - throw new AssertException(msg); + fail("Page already free... terminating"); } freePage[pageNumber] = false; } From 1b9cf4a274ee4cf480e33ccb8b5f59e2b227513c Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Wed, 9 Sep 2020 16:24:02 -0400 Subject: [PATCH 10/15] GT-3112 - PDB Universal Reader/Analyzer - 121 commits --- .../ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java | 7 +++---- .../ghidra/app/util/pdb/pdbapplicator/PdbResearch.java | 2 +- .../app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java | 2 +- .../util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java | 7 ++----- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java index 78c67eb752..d48d76bf2d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsSymbolApplier.java @@ -43,7 +43,7 @@ public abstract class MsSymbolApplier { */ public MsSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { Objects.requireNonNull(applicator, "applicator cannot be null"); - Objects.requireNonNull(iter, "symbolGroup cannot be null"); + Objects.requireNonNull(iter, "iter cannot be null"); this.applicator = applicator; this.iter = iter; currentOffset = iter.getCurrentOffset(); @@ -76,13 +76,12 @@ public abstract class MsSymbolApplier { /** * Applies logic of this class to another {@link MsSymbolApplier} instead of to - * "the program." + * the program. * @param applyToApplier the applier to which the logic of this class is applied. * @throws PdbException if there was a problem processing the data. * @throws CancelledException upon user cancellation. */ - abstract void applyTo(MsSymbolApplier applyToApplier) - throws PdbException, CancelledException; + abstract void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException; /** * Manages block nesting for symbols/appliers that represent the beginning or end of blocks. diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java index 2723897857..e42eb782eb 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java @@ -32,7 +32,7 @@ import mdemangler.*; import mdemangler.object.MDObjectCPP; /** - * This is a class for develop research into various areas. Anything in this class that needs to + * This class is for developer research into various areas. Anything in this class that needs to * end up as part of any usable output should be moved into another class. This class just * aggregates various items being investigated, and will eventually be eliminated from the code * base. diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java index cbb7e39c73..a2d60bffaf 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/PdbByteWriter.java @@ -253,7 +253,7 @@ public class PdbByteWriter { public void putGUID(int data1, short data2, short data3, byte[] data4) { if (data4.length != 8) { String msg = "GUID invalid byte[] size... terminating"; - Msg.error(null, msg); + Msg.error(this, msg); throw new AssertException(msg); } putInt(data1); diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java index 0256333492..c93d522862 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/bin/format/pdb2/pdbreader/symbol/SymbolsTest.java @@ -16,6 +16,7 @@ package ghidra.app.util.bin.format.pdb2.pdbreader.symbol; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import java.math.BigInteger; @@ -26,8 +27,6 @@ import generic.test.AbstractGenericTest; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.DummyMsType; -import ghidra.util.Msg; -import ghidra.util.exception.AssertException; public class SymbolsTest extends AbstractGenericTest { @@ -63,9 +62,7 @@ public class SymbolsTest extends AbstractGenericTest { dummyPdb700.setItemRecord(4096, item); } catch (Exception e) { - String msg = "Error in static initialization of testt: " + e; - Msg.error(null, msg); - throw new AssertException(msg); + fail("Error in static initialization of test: " + e); } } From 1a6cf81d919ae4d45041ba13ce0d5d16b0a7216a Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Tue, 15 Sep 2020 16:23:36 -0400 Subject: [PATCH 11/15] GT-3112 - PDB Universal Reader/Analyzer - 122 commits --- .../core/analysis/PdbUniversalAnalyzer.java | 93 +++++------ .../pdb/pdbapplicator/DataSymbolApplier.java | 25 +-- .../pdbapplicator/FunctionSymbolApplier.java | 100 ++++++------ .../pdb/pdbapplicator/LabelSymbolApplier.java | 3 + .../pdb/pdbapplicator/PdbAddressManager.java | 146 ++++++++++++------ .../util/pdb/pdbapplicator/PdbApplicator.java | 75 +++++++-- .../pdbapplicator/PdbApplicatorMetrics.java | 10 +- .../pdbapplicator/PdbApplicatorOptions.java | 43 ++---- .../PdbApplicatorRestrictions.java | 35 +++++ .../util/pdb/pdbapplicator/PdbResearch.java | 10 +- .../util/pdb/pdbapplicator/PdbVbtManager.java | 4 +- .../PeCoffGroupSymbolApplier.java | 8 +- .../pdbapplicator/PublicSymbolApplier.java | 24 ++- .../SeparatedCodeSymbolApplier.java | 3 + .../TrampolineSymbolApplier.java | 10 +- 15 files changed, 349 insertions(+), 240 deletions(-) create mode 100644 Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorRestrictions.java diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java index 5be73c3868..1d104d0cd2 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java @@ -134,17 +134,11 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { //============================================================================================== // PdbApplicator options //============================================================================================== - // Apply Data Types Only. - private static final String OPTION_NAME_APPLY_DATA_TYPES_ONLY = "Apply Data Types Only"; - private static final String OPTION_DESCRIPTION_APPLY_DATA_TYPES_ONLY = - "If checked, only applies data types to program."; - private boolean applyDataTypesOnly; - - // Apply Public Symbols Only. - private static final String OPTION_NAME_PUBLIC_SYMBOLS_ONLY = "Apply Public Symbols Only"; - private static final String OPTION_DESCRIPTION_PUBLIC_SYMBOLS_ONLY = - "If checked, only applies public symbols to program. Does not apply data types."; - private boolean applyPublicSymbolsOnly; + // Applicator Restrictions. + private static final String OPTION_NAME_PROCESSING_RESTRICTIONS = "Processing Restrictions"; + private static final String OPTION_DESCRIPTION_PROCESSING_RESTRICTIONS = + "Restrictions on applicator processing."; + private static PdbApplicatorRestrictions restrictions; // Apply Code Block Comments. private static final String OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS = @@ -206,10 +200,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { //============================================================================================== // Additional instance data //============================================================================================== - private AbstractPdb myPdb = null; private PdbReaderOptions pdbReaderOptions; private PdbApplicatorOptions pdbApplicatorOptions; - private MessageLog messageLog = null; //============================================================================================== //============================================================================================== @@ -245,7 +237,6 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException { - messageLog = log; // TODO: // Work on use cases... // Code for checking if the PDB is already loaded (... assumes it was analyzed as well). @@ -268,6 +259,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { return true; } + setPdbLogging(log); + String pdbFilename; if (doForceLoad) { pdbFilename = forceLoadFile.getAbsolutePath(); @@ -292,10 +285,9 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { PdbLog.message("PDB Filename: " + pdbFilename + "\n"); try (AbstractPdb pdb = PdbParser.parse(pdbFilename, pdbReaderOptions, monitor)) { - myPdb = pdb; monitor.setMessage("PDB: Parsing " + pdbFilename + "..."); pdb.deserialize(monitor); - PdbApplicator applicator = new PdbApplicator(pdbFilename, myPdb); + PdbApplicator applicator = new PdbApplicator(pdbFilename, pdb); applicator.applyTo(program, program.getDataTypeManager(), program.getImageBase(), pdbApplicatorOptions, monitor, log); } @@ -348,17 +340,6 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { @Override public void registerOptions(Options options, Program program) { - // TODO: keeping around while still developing, but eventually delete these. -// options.removeOption(OPTION_NAME_DO_FORCELOAD); -// options.removeOption(OPTION_NAME_FORCELOAD_FILE); -// options.removeOption(OPTION_NAME_INCLUDE_PE_PDB_PATH); -// options.removeOption(OPTION_NAME_PDB_READER_ANALYZER_LOGGING); -// options.removeOption(OPTION_NAME_APPLY_INSTRUCTION_LABELS); -// options.removeOption(OPTION_NAME_SYMBOLPATH); -// options.removeOption(OPTION_NAME_ONE_BYTE_CHARSET_NAME); -// options.removeOption(OPTION_NAME_WCHAR_CHARSET_NAME); -// options.removeOption("Analyzers.PDB Universal Reader/Analyzer.Symbol Repository Path"); - // PDB file location information options.registerOption(OPTION_NAME_DO_FORCELOAD, doForceLoad, null, OPTION_DESCRIPTION_DO_FORCELOAD); @@ -373,31 +354,40 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { getPdbReaderOptions(); options.registerOption(OPTION_NAME_PDB_READER_ANALYZER_LOGGING, pdbLogging, null, OPTION_DESCRIPTION_PDB_READER_ANALYZER_LOGGING); - options.registerOption(OPTION_NAME_ONE_BYTE_CHARSET_NAME, oneByteCharsetName, null, - OPTION_DESCRIPTION_ONE_BYTE_CHARSET_NAME); - options.registerOption(OPTION_NAME_WCHAR_CHARSET_NAME, wideCharCharsetName, null, - OPTION_DESCRIPTION_WCHAR_CHARSET_NAME); + if (developerMode) { + options.registerOption(OPTION_NAME_ONE_BYTE_CHARSET_NAME, oneByteCharsetName, null, + OPTION_DESCRIPTION_ONE_BYTE_CHARSET_NAME); + options.registerOption(OPTION_NAME_WCHAR_CHARSET_NAME, wideCharCharsetName, null, + OPTION_DESCRIPTION_WCHAR_CHARSET_NAME); + } // PdbApplicatorOptions getPdbApplicatorOptions(); - options.registerOption(OPTION_NAME_APPLY_DATA_TYPES_ONLY, applyDataTypesOnly, null, - OPTION_DESCRIPTION_APPLY_DATA_TYPES_ONLY); - options.registerOption(OPTION_NAME_PUBLIC_SYMBOLS_ONLY, applyPublicSymbolsOnly, null, - OPTION_DESCRIPTION_PUBLIC_SYMBOLS_ONLY); + options.registerOption(OPTION_NAME_PROCESSING_RESTRICTIONS, restrictions, null, + OPTION_DESCRIPTION_PROCESSING_RESTRICTIONS); options.registerOption(OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, applyCodeScopeBlockComments, null, OPTION_DESCRIPTION_APPLY_CODE_SCOPE_BLOCK_COMMENTS); if (developerMode) { // Mechanism to apply instruction labels is not yet implemented-> does nothing options.registerOption(OPTION_NAME_APPLY_INSTRUCTION_LABELS, applyInstructionLabels, null, OPTION_DESCRIPTION_APPLY_INSTRUCTION_LABELS); + // The remap capability is not completely implemented... do not turn on. options.registerOption(OPTION_NAME_ADDRESS_REMAP, remapAddressUsingExistingPublicMangledSymbols, null, OPTION_DESCRIPTION_ADDRESS_REMAP); options.registerOption(OPTION_NAME_ALLOW_DEMOTE_MANGLED_PRIMARY, allowDemotePrimaryMangledSymbol, null, OPTION_DESCRIPTION_ALLOW_DEMOTE_MANGLED_PRIMARY); + // Function params and local implementation is not complete... do not turn on. options.registerOption(OPTION_NAME_APPLY_FUNCTION_VARIABLES, applyFunctionVariables, null, OPTION_DESCRIPTION_APPLY_FUNCTION_VARIABLES); + // Object-oriented composite layout is fairly far along, but its use will likely not + // be forward compatible with future Ghidra work in this area; i.e., it might leave + // the data type manager in a bad state for future revisions. While the current + // layout mechanism might work, I will likely change it to, instead, create a + // syntactic intermediate representation before creating the final layout. This will + // aid portability between tool chains and versions and yield a standard way of + // data-basing and presenting the information to a user. options.registerOption(OPTION_NAME_COMPOSITE_LAYOUT, compositeLayout, null, OPTION_DESCRIPTION_COMPOSITE_LAYOUT); } @@ -438,21 +428,18 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { includePeSpecifiedPdbPath = options.getBoolean(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath); - pdbLogging = options.getBoolean(OPTION_NAME_PDB_READER_ANALYZER_LOGGING, pdbLogging); - setPdbLogging(); - // PdbReaderOptions - oneByteCharsetName = - options.getString(OPTION_NAME_ONE_BYTE_CHARSET_NAME, oneByteCharsetName); - wideCharCharsetName = - options.getString(OPTION_NAME_WCHAR_CHARSET_NAME, wideCharCharsetName); + pdbLogging = options.getBoolean(OPTION_NAME_PDB_READER_ANALYZER_LOGGING, pdbLogging); + if (developerMode) { + oneByteCharsetName = + options.getString(OPTION_NAME_ONE_BYTE_CHARSET_NAME, oneByteCharsetName); + wideCharCharsetName = + options.getString(OPTION_NAME_WCHAR_CHARSET_NAME, wideCharCharsetName); + } setPdbReaderOptions(); // PdbApplicatorOptions - applyDataTypesOnly = - options.getBoolean(OPTION_NAME_APPLY_DATA_TYPES_ONLY, applyDataTypesOnly); - applyPublicSymbolsOnly = - options.getBoolean(OPTION_NAME_PUBLIC_SYMBOLS_ONLY, applyPublicSymbolsOnly); + restrictions = options.getEnum(OPTION_NAME_PROCESSING_RESTRICTIONS, restrictions); applyCodeScopeBlockComments = options.getBoolean( OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, applyCodeScopeBlockComments); if (developerMode) { @@ -535,16 +522,16 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { return true; } - private void setPdbLogging() { + private void setPdbLogging(MessageLog log) { try { PdbLog.setEnabled(pdbLogging); } catch (IOException e) { // Probably could not open the file. - if (messageLog != null) { - messageLog.appendMsg(getClass().getSimpleName(), + if (log != null) { + log.appendMsg(getClass().getSimpleName(), "IOException when trying to open PdbLog file: "); - messageLog.appendException(e); + log.appendException(e); } } } @@ -561,8 +548,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { private void getPdbApplicatorOptions() { applyCodeScopeBlockComments = PdbApplicatorOptions.DEFAULT_APPLY_CODE_SCOPE_BLOCK_COMMENTS; - applyDataTypesOnly = PdbApplicatorOptions.DEFAULT_APPLY_DATA_TYPES_ONLY; - applyPublicSymbolsOnly = PdbApplicatorOptions.DEFAULT_APPLY_PUBLIC_SYMBOLS_ONLY; + restrictions = PdbApplicatorOptions.DEFAULT_RESTRICTIONS; applyInstructionLabels = PdbApplicatorOptions.DEFAULT_APPLY_INSTRUCTION_LABELS; remapAddressUsingExistingPublicMangledSymbols = @@ -574,8 +560,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { } private void setPdbApplicatorOptions() { - pdbApplicatorOptions.setApplyDataTypesOnly(applyDataTypesOnly); - pdbApplicatorOptions.setApplyPublicSymbolsOnly(applyPublicSymbolsOnly); + pdbApplicatorOptions.setRestrictions(restrictions); pdbApplicatorOptions.setApplyCodeScopeBlockComments(applyCodeScopeBlockComments); pdbApplicatorOptions.setApplyInstructionLabels(applyInstructionLabels); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java index ed9d544652..e2563c6137 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DataSymbolApplier.java @@ -39,7 +39,6 @@ public class DataSymbolApplier extends MsSymbolApplier { * Constructor * @param applicator the {@link PdbApplicator} for which we are working. * @param iter the Iterator containing the symbol sequence being processed - * @throws CancelledException upon user cancellation */ public DataSymbolApplier(PdbApplicator applicator, AbstractMsSymbolIterator iter) { super(applicator, iter); @@ -55,9 +54,6 @@ public class DataSymbolApplier extends MsSymbolApplier { void applyTo(MsSymbolApplier applyToApplier) throws PdbException, CancelledException { if (applyToApplier instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applyToApplier; - if (symbol.getSegment() == 0 && symbol.getOffset() == 0L) { - return; // silently return. - } MsTypeApplier applier = getTypeApplier(); DataType dataType = applier.getDataType(); if (dataType == null) { // TODO: check that we can have null here. @@ -65,21 +61,22 @@ public class DataSymbolApplier extends MsSymbolApplier { } String name = symbol.getName(); Address address = applicator.getAddress(symbol); - + if (applicator.isInvalidAddress(address, symbol.getName())) { + return; + } functionSymbolApplier.setLocalVariable(address, name, dataType); } } @Override void apply() throws CancelledException, PdbException { - // skip if both zero (i.e,. process if either is not zero) - if (symbol.getSegment() != 0 || symbol.getOffset() != 0L) { - Address symbolAddress = applicator.getAddress(symbol); - Address remapAddress = applicator.getRemapAddressByAddress(symbolAddress); - RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); - applicator.createSymbol(symbolAddress, symbol.getName(), true); - createData(remapAddress, typeRecordNumber); + Address symbolAddress = applicator.getAddress(symbol); + if (applicator.isInvalidAddress(symbolAddress, symbol.getName())) { + return; } + RecordNumber typeRecordNumber = symbol.getTypeRecordNumber(); + applicator.createSymbol(symbolAddress, symbol.getName(), true); + createData(symbolAddress, typeRecordNumber); } MsTypeApplier getTypeApplier() { @@ -102,6 +99,10 @@ public class DataSymbolApplier extends MsSymbolApplier { } return; } + if (applicator.getImageBase().equals(address) && + !"_IMAGE_DOS_HEADER".equals(dataType.getName())) { + return; // Squash some noise + } if (!(dataType instanceof FunctionDefinition)) { //TODO: might want to do an ApplyDatatypeCmd here!!! DumbMemBufferImpl memBuffer = diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 95d79a87ac..36c6038f33 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -41,10 +41,9 @@ public class FunctionSymbolApplier extends MsSymbolApplier { private static final String BLOCK_INDENT = " "; - private AbstractProcedureMsSymbol procedureSymbol; - private AbstractThunkMsSymbol thunkSymbol; + private AddressMsSymbol symbol; private Address specifiedAddress; - private Address remapAddress; + private Address address; private Function function = null; private long specifiedFrameSize = 0; private long currentFrameSize = 0; @@ -75,19 +74,16 @@ public class FunctionSymbolApplier extends MsSymbolApplier { comments = new BlockCommentsManager(); currentBlockAddress = null; - if (abstractSymbol instanceof AbstractProcedureMsSymbol) { - procedureSymbol = (AbstractProcedureMsSymbol) abstractSymbol; - specifiedAddress = applicator.getAddress(procedureSymbol); - } - else if (abstractSymbol instanceof AbstractThunkMsSymbol) { - thunkSymbol = (AbstractThunkMsSymbol) abstractSymbol; - specifiedAddress = applicator.getAddress(thunkSymbol); + if (abstractSymbol instanceof AbstractProcedureMsSymbol || + abstractSymbol instanceof AbstractThunkMsSymbol) { + symbol = (AddressMsSymbol) abstractSymbol; + specifiedAddress = applicator.getRawAddress(symbol); + address = applicator.getAddress(symbol); } else { throw new AssertException( "Invalid symbol type: " + abstractSymbol.getClass().getSimpleName()); } - remapAddress = applicator.getRemapAddressByAddress(specifiedAddress); manageBlockNesting(this); while (notDone()) { @@ -102,16 +98,17 @@ public class FunctionSymbolApplier extends MsSymbolApplier { void manageBlockNesting(MsSymbolApplier applierParam) { if (applierParam instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; - if (procedureSymbol != null) { - long start = procedureSymbol.getDebugStartOffset(); - long end = procedureSymbol.getDebugEndOffset(); - Address blockAddress = remapAddress.add(start); + if (symbol instanceof AbstractProcedureMsSymbol) { + AbstractProcedureMsSymbol sym = (AbstractProcedureMsSymbol) symbol; + long start = sym.getDebugStartOffset(); + long end = sym.getDebugEndOffset(); + Address blockAddress = address.add(start); long length = end - start; - functionSymbolApplier.beginBlock(blockAddress, procedureSymbol.getName(), length); + functionSymbolApplier.beginBlock(blockAddress, sym.getName(), length); } - else if (thunkSymbol != null) { - functionSymbolApplier.beginBlock(remapAddress, thunkSymbol.getName(), - thunkSymbol.getLength()); + else { + AbstractThunkMsSymbol sym = (AbstractThunkMsSymbol) symbol; + functionSymbolApplier.beginBlock(address, sym.getName(), sym.getLength()); } } } @@ -154,11 +151,8 @@ public class FunctionSymbolApplier extends MsSymbolApplier { * @return the function name */ String getName() { - if (procedureSymbol != null) { - return procedureSymbol.getName(); - } - else if (thunkSymbol != null) { - return thunkSymbol.getName(); + if (symbol != null) { + return ((NameMsSymbol) symbol).getName(); } return ""; } @@ -178,13 +172,15 @@ public class FunctionSymbolApplier extends MsSymbolApplier { } boolean applyTo(TaskMonitor monitor) throws PdbException, CancelledException { - return applyTo(applicator.getProgram(), remapAddress, monitor); - } + if (applicator.isInvalidAddress(specifiedAddress, getName())) { + return false; + } + if (!(symbol instanceof AbstractProcedureMsSymbol)) { + return false; + } + AbstractProcedureMsSymbol procedureSymbol = (AbstractProcedureMsSymbol) symbol; - boolean applyTo(Program program, Address address, TaskMonitor monitor) - throws PdbException, CancelledException { - - boolean functionSuccess = applyFunction(program, address, monitor); + boolean functionSuccess = applyFunction(monitor); if (functionSuccess == false) { return false; } @@ -198,7 +194,7 @@ public class FunctionSymbolApplier extends MsSymbolApplier { // comments long addressDelta = address.subtract(specifiedAddress); - comments.applyTo(program, addressDelta); + comments.applyTo(applicator.getProgram(), addressDelta); // line numbers // TODO: not done yet @@ -232,20 +228,20 @@ public class FunctionSymbolApplier extends MsSymbolApplier { comments.addPreComment(currentBlockAddress, comment); } - private boolean applyFunction(Program program, Address address, TaskMonitor monitor) { - Listing listing = program.getListing(); + private boolean applyFunction(TaskMonitor monitor) { + Listing listing = applicator.getProgram().getListing(); applicator.createSymbol(address, getName(), true); function = listing.getFunctionAt(address); if (function == null) { - function = createFunction(program, address, monitor); + function = createFunction(monitor); } if (function != null && !function.isThunk() && (function.getSignatureSource() == SourceType.DEFAULT || function.getSignatureSource() == SourceType.ANALYSIS)) { // Set the function definition - setFunctionDefinition(program, address, monitor); + setFunctionDefinition(monitor); } if (function == null) { @@ -256,10 +252,10 @@ public class FunctionSymbolApplier extends MsSymbolApplier { return true; } - private Function createFunction(Program program, Address address, TaskMonitor monitor) { + private Function createFunction(TaskMonitor monitor) { // Does function already exist? - Function myFunction = program.getListing().getFunctionAt(address); + Function myFunction = applicator.getProgram().getListing().getFunctionAt(address); if (myFunction != null) { // Actually not sure if we should set to 0 or calculate from the function here. // Need to investigate more, so at least keeping it as a separate 'else' for now. @@ -267,25 +263,25 @@ public class FunctionSymbolApplier extends MsSymbolApplier { } // Disassemble - Instruction instr = program.getListing().getInstructionAt(address); + Instruction instr = applicator.getProgram().getListing().getInstructionAt(address); if (instr == null) { DisassembleCommand cmd = new DisassembleCommand(address, null, true); - cmd.applyTo(program, monitor); + cmd.applyTo(applicator.getProgram(), monitor); } - myFunction = createFunctionCommand(program, address, monitor); + myFunction = createFunctionCommand(monitor); return myFunction; } - private boolean setFunctionDefinition(Program program, Address address, TaskMonitor monitor) { - if (procedureSymbol == null) { + private boolean setFunctionDefinition(TaskMonitor monitor) { + if (!(symbol instanceof AbstractProcedureMsSymbol)) { // TODO: is there anything we can do with thunkSymbol? // long x = thunkSymbol.getParentPointer(); return true; } // Rest presumes procedureSymbol. - RecordNumber typeRecordNumber = procedureSymbol.getTypeRecordNumber(); + RecordNumber typeRecordNumber = ((AbstractProcedureMsSymbol) symbol).getTypeRecordNumber(); MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); if (applier == null) { applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " + @@ -308,7 +304,7 @@ public class FunctionSymbolApplier extends MsSymbolApplier { FunctionDefinition def = (FunctionDefinition) dataType; ApplyFunctionSignatureCmd sigCmd = new ApplyFunctionSignatureCmd(address, def, SourceType.IMPORTED); - if (!sigCmd.applyTo(program, monitor)) { + if (!sigCmd.applyTo(applicator.getProgram(), monitor)) { applicator.appendLogMsg( "failed to apply signature to function at address " + address.toString()); return false; @@ -317,13 +313,12 @@ public class FunctionSymbolApplier extends MsSymbolApplier { return true; } - private Function createFunctionCommand(Program program, Address entryPoint, - TaskMonitor monitor) { - CreateFunctionCmd funCmd = new CreateFunctionCmd(entryPoint); - if (!funCmd.applyTo(program, monitor)) { - applicator.appendLogMsg("Failed to apply function at address " + entryPoint.toString() + + private Function createFunctionCommand(TaskMonitor monitor) { + CreateFunctionCmd funCmd = new CreateFunctionCmd(address); + if (!funCmd.applyTo(applicator.getProgram(), monitor)) { + applicator.appendLogMsg("Failed to apply function at address " + address.toString() + "; attempting to use possible existing function"); - return program.getListing().getFunctionAt(entryPoint); + return applicator.getProgram().getListing().getFunctionAt(address); } return funCmd.getFunction(); } @@ -335,7 +330,7 @@ public class FunctionSymbolApplier extends MsSymbolApplier { int endBlock() { if (--symbolBlockNestingLevel < 0) { applicator.appendLogMsg( - "Block Nesting went negative for " + getName() + " at " + remapAddress); + "Block Nesting went negative for " + getName() + " at " + address); } if (symbolBlockNestingLevel == 0) { //currentFunctionSymbolApplier = null; @@ -349,6 +344,9 @@ public class FunctionSymbolApplier extends MsSymbolApplier { if (!applicator.getPdbApplicatorOptions().applyCodeScopeBlockComments()) { return; } + if (applicator.isInvalidAddress(startAddress, name)) { + return; + } String indent = getIndent(nestingLevel); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java index b6884d88ba..53018e150b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/LabelSymbolApplier.java @@ -58,6 +58,9 @@ public class LabelSymbolApplier extends MsSymbolApplier { // Place compiler generated symbols (e.g., $LN9) within containing function when possible String name = symbol.getName(); Address symbolAddress = applicator.getAddress(symbol); + if (applicator.isInvalidAddress(symbolAddress, name)) { + return; + } FunctionManager functionManager = applicator.getProgram().getFunctionManager(); // TODO: What do we do with labels such as this?... "__catch$?test_eh1@@YAHXZ$7" if (name.startsWith("$") && !name.contains(Namespace.DELIMITER)) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index 6c87c6c84d..c4da076a6f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -20,6 +20,7 @@ import java.util.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSpace; import ghidra.program.model.listing.Program; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryBlock; @@ -33,7 +34,11 @@ import ghidra.util.exception.CancelledException; */ public class PdbAddressManager { - private static final Address BAD_ADDRESS = Address.NO_ADDRESS; // using NO_ADDRESS as a marker + // This could be a valid address for the program, but we are using it as a flag. We return + // it to designate that an address is an external address, and we use it outside of this class + // to test for it being an external address. + static final Address EXTERNAL_ADDRESS = AddressSpace.EXTERNAL_SPACE.getAddress(0); + static final Address BAD_ADDRESS = Address.NO_ADDRESS; // using NO_ADDRESS as a marker //============================================================================================== private Map realAddressesBySection; @@ -79,46 +84,90 @@ public class PdbAddressManager { allSegmentsInfo = new ArrayList<>(); addressByPreExistingSymbolName = new HashMap<>(); primarySymbolByAddress = new HashMap<>(); - remapAddressByAddress = new HashMap<>(); determineMemoryBlocks(); mapPreExistingSymbols(); + createAddressRemap(); } /** - * Returns the Address for the given section and offset. + * Returns the Address for the given symbol. If the {@link PdbApplicatorOptions} + * Address Remap option is turned on is turned on, it will attempt to map the address to a + * new address in the current program. * @param symbol The {@link AddressMsSymbol} - * @return The Address + * @return The Address, which can be {@code Address.NO_ADDRESS} if invalid or + * {@code Address.EXTERNAL_ADDRESS} if the address is external to the program. */ - // Returns an address using the section and offset. Address getAddress(AddressMsSymbol symbol) { return getAddress(symbol.getSegment(), symbol.getOffset()); } + /** + * Returns the Address for the given section and offset. If the {@link PdbApplicatorOptions} + * Address Remap option is turned on is turned on, it will attempt to map the address to a + * new address in the current program. + * @param segment The segment + * @param offset The offset + * @return The Address, which can be {@code Address.NO_ADDRESS} if invalid or + * {@code Address.EXTERNAL_ADDRESS} if the address is external to the program. + */ + Address getAddress(int segment, long offset) { + Address address = getRawAddress(segment, offset); + if (applicator.getPdbApplicatorOptions().remapAddressUsingExistingPublicSymbols()) { + return getRemapAddressByAddress(address); + } + return address; + } + + /** + * Returns the Address for the given section and offset. If the {@link PdbApplicatorOptions} + * Address Remap option is turned on is turned on, it will attempt to map the address to a + * new address in the current program. + * @param symbol The {@link AddressMsSymbol} + * @return The Address, which can be {@code Address.NO_ADDRESS} if invalid or + * {@code Address.EXTERNAL_ADDRESS} if the address is external to the program. + */ + Address getRawAddress(AddressMsSymbol symbol) { + return getRawAddress(symbol.getSegment(), symbol.getOffset()); + } + /** * Returns the Address for the given section and offset. Will attempt to map the address * to a new address if the {@link PdbApplicatorOptions} * @param segment The segment * @param offset The offset - * @return The Address, which can be {@code Address.NO_ADDRESS} if it was the original address. + * @return The Address, which can be {@code Address.NO_ADDRESS} if invalid or + * {@code Address.EXTERNAL_ADDRESS} if the address is external to the program. */ - // Returns an address using the section and offset. - Address getAddress(int segment, long offset) { + Address getRawAddress(int segment, long offset) { if (segment < 0 || segment > allSegmentsInfo.size()) { - return Address.NO_ADDRESS; + return BAD_ADDRESS; } else if (segment == allSegmentsInfo.size()) { - // Was getting issues of _IMAGE_DOSHEADER showing up with a segemnt index one - // beyond the end. - segment = 0; // The anomaly of last segment meaning the first. + // External address. + // Was getting issues of _IMAGE_DOSHEADER showing up with a segment index one + // beyond the end. + return EXTERNAL_ADDRESS; } SegmentInfo segmentInfo = allSegmentsInfo.get(segment); if (offset >= segmentInfo.getLength()) { - return Address.NO_ADDRESS; + return BAD_ADDRESS; } return segmentInfo.getStartAddress().add(offset); } + /** + * Returns the Address of an existing symbol for the query address, where the mapping is + * derived by using a the address of a PDB symbol as the key and finding the address of + * a symbol in the program of the same "unique" name. This is accomplished using public + * mangled symbols. If the program symbol came from the PDB, then it maps to itself. + * @param address the query address + * @return the remapAddress + */ + Address getRemapAddressByAddress(Address address) { + return remapAddressByAddress.getOrDefault(address, address); + } + /** * Returns the primary symbol for the address, as determined at the start of PDB processing * before apply any PDB symbols. @@ -145,22 +194,6 @@ public class PdbAddressManager { return existingAddress; } - /** - * Returns the Address of an existing symbol for the query address, where the mapping is - * derived by using a the address of a PDB symbol as the key and finding the address of - * a symbol in the program of the same "unique" name. This is accomplished using public - * mangled symbols. If the program symbol came from the PDB, then it maps to itself. - * @param address the query address - * @return the remapAddress - */ - Address getRemapAddressByAddress(Address address) { - if (!Address.NO_ADDRESS.equals(address) && - applicator.getPdbApplicatorOptions().remapAddressUsingExistingPublicSymbols()) { - return remapAddressByAddress.getOrDefault(address, address); - } - return address; - } - /** * Method for callee to set the real address for the section. * @param sectionNum the section number @@ -217,7 +250,7 @@ public class PdbAddressManager { private void determineMemoryBlocks() { // Set section/segment 0 to image base. (should be what is header), but what is its size? - // TODO... made up size for now... is there something else? We could + // TODO... made up size for now... is there something else? We could long segmentZeroLength = 0x7fffffff; allSegmentsInfo.add(new SegmentInfo(imageBase, segmentZeroLength)); AbstractDatabaseInterface dbi = applicator.getPdb().getDatabaseInterface(); @@ -227,13 +260,14 @@ public class PdbAddressManager { for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) { long virtualAddress = imageSectionHeader.getVirtualAddress(); // TODO: not sure when unionPAVS is physical address vs. virtual size. Perhaps - // it keys off whether virtualAddress is not some special value such as - // 0x00000000 or 0xffffffff. + // it keys off whether virtualAddress is not some special value such as + // 0x00000000 or 0xffffffff. long size = imageSectionHeader.getUnionPAVS(); allSegmentsInfo.add(new SegmentInfo(imageBase.add(virtualAddress), size)); } } // else instance of DatabaseInterface; TODO: what can we do here? + // Maybe get information from the program itself. // TODO: what should we do with these? Not doing anything at the moment AbstractPdb pdb = applicator.getPdb(); @@ -251,6 +285,11 @@ public class PdbAddressManager { * @throws PdbException If Program is null; */ private void mapPreExistingSymbols() throws PdbException { + // Cannot do this commented-out code here... as we are relying on the primary symbol + // map, regardless of the remap... so might need to separate the two. TODO: later thoughts +// if (!applicator.getPdbApplicatorOptions().remapAddressUsingExistingPublicSymbols()) { +// return; +// } Program program = applicator.getProgram(); if (program == null) { throw new PdbException("Program may not be null"); @@ -258,7 +297,7 @@ public class PdbAddressManager { SymbolIterator iter = program.getSymbolTable().getAllSymbols(false); while (iter.hasNext()) { Symbol symbol = iter.next(); - String name = symbol.getName(); + String name = symbol.getPath().toString(); Address address = symbol.getAddress(); Address existingAddress = addressByPreExistingSymbolName.get(name); if (existingAddress == null) { @@ -283,9 +322,9 @@ public class PdbAddressManager { private Address getAddressByPreExistingSymbolName(String name) { Address address = addressByPreExistingSymbolName.get(name); // Thin the list of map values we no longer need. This method should only be - // used after the list has been completely populated, and the NO_ADDRESS marker - // was only being used during the method that populated the list to indicate that a - // name was not unique for our needs. + // used after the list has been completely populated, and the NO_ADDRESS marker + // was only being used during the method that populated the list to indicate that a + // name was not unique for our needs. if (address != null && address.equals(Address.NO_ADDRESS)) { addressByPreExistingSymbolName.remove(name); return null; @@ -293,6 +332,15 @@ public class PdbAddressManager { return address; } + private void createAddressRemap() { + remapAddressByAddress = new HashMap<>(); + + // Put in two basic entries so we do not have to do conditional tests before looking + // up values in the table. + remapAddressByAddress.put(BAD_ADDRESS, BAD_ADDRESS); + remapAddressByAddress.put(EXTERNAL_ADDRESS, EXTERNAL_ADDRESS); + } + /** * Write the mapped address for a query address, where where the mapping is * derived by using a the address of a PDB symbol as the key and finding the address of @@ -321,8 +369,8 @@ public class PdbAddressManager { */ private void logMemorySectionRefinement() throws CancelledException { // Offer memory refinement (could have done it as symbols came in; we just collected - // them and are dealing with them now... ultimately not sure if we will want to use - // this refinement. + // them and are dealing with them now... ultimately not sure if we will want to use + // this refinement. // Look at SectionFlags.java for characteristics information. // TODO: should we perform refinement of program memory blocks? PdbLog.message("\nMemorySectionRefinement"); @@ -347,14 +395,14 @@ public class PdbAddressManager { */ private void logMemoryGroupRefinement() throws CancelledException { // Note that I've seen example where PE header has two .data sections (one for initialized - // and the other for uninitialized, 0x2800 and 0x250 in size, respectively), but the PDB - // information shows two sections totally 0x2a50 size, but sizes of 0x2750 and 0x0300, - // the latter of which is marked as ".bss" in name. This suggests that the PE header is - // more focused on what needs initialized, which includes 0x2750 of .data and 0xa0 of - // .bss, the remaining 0x250 of .bss is not initialized. These .bss portion that needs - // initialized is lumped with the .data section in the PE header... only my opinion... - // however, this leaves us with question of what we do here. Do believe the PDB over - // the PE? (See vcamp110.arm.pdb and (arm) vcamp110.dll). + // and the other for uninitialized, 0x2800 and 0x250 in size, respectively), but the PDB + // information shows two sections totally 0x2a50 size, but sizes of 0x2750 and 0x0300, + // the latter of which is marked as ".bss" in name. This suggests that the PE header is + // more focused on what needs initialized, which includes 0x2750 of .data and 0xa0 of + // .bss, the remaining 0x250 of .bss is not initialized. These .bss portion that needs + // initialized is lumped with the .data section in the PE header... only my opinion... + // however, this leaves us with question of what we do here. Do believe the PDB over + // the PE? (See vcamp110.arm.pdb and (arm) vcamp110.dll). // TODO: should we perform refinement of program memory blocks? PdbLog.message("\nMemoryGroupRefinement"); for (PeCoffGroupMsSymbol sym : memoryGroupRefinement) { @@ -373,7 +421,7 @@ public class PdbAddressManager { //============================================================================================== //============================================================================================== // TODO: This is not complete... It was a research thought, which might get looked at in the - // future. + // future. /** * Tries to align section/segment information of the PDB in {@link SegmentMapDescription} from * the {@link AbstractDatabaseInterface} header substream with the memory blocks of the @@ -412,7 +460,7 @@ public class PdbAddressManager { List myAllSegmentsInfo = new ArrayList<>(); // Contender set of segment info (vs what is in class) - allSegmentsInfo.add(new SegmentInfo(blocks[0].getStart(), blocks[0].getSize())); + myAllSegmentsInfo.add(new SegmentInfo(blocks[0].getStart(), blocks[0].getSize())); // Try to match memory in order, grouping as needed. long blockAccum = 0; while (progIndex < progIndexLimit && pdbIndex < pdbIndexLimit) { @@ -454,7 +502,7 @@ public class PdbAddressManager { //============================================================================================== // TODO: This is not complete... It was a research thought, which might get looked at in the - // future. + // future. @SuppressWarnings("unused") // for method not being called. private boolean garnerSectionSegmentInformation() throws PdbException { AbstractPdb pdb = applicator.getPdb(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java index a00fffc254..6b6657b263 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -183,17 +183,19 @@ public class PdbApplicator { initializeApplyTo(programParam, dataTypeManagerParam, imageBaseParam, applicatorOptionsParam, monitorParam, logParam); - if (!applicatorOptions.applyPublicSymbolsOnly()) { - processTypes(); - } - - if (program != null && !applicatorOptions.applyDataTypesOnly()) { - if (applicatorOptions.applyPublicSymbolsOnly()) { + switch (applicatorOptions.getRestrictions()) { + case DATA_TYPES_ONLY: + processTypes(); + break; + case PUBLIC_SYMBOLS_ONLY: processPublicSymbols(); - } - else { + break; + case NONE: + processTypes(); processSymbols(); - } + break; + default: + throw new PdbException("Invalid Restriction"); } pdbAddressManager.logReport(); @@ -328,6 +330,8 @@ public class PdbApplicator { DataTypeManager dataTypeManagerParam, Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, TaskMonitor monitorParam, MessageLog logParam) throws PdbException { + applicatorOptions = + (applicatorOptionsParam != null) ? applicatorOptionsParam : new PdbApplicatorOptions(); if (programParam == null) { if (dataTypeManagerParam == null) { throw new PdbException( @@ -336,11 +340,11 @@ public class PdbApplicator { if (imageBaseParam == null) { throw new PdbException("programParam and imageBaseParam may not both be null."); } - } - applicatorOptions = - (applicatorOptionsParam != null) ? applicatorOptionsParam : new PdbApplicatorOptions(); - if (applicatorOptions.applyDataTypesOnly() && applicatorOptions.applyPublicSymbolsOnly()) { - throw new PdbException("Cannot have both: applyDataTypesOnly, applyPublicSymbolOnly."); + if (applicatorOptions.getRestrictions() != PdbApplicatorRestrictions.DATA_TYPES_ONLY) { + throw new PdbException( + "programParam may not be null for the chosen PdbApplicatorRestrictions: " + + applicatorOptions.getRestrictions()); + } } monitor = (monitorParam != null) ? monitorParam : TaskMonitor.DUMMY; log = (logParam != null) ? logParam : new MessageLog(); @@ -773,10 +777,39 @@ public class PdbApplicator { //============================================================================================== // Address-related methods. //============================================================================================== + /** + * Returns true if the {@link Address} is an invalid address for continuing application of + * information to the program. Will report Error or message for an invalid address and will + * report a "External address" message for the name when the address is external. + * @param address the address to test + * @param name name associated with the address used for reporting error/info situations. + * @return {@code true} if the address should be processed. + */ + boolean isInvalidAddress(Address address, String name) { + if (address == PdbAddressManager.BAD_ADDRESS) { + appendLogMsg("Invalid address encountered for: " + name); + return true; + } + if (address == PdbAddressManager.EXTERNAL_ADDRESS) { + appendLogMsg("External address not known for: " + name); + return true; + } + return false; + } + + /** + * Returns the image base Address being used by the applicator. + * @return The Address + */ + Address getImageBase() { + return imageBase; + } + /** * Returns the Address for the given section and offset. * @param symbol The {@link AddressMsSymbol} - * @return The Address + * @return The Address, which can be {@code Address.NO_ADDRESS} if invalid or + * {@code Address.EXTERNAL_ADDRESS} if the address is external to the program. */ Address getAddress(AddressMsSymbol symbol) { return pdbAddressManager.getAddress(symbol); @@ -789,7 +822,17 @@ public class PdbApplicator { * @return The Address */ Address getAddress(int segment, long offset) { - return pdbAddressManager.getAddress(segment, offset); + return pdbAddressManager.getRawAddress(segment, offset); + } + + /** + * Returns the Address for the given section and offset. + * @param symbol The {@link AddressMsSymbol} + * @return The Address, which can be {@code Address.NO_ADDRESS} if invalid or + * {@code Address.EXTERNAL_ADDRESS} if the address is external to the program. + */ + Address getRawAddress(AddressMsSymbol symbol) { + return pdbAddressManager.getRawAddress(symbol); } /** diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java index 8e0f6942c6..460568ddd3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java @@ -213,8 +213,9 @@ public class PdbApplicatorMetrics { private String reportNonappliableTypes() { StringBuilder builder = new StringBuilder(); for (Class clazz : cannotApplyTypes) { - builder.append("Could not apply one or more instances of PDB data type: " + - clazz.getSimpleName() + "\n"); + builder.append( + "Could not apply one or more instances of an unsupported PDB data type: " + + clazz.getSimpleName() + "\n"); } return builder.toString(); } @@ -246,8 +247,9 @@ public class PdbApplicatorMetrics { private String reportNonappliableSymbols() { StringBuilder builder = new StringBuilder(); for (Class clazz : cannotApplySymbols) { - builder.append("Could not apply one or more instances of PDB symbol type: " + - clazz.getSimpleName() + "\n"); + builder.append( + "Could not apply one or more instances of an unsupported PDB symbol type: " + + clazz.getSimpleName() + "\n"); } return builder.toString(); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java index 61b951e514..a4d1ea9de1 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorOptions.java @@ -26,8 +26,8 @@ public class PdbApplicatorOptions { public static final boolean DEFAULT_APPLY_CODE_SCOPE_BLOCK_COMMENTS = false; public static final boolean DEFAULT_APPLY_INSTRUCTION_LABELS = false; - public static final boolean DEFAULT_APPLY_DATA_TYPES_ONLY = false; - public static final boolean DEFAULT_APPLY_PUBLIC_SYMBOLS_ONLY = false; + public static final PdbApplicatorRestrictions DEFAULT_RESTRICTIONS = + PdbApplicatorRestrictions.NONE; public static final boolean DEFAULT_REMAP_ADDRESSES_USING_EXISTING_SYMBOLS = false; public static final boolean DEFAULT_ALLOW_DEMOTE_PRIMARY_MANGLED_SYMBOLS = true; @@ -46,8 +46,7 @@ public class PdbApplicatorOptions { //============================================================================================== private boolean applyCodeScopeBlockComments; private boolean applyInstructionLabels; - private boolean applyDataTypesOnly; - private boolean applyPublicSymbolsOnly; + private PdbApplicatorRestrictions restrictions; private boolean remapAddressesUsingExistingPublicSymbols; private boolean allowDemotePrimaryMangledSymbols; @@ -68,8 +67,7 @@ public class PdbApplicatorOptions { public void restoreDefaults() { applyCodeScopeBlockComments = DEFAULT_APPLY_CODE_SCOPE_BLOCK_COMMENTS; applyInstructionLabels = DEFAULT_APPLY_INSTRUCTION_LABELS; - applyDataTypesOnly = DEFAULT_APPLY_DATA_TYPES_ONLY; - applyPublicSymbolsOnly = DEFAULT_APPLY_PUBLIC_SYMBOLS_ONLY; + restrictions = DEFAULT_RESTRICTIONS; remapAddressesUsingExistingPublicSymbols = DEFAULT_REMAP_ADDRESSES_USING_EXISTING_SYMBOLS; allowDemotePrimaryMangledSymbols = DEFAULT_ALLOW_DEMOTE_PRIMARY_MANGLED_SYMBOLS; applyFunctionVariables = DEFAULT_APPLY_FUNCTION_VARIABLES; @@ -109,36 +107,19 @@ public class PdbApplicatorOptions { } /** - * Enable/disable the option to only apply data types (skipping symbol information). - * In other words, the default is to apply symbols. - * @param applyDataTypesOnly {@code true} to turn applyDataTypesOnly on + * Set processing restrictions for PdbApplicator + * @param restrictions the restrictions */ - public void setApplyDataTypesOnly(boolean applyDataTypesOnly) { - this.applyDataTypesOnly = applyDataTypesOnly; + public void setRestrictions(PdbApplicatorRestrictions restrictions) { + this.restrictions = restrictions; } /** - * Returns {@code true} if applyDataTypesOnly is "on." - * @return {@code true} if applyDataTypesOnly is "on." + * Returns the current restrictions on PdbApplicator processing + * @return the restrictions */ - public boolean applyDataTypesOnly() { - return applyDataTypesOnly; - } - - /** - * Enable/disable the option to only apply public symbols. - * @param applyPublicSymbolsOnly {@code true} to turn applyPublicSymbolsOnly on - */ - public void setApplyPublicSymbolsOnly(boolean applyPublicSymbolsOnly) { - this.applyPublicSymbolsOnly = applyPublicSymbolsOnly; - } - - /** - * Returns {@code true} if applyPublicSymbolsOnly is "on." - * @return {@code true} if applyPublicSymbolsOnly is "on." - */ - public boolean applyPublicSymbolsOnly() { - return applyPublicSymbolsOnly; + public PdbApplicatorRestrictions getRestrictions() { + return restrictions; } /** diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorRestrictions.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorRestrictions.java new file mode 100644 index 0000000000..893c91862e --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorRestrictions.java @@ -0,0 +1,35 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.pdb.pdbapplicator; + +/** + * PDB Applicator restrictions of actions performed. Used by {@link PdbApplicatorOptions} + */ +public enum PdbApplicatorRestrictions { + NONE("None"), DATA_TYPES_ONLY("Data Types Only"), PUBLIC_SYMBOLS_ONLY("Public Symbols Only"); + + private final String label; + + @Override + public String toString() { + return label; + } + + private PdbApplicatorRestrictions(String label) { + this.label = label; + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java index e42eb782eb..381bd85d22 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java @@ -689,8 +689,11 @@ public class PdbResearch { !((AbstractPublic32MsSymbol) symbol).isFunction()) { return; } - Address address = applicator.getAddress((AbstractPublicMsSymbol) symbol); String name = ((AbstractPublicMsSymbol) symbol).getName(); + Address address = applicator.getAddress((AbstractPublicMsSymbol) symbol); + if (applicator.isInvalidAddress(address, name)) { + return; + } String demangledName = getDemangledQualifiedName(name); if (demangledName != null) { stuff = new Stuff(symbol, demangledName, What.PUBLIC_QUAL_FROM_MANGLED); @@ -704,8 +707,11 @@ public class PdbResearch { private static void processProcedureSymbol(PdbApplicator applicator, Map> map, AbstractMsSymbol symbol) { if (symbol instanceof AbstractProcedureMsSymbol) { - Address address = applicator.getAddress((AbstractProcedureMsSymbol) symbol); String name = ((AbstractProcedureMsSymbol) symbol).getName(); + Address address = applicator.getAddress((AbstractProcedureMsSymbol) symbol); + if (applicator.isInvalidAddress(address, name)) { + return; + } Stuff stuff = new Stuff(symbol, name, What.GLOBAL); addStuff(map, address, stuff); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java index 9b15d2d24b..6049d8341a 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbVbtManager.java @@ -75,7 +75,9 @@ public class PdbVbtManager extends VbtManager { String name = pubSymbol.getName(); if (name.startsWith("??_8")) { Address address = applicator.getAddress(pubSymbol); - myAddressByMangledName.put(name, address); + if (!applicator.isInvalidAddress(address, name)) { + myAddressByMangledName.put(name, address); + } } } monitor.incrementProgress(1); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java index 1400e889bf..4e0f0bc21b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PeCoffGroupSymbolApplier.java @@ -49,12 +49,10 @@ public class PeCoffGroupSymbolApplier extends MsSymbolApplier { void apply() throws PdbException, CancelledException { applicator.addMemoryGroupRefinement(symbol); Address symbolAddress = applicator.getAddress(symbol); - if (!Address.NO_ADDRESS.equals(symbolAddress)) { - applicator.createSymbol(symbolAddress, symbol.getName(), false); - } - else { -// monitor.setMessage("Skipping NO_ADDRESS symbol " + symb.getName() + "..."); + if (applicator.isInvalidAddress(symbolAddress, symbol.getName())) { + return; } + applicator.createSymbol(symbolAddress, symbol.getName(), false); } @Override diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java index e53764c595..1822bc2671 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PublicSymbolApplier.java @@ -56,20 +56,18 @@ public class PublicSymbolApplier extends MsSymbolApplier { void apply() throws CancelledException, PdbException { symbolAddress = applicator.getAddress(symbol); - if (!Address.NO_ADDRESS.equals(symbolAddress)) { - existingSymbolAddress = applicator.witnessSymbolNameAtAddress(getName(), symbolAddress); - // TODO: Consider... could add restriction of not putting down symbol if it is mangled, - // as this would violate the uniqueness of the symbol... but we would also want to - // know that this situation was being presented. - if (!symbolAddress.equals(existingSymbolAddress)) { - // Note: there might be issues of thunk functions getting the same mangled name - // as thunked functions, which violates the thesis of their being unique. - // TODO: investigate this. - applicator.createSymbol(symbolAddress, symbol.getName(), true); - } + if (applicator.isInvalidAddress(symbolAddress, symbol.getName())) { + return; } - else { - pdbLogAndInfoMessage(this, "Could not apply symbol at NO_ADDRESS: " + symbol.getName()); + existingSymbolAddress = applicator.witnessSymbolNameAtAddress(getName(), symbolAddress); + // TODO: Consider... could add restriction of not putting down symbol if it is mangled, + // as this would violate the uniqueness of the symbol... but we would also want to + // know that this situation was being presented. + if (!symbolAddress.equals(existingSymbolAddress)) { + // Note: there might be issues of thunk functions getting the same mangled name + // as thunked functions, which violates the thesis of their being unique. + // TODO: investigate this. + applicator.createSymbol(symbolAddress, symbol.getName(), true); } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java index e5296b3f92..be3772718d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/SeparatedCodeSymbolApplier.java @@ -101,6 +101,9 @@ public class SeparatedCodeSymbolApplier extends MsSymbolApplier { @Override void apply() throws PdbException, CancelledException { + if (applicator.isInvalidAddress(currentBlockAddress, craftedName)) { + return; + } // DO NOTHING FOR NOW. TODO: should we have a configuration option? // Note: these comments can be noise in the decompiler an code browser setComments(false); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java index 071aa38239..a5871b6c9d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/TrampolineSymbolApplier.java @@ -61,8 +61,14 @@ public class TrampolineSymbolApplier extends MsSymbolApplier { Address targetAddress = applicator.getAddress(symbol.getSegmentTarget(), symbol.getOffsetTarget()); - Function target = createNewFunction(targetAddress, 1); - Function thunk = createNewFunction(symbolAddress, symbol.getSizeOfThunk()); + Function target = null; + Function thunk = null; + if (!applicator.isInvalidAddress(targetAddress, "thunk target")) { + target = createNewFunction(targetAddress, 1); + } + if (!applicator.isInvalidAddress(symbolAddress, "thunk symbol")) { + thunk = createNewFunction(symbolAddress, symbol.getSizeOfThunk()); + } if (target != null && thunk != null) { thunk.setThunkedFunction(target); } From dec66ed2c2260c4cd7fcd65506f4da2c6bc29788 Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Wed, 16 Sep 2020 13:29:20 -0400 Subject: [PATCH 12/15] GT-3112 - PDB Universal Reader/Analyzer - 123 commits --- .../core/analysis/PdbUniversalAnalyzer.java | 9 ++- .../ComplexTypeApplierMapper.java | 2 +- .../pdbapplicator/FunctionSymbolApplier.java | 47 ++++++------ .../pdb/pdbapplicator/PdbAddressManager.java | 8 +- .../util/pdb/pdbapplicator/PdbApplicator.java | 11 +-- .../util/pdb/pdbapplicator/PdbResearch.java | 75 ++++++++++++++----- 6 files changed, 100 insertions(+), 52 deletions(-) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java index 1d104d0cd2..0b6c2e8ce9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java @@ -365,9 +365,10 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { getPdbApplicatorOptions(); options.registerOption(OPTION_NAME_PROCESSING_RESTRICTIONS, restrictions, null, OPTION_DESCRIPTION_PROCESSING_RESTRICTIONS); - options.registerOption(OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, - applyCodeScopeBlockComments, null, OPTION_DESCRIPTION_APPLY_CODE_SCOPE_BLOCK_COMMENTS); if (developerMode) { + options.registerOption(OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, + applyCodeScopeBlockComments, null, + OPTION_DESCRIPTION_APPLY_CODE_SCOPE_BLOCK_COMMENTS); // Mechanism to apply instruction labels is not yet implemented-> does nothing options.registerOption(OPTION_NAME_APPLY_INSTRUCTION_LABELS, applyInstructionLabels, null, OPTION_DESCRIPTION_APPLY_INSTRUCTION_LABELS); @@ -440,9 +441,9 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { // PdbApplicatorOptions restrictions = options.getEnum(OPTION_NAME_PROCESSING_RESTRICTIONS, restrictions); - applyCodeScopeBlockComments = options.getBoolean( - OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, applyCodeScopeBlockComments); if (developerMode) { + applyCodeScopeBlockComments = options.getBoolean( + OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, applyCodeScopeBlockComments); // Mechanism to apply instruction labels is not yet implemented-> does nothing applyInstructionLabels = options.getBoolean(OPTION_NAME_APPLY_INSTRUCTION_LABELS, applyInstructionLabels); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java index ec7dd3262b..0fbbcaef61 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ComplexTypeApplierMapper.java @@ -56,7 +56,7 @@ public class ComplexTypeApplierMapper { applicator.setMonitorMessage("PDB: Mapping Composites..."); while (indexNumber < indexLimit) { monitor.checkCanceled(); - PdbResearch.checkBreak(indexNumber); + //PdbResearch.checkBreak(indexNumber); MsTypeApplier applier = applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber++)); // From real data, we know that an enum and a composite both had the same SymbolPath, diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 36c6038f33..4340364a8c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -41,7 +41,8 @@ public class FunctionSymbolApplier extends MsSymbolApplier { private static final String BLOCK_INDENT = " "; - private AddressMsSymbol symbol; + private AbstractProcedureMsSymbol procedureSymbol; + private AbstractThunkMsSymbol thunkSymbol; private Address specifiedAddress; private Address address; private Function function = null; @@ -74,11 +75,15 @@ public class FunctionSymbolApplier extends MsSymbolApplier { comments = new BlockCommentsManager(); currentBlockAddress = null; - if (abstractSymbol instanceof AbstractProcedureMsSymbol || - abstractSymbol instanceof AbstractThunkMsSymbol) { - symbol = (AddressMsSymbol) abstractSymbol; - specifiedAddress = applicator.getRawAddress(symbol); - address = applicator.getAddress(symbol); + if (abstractSymbol instanceof AbstractProcedureMsSymbol) { + procedureSymbol = (AbstractProcedureMsSymbol) abstractSymbol; + specifiedAddress = applicator.getRawAddress(procedureSymbol); + address = applicator.getAddress(procedureSymbol); + } + else if (abstractSymbol instanceof AbstractThunkMsSymbol) { + thunkSymbol = (AbstractThunkMsSymbol) abstractSymbol; + specifiedAddress = applicator.getRawAddress(thunkSymbol); + address = applicator.getAddress(thunkSymbol); } else { throw new AssertException( @@ -98,17 +103,16 @@ public class FunctionSymbolApplier extends MsSymbolApplier { void manageBlockNesting(MsSymbolApplier applierParam) { if (applierParam instanceof FunctionSymbolApplier) { FunctionSymbolApplier functionSymbolApplier = (FunctionSymbolApplier) applierParam; - if (symbol instanceof AbstractProcedureMsSymbol) { - AbstractProcedureMsSymbol sym = (AbstractProcedureMsSymbol) symbol; - long start = sym.getDebugStartOffset(); - long end = sym.getDebugEndOffset(); + if (procedureSymbol != null) { + long start = procedureSymbol.getDebugStartOffset(); + long end = procedureSymbol.getDebugEndOffset(); Address blockAddress = address.add(start); long length = end - start; - functionSymbolApplier.beginBlock(blockAddress, sym.getName(), length); + functionSymbolApplier.beginBlock(blockAddress, procedureSymbol.getName(), length); } - else { - AbstractThunkMsSymbol sym = (AbstractThunkMsSymbol) symbol; - functionSymbolApplier.beginBlock(address, sym.getName(), sym.getLength()); + else if (thunkSymbol != null) { + functionSymbolApplier.beginBlock(address, thunkSymbol.getName(), + thunkSymbol.getLength()); } } } @@ -151,8 +155,11 @@ public class FunctionSymbolApplier extends MsSymbolApplier { * @return the function name */ String getName() { - if (symbol != null) { - return ((NameMsSymbol) symbol).getName(); + if (procedureSymbol != null) { + return procedureSymbol.getName(); + } + else if (thunkSymbol != null) { + return thunkSymbol.getName(); } return ""; } @@ -175,10 +182,6 @@ public class FunctionSymbolApplier extends MsSymbolApplier { if (applicator.isInvalidAddress(specifiedAddress, getName())) { return false; } - if (!(symbol instanceof AbstractProcedureMsSymbol)) { - return false; - } - AbstractProcedureMsSymbol procedureSymbol = (AbstractProcedureMsSymbol) symbol; boolean functionSuccess = applyFunction(monitor); if (functionSuccess == false) { @@ -275,13 +278,13 @@ public class FunctionSymbolApplier extends MsSymbolApplier { } private boolean setFunctionDefinition(TaskMonitor monitor) { - if (!(symbol instanceof AbstractProcedureMsSymbol)) { + if (procedureSymbol == null) { // TODO: is there anything we can do with thunkSymbol? // long x = thunkSymbol.getParentPointer(); return true; } // Rest presumes procedureSymbol. - RecordNumber typeRecordNumber = ((AbstractProcedureMsSymbol) symbol).getTypeRecordNumber(); + RecordNumber typeRecordNumber = procedureSymbol.getTypeRecordNumber(); MsTypeApplier applier = applicator.getTypeApplier(typeRecordNumber); if (applier == null) { applicator.appendLogMsg("Error: Failed to resolve datatype RecordNumber " + diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index c4da076a6f..8213c93c0d 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -143,7 +143,9 @@ public class PdbAddressManager { if (segment < 0 || segment > allSegmentsInfo.size()) { return BAD_ADDRESS; } - else if (segment == allSegmentsInfo.size()) { + // We are lumping 0 and size as EXTERNAL... one or other could be image base... but not + // necessarily consistent... but that's OK... it is still "EXTERNAL" from the program. + else if (segment == 0 || segment == allSegmentsInfo.size()) { // External address. // Was getting issues of _IMAGE_DOSHEADER showing up with a segment index one // beyond the end. @@ -250,7 +252,9 @@ public class PdbAddressManager { private void determineMemoryBlocks() { // Set section/segment 0 to image base. (should be what is header), but what is its size? - // TODO... made up size for now... is there something else? We could + // TODO... made up size for now... is there something else? We could put null instead. + // For now, the method that reads this information might report EXTERNAL instead of + // trying to use this. long segmentZeroLength = 0x7fffffff; allSegmentsInfo.add(new SegmentInfo(imageBase, segmentZeroLength)); AbstractDatabaseInterface dbi = applicator.getPdb().getDatabaseInterface(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java index 6b6657b263..d04c4d6b58 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -598,6 +598,7 @@ public class PdbApplicator { } MsTypeApplier getTypeApplier(RecordNumber recordNumber) { + //PdbResearch.checkBreak(recordNumber.getNumber()); return typeApplierParser.getTypeApplier(recordNumber); } @@ -629,7 +630,7 @@ public class PdbApplicator { for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) { monitor.checkCanceled(); - PdbResearch.checkBreak(indexNumber); + //PdbResearch.checkBreak(indexNumber); MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); //PdbResearch.checkBreak(indexNumber, applier); applier.apply(); @@ -712,7 +713,7 @@ public class PdbApplicator { " deferred data type dependencies..."); for (MsTypeApplier applier : verticesInPostOrder) { monitor.checkCanceled(); - PdbResearch.checkBreak(applier.index); + //PdbResearch.checkBreak(applier.index); //checkBreak(applier.index, applier); if (applier.isDeferred()) { applier.deferredApply(); @@ -732,9 +733,9 @@ public class PdbApplicator { for (int indexNumber = tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) { monitor.checkCanceled(); - PdbResearch.checkBreak(indexNumber); + //PdbResearch.checkBreak(indexNumber); MsTypeApplier applier = getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); - PdbResearch.checkBreak(indexNumber, applier); + //PdbResearch.checkBreak(indexNumber, applier); applier.resolve(); monitor.incrementProgress(1); } @@ -791,7 +792,7 @@ public class PdbApplicator { return true; } if (address == PdbAddressManager.EXTERNAL_ADDRESS) { - appendLogMsg("External address not known for: " + name); + //Msg.info(this, "External address not known for: " + name); return true; } return false; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java index 381bd85d22..84b448ceae 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbResearch.java @@ -41,7 +41,7 @@ public class PdbResearch { //============================================================================================== private static Set debugIndexNumbers; - private Set developerDebugOrderIndexNumbers; + private static Set developerDebugOrderIndexNumbers; //============================================================================================== /** @@ -52,7 +52,21 @@ public class PdbResearch { static void initBreakPointRecordNumbers() { debugIndexNumbers = new TreeSet<>(); - debugIndexNumbers.add(12527); + debugIndexNumbers.add(9715); + +// debugIndexNumbers.add(9696); +// debugIndexNumbers.add(9700); +// debugIndexNumbers.add(9709); +// debugIndexNumbers.add(9783); +// debugIndexNumbers.add(216012); +// debugIndexNumbers.add(216055); +// debugIndexNumbers.add(216058); + +// debugIndexNumbers.add(9703); +// debugIndexNumbers.add(9709); +// debugIndexNumbers.add(9782); + +// debugIndexNumbers.add(12527); // debugIndexNumbers.add(180462); @@ -334,31 +348,56 @@ public class PdbResearch { //============================================================================================== //============================================================================================== - private void initDeveloperOrderRecordNumbers() { + static private void initDeveloperOrderRecordNumbers() { developerDebugOrderIndexNumbers = new TreeSet<>(); - // big class - developerDebugOrderIndexNumbers.add(105212); + developerDebugOrderIndexNumbers.add(9696); + developerDebugOrderIndexNumbers.add(9697); + developerDebugOrderIndexNumbers.add(9700); + developerDebugOrderIndexNumbers.add(9701); + developerDebugOrderIndexNumbers.add(9704); + developerDebugOrderIndexNumbers.add(9707); + developerDebugOrderIndexNumbers.add(9709); + developerDebugOrderIndexNumbers.add(9714); + developerDebugOrderIndexNumbers.add(9715); + developerDebugOrderIndexNumbers.add(9773); + developerDebugOrderIndexNumbers.add(9774); + developerDebugOrderIndexNumbers.add(9775); + developerDebugOrderIndexNumbers.add(9776); + developerDebugOrderIndexNumbers.add(9777); + developerDebugOrderIndexNumbers.add(9778); + developerDebugOrderIndexNumbers.add(9779); + developerDebugOrderIndexNumbers.add(9780); + developerDebugOrderIndexNumbers.add(9781); + developerDebugOrderIndexNumbers.add(9782); + developerDebugOrderIndexNumbers.add(9783); + developerDebugOrderIndexNumbers.add(216012); + developerDebugOrderIndexNumbers.add(216055); + developerDebugOrderIndexNumbers.add(216058); - // member 2 (def) of big class (fwdref 105103) - developerDebugOrderIndexNumbers.add(105444); - - // member 3 (def) of big class (fwdref 105104) - developerDebugOrderIndexNumbers.add(105594); - - // base classes of 105444 (field list 105443) - developerDebugOrderIndexNumbers.add(5251); // fwdref is 5072 - developerDebugOrderIndexNumbers.add(105594); // fwdref is 105430 - - // first and only member of 5251 - developerDebugOrderIndexNumbers.add(5051); // fwdref is 4505 +// // big class +// developerDebugOrderIndexNumbers.add(105212); +// +// // member 2 (def) of big class (fwdref 105103) +// developerDebugOrderIndexNumbers.add(105444); +// +// // member 3 (def) of big class (fwdref 105104) +// developerDebugOrderIndexNumbers.add(105594); +// +// // base classes of 105444 (field list 105443) +// developerDebugOrderIndexNumbers.add(5251); // fwdref is 5072 +// developerDebugOrderIndexNumbers.add(105594); // fwdref is 105430 +// +// // first and only member of 5251 +// developerDebugOrderIndexNumbers.add(5051); // fwdref is 4505 } - void developerDebugOrder(PdbApplicator applicator, TaskMonitor monitor) + static void developerDebugOrder(PdbApplicator applicator, TaskMonitor monitor) throws CancelledException, PdbException { initDeveloperOrderRecordNumbers(); for (int indexNumber : developerDebugOrderIndexNumbers) { monitor.checkCanceled(); + PdbResearch.checkBreak(indexNumber); MsTypeApplier applier = applicator.getTypeApplier(RecordNumber.typeRecordNumber(indexNumber)); applier.apply(); From 4e0e28933f5d9681ca9c880615b594b1947ced2a Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Wed, 16 Sep 2020 17:04:37 -0400 Subject: [PATCH 13/15] GT-3112 - PDB Universal Reader/Analyzer - 124 commits --- .../app/util/pdb/pdbapplicator/FunctionSymbolApplier.java | 6 +++--- .../app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java index 4340364a8c..586055f5f9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/FunctionSymbolApplier.java @@ -173,13 +173,13 @@ public class FunctionSymbolApplier extends MsSymbolApplier { void apply() throws PdbException, CancelledException { boolean result = applyTo(applicator.getCancelOnlyWrappingMonitor()); if (result == false) { - throw new PdbException("failure in applying " + this.getClass().getSimpleName() + - " to program: " + getName()); + throw new PdbException(this.getClass().getSimpleName() + ": failure at " + address + + " applying " + getName()); } } boolean applyTo(TaskMonitor monitor) throws PdbException, CancelledException { - if (applicator.isInvalidAddress(specifiedAddress, getName())) { + if (applicator.isInvalidAddress(address, getName())) { return false; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java index 460568ddd3..c449fa6892 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicatorMetrics.java @@ -59,6 +59,14 @@ public class PdbApplicatorMetrics { LocalManagedDataMsSymbol.PDB_ID, LocalManagedDataStMsSymbol.PDB_ID, + // AbstractThreadStorageMsSymbol + GlobalThreadStorage3216MsSymbol.PDB_ID, + GlobalThreadStorage32MsSymbol.PDB_ID, + GlobalThreadStorage32StMsSymbol.PDB_ID, + LocalThreadStorage3216MsSymbol.PDB_ID, + LocalThreadStorage32MsSymbol.PDB_ID, + LocalThreadStorage32StMsSymbol.PDB_ID, + // AbstractUserDefinedTypeMsSymbol CobolUserDefinedType16MsSymbol.PDB_ID, CobolUserDefinedTypeMsSymbol.PDB_ID, From 0df36d17a35971eb3523c7c35587b447c822a508 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Thu, 17 Sep 2020 19:40:35 -0400 Subject: [PATCH 14/15] GP-177 allow changes to Stack and PDB analyzer enablement to be retained as a new default enablement --- .../core/analysis/AnalysisScheduler.java | 63 ++++++++++++++----- .../core/analysis/AutoAnalysisManager.java | 3 + .../core/function/StackVariableAnalyzer.java | 7 +++ .../ghidra/app/services/AbstractAnalyzer.java | 6 +- .../java/ghidra/app/services/Analyzer.java | 20 +++++- .../app/plugin/core/analysis/PdbAnalyzer.java | 5 ++ .../core/analysis/PdbUniversalAnalyzer.java | 5 ++ .../analyzers/AbstractJavaAnalyzer.java | 5 ++ 8 files changed, 93 insertions(+), 21 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisScheduler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisScheduler.java index 1cfab6ac7f..12ab1677f1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisScheduler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalysisScheduler.java @@ -15,13 +15,18 @@ */ package ghidra.app.plugin.core.analysis; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + import ghidra.app.services.Analyzer; import ghidra.app.util.importer.MessageLog; import ghidra.framework.options.Options; +import ghidra.framework.preferences.Preferences; import ghidra.program.model.address.*; import ghidra.program.model.lang.Language; import ghidra.program.model.listing.Program; import ghidra.util.Msg; +import ghidra.util.SystemUtilities; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -42,11 +47,44 @@ public class AnalysisScheduler { throw new IllegalArgumentException("Analyzer name may not contain a period: " + analyzer.getName()); } - this.enabled = analyzer.getDefaultEnablement(analysisMgr.getProgram()); + boolean defaultEnable = analyzer.getDefaultEnablement(analysisMgr.getProgram()); + enabled = getEnableOverride(defaultEnable); + if (rememberEnablementChangeAsUserPreference()) { + String val = + Preferences.getProperty(getAnalyzerPreferenceName(), Boolean.toString(enabled)); + enabled = Boolean.valueOf(val); + } + else if (defaultEnable != enabled) { + Msg.warn(this, + "Analyzer \'" + analyzer.getName() + "\' for " + + analysisMgr.getProgram().getName() + " " + (enabled ? "enabled" : "disabled") + + " by PSPEC file override"); + } removeSet = new AddressSet(); addSet = new AddressSet(); } + private boolean rememberEnablementChangeAsUserPreference() { + if (!analyzer.rememberEnablementChangeAsUserPreference()) { + return false; + } + if (SystemUtilities.isInTestingMode() || SystemUtilities.isInHeadlessMode()) { + return false; + } + return true; + } + + private String getAnalyzerPreferenceName() { + String str = analyzer.getName(); + try { + str = URLEncoder.encode(str, "UTF8"); + } + catch (UnsupportedEncodingException e) { + // ignore + } + return "Analyzers." + str; + } + synchronized void schedule() { // if not scheduled right now, schedule it if (!scheduled && (!addSet.isEmpty() || !removeSet.isEmpty())) { @@ -116,29 +154,20 @@ public class AnalysisScheduler { boolean defaultEnable = analyzer.getDefaultEnablement(analysisMgr.getProgram()); defaultEnable = getEnableOverride(defaultEnable); - enabled = options.getBoolean(analyzer.getName(), defaultEnable); + + boolean state = options.getBoolean(analyzer.getName(), defaultEnable); + if (state != enabled && rememberEnablementChangeAsUserPreference()) { + Preferences.setProperty(getAnalyzerPreferenceName(), Boolean.toString(state)); + } + enabled = state; analyzer.optionsChanged(options.getOptions(analyzer.getName()), analysisMgr.getProgram()); } public void registerOptions(Options options) { Options analyzerOptions = options.getOptions(analyzer.getName()); - - boolean defaultEnable = analyzer.getDefaultEnablement(analysisMgr.getProgram()); - - boolean overrideEnable = getEnableOverride(defaultEnable); - - // only warn when option registered - if (defaultEnable != overrideEnable) { - Msg.warn(this, - "Analyzer \'" + analyzer.getName() + "\' for " + - analysisMgr.getProgram().getName() + " " + - (overrideEnable ? "enabled" : "disabled") + " by PSPEC file override"); - } - options.registerOption(analyzer.getName(), - overrideEnable, null, - analyzer.getDescription()); + enabled, null, analyzer.getDescription()); analyzer.registerOptions(analyzerOptions, analysisMgr.getProgram()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisManager.java index 647e5d01eb..821016d66b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AutoAnalysisManager.java @@ -36,6 +36,7 @@ import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.model.*; import ghidra.framework.options.Options; import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.preferences.Preferences; import ghidra.program.model.address.*; import ghidra.program.model.listing.*; import ghidra.program.util.*; @@ -394,6 +395,7 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl case DomainObject.DO_PROPERTY_CHANGED: if (!optionsChanged) { initializeOptions(); + Preferences.store(); optionsChanged = true; } break; @@ -1054,6 +1056,7 @@ public class AutoAnalysisManager implements DomainObjectListener, DomainObjectCl initializeOptions(options); } catch (OptionsVetoException e) { +// FIXME!! Not good to popup for all use cases // This will only happen if an Analyzer author makes a mistake Msg.showError(this, null, "Invalid Analysis Option", "Invalid Analysis option set during initialization", e); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java index ba6b14c903..f6863054f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/StackVariableAnalyzer.java @@ -41,6 +41,12 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { setSupportsOneTimeAnalysis(); } + @Override + public boolean rememberEnablementChangeAsUserPreference() { + return true; + } + + @Override public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) { BackgroundCommand cmd; @@ -79,6 +85,7 @@ public class StackVariableAnalyzer extends AbstractAnalyzer { "Create Function Parameter stack variables and references"); } + @Override public void optionsChanged(Options options, Program program) { doNewStackAnalysis = options.getBoolean(GhidraLanguagePropertyKeys.USE_NEW_FUNCTION_STACK_ANALYSIS, diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/services/AbstractAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/services/AbstractAnalyzer.java index 8be493c98c..30a8e3a2d4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/services/AbstractAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/services/AbstractAnalyzer.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,6 +72,11 @@ public abstract class AbstractAnalyzer implements Analyzer { return defaultEnablement; } + @Override + public boolean rememberEnablementChangeAsUserPreference() { + return false; + } + @Override public final boolean supportsOneTimeAnalysis() { return supportsOneTimeAnalysis; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/services/Analyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/services/Analyzer.java index 49e21a9394..dcb6a3647c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/services/Analyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/services/Analyzer.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -103,10 +102,18 @@ public interface Analyzer extends ExtensionPoint { public boolean removed(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException; + /** + * Analyzers should register their options with associated default value, help content and + * description + * @param options the program options/property list that contains the options + * @param program program to be analyzed + */ + public void registerOptions(Options options, Program program); + /** * Analyzers should initialize their options from the values in the given Options, * providing appropriate default values. - * @param options the property list that contains the options + * @param options the program options/property list that contains the options * @param program program to be analyzed */ public void optionsChanged(Options options, Program program); @@ -124,6 +131,13 @@ public interface Analyzer extends ExtensionPoint { */ public boolean isPrototype(); - public void registerOptions(Options options, Program program); + /** + * Returns true if a change to the analyzer enablement should be saved as a user preference + * so that it may be establish the default enablement for analysis in other programs. + * NOTE: This feature is ignored while operating in test mode or headless mode where + * it is expected that explicit enablement/disablement will be utilized. + * @return true if an enablement change should be remembered as the new default + */ + public boolean rememberEnablementChangeAsUserPreference(); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java index 51b5f36323..63e76644e4 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbAnalyzer.java @@ -63,6 +63,11 @@ public class PdbAnalyzer extends AbstractAnalyzer { setSupportsOneTimeAnalysis(); } + @Override + public boolean rememberEnablementChangeAsUserPreference() { + return true; + } + @Override public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java index 0b6c2e8ce9..c8ada5106c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/plugin/core/analysis/PdbUniversalAnalyzer.java @@ -233,6 +233,11 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer { pdbApplicatorOptions = new PdbApplicatorOptions(); } + @Override + public boolean rememberEnablementChangeAsUserPreference() { + return true; + } + @Override public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException { diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/AbstractJavaAnalyzer.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/AbstractJavaAnalyzer.java index e50f67f408..69c9d00f04 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/AbstractJavaAnalyzer.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/AbstractJavaAnalyzer.java @@ -221,4 +221,9 @@ public abstract class AbstractJavaAnalyzer implements Analyzer { protected Address find(Program program, Address start, byte[] values, TaskMonitor monitor) { return program.getMemory().findBytes(start, values, null, true, monitor); } + + @Override + public boolean rememberEnablementChangeAsUserPreference() { + return false; + } } From 99663c7ff129335fa707c171bf65dd0323ab2295 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Thu, 17 Sep 2020 19:48:35 -0400 Subject: [PATCH 15/15] GP-177 added missing file change --- .../main/java/ghidra/file/analyzers/FileFormatAnalyzer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/analyzers/FileFormatAnalyzer.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/analyzers/FileFormatAnalyzer.java index 17a67dd323..c033b0b7c7 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/analyzers/FileFormatAnalyzer.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/analyzers/FileFormatAnalyzer.java @@ -228,4 +228,9 @@ public abstract class FileFormatAnalyzer implements Analyzer { protected Address find(Program program, Address start, byte[] values, TaskMonitor monitor) { return program.getMemory().findBytes(start, values, null, true, monitor); } + + @Override + public boolean rememberEnablementChangeAsUserPreference() { + return false; + } }