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;