From c6a3300fe840aa33ecaba5c7dfd1aa0ce479bbba Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Thu, 30 Jan 2025 15:38:28 -0500 Subject: [PATCH] GP-5323 - PDB - improve vxtables and test set up --- .../util/pdb/classtype/MsftVxtManager.java | 62 +- .../classtype/ProgramVirtualBaseTable.java | 10 +- .../ProgramVirtualFunctionTable.java | 29 +- .../pdbapplicator/DefaultPdbApplicator.java | 2 +- .../pdb/classtype/MsftVxtManagerTest.java | 576 ++++++++++++------ .../pdbapplicator/CppCompositeTypeTest.java | 53 +- 6 files changed, 515 insertions(+), 217 deletions(-) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/MsftVxtManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/MsftVxtManager.java index c56ac0ca61..16506756ad 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/MsftVxtManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/MsftVxtManager.java @@ -25,7 +25,7 @@ import ghidra.app.util.demangler.microsoft.MicrosoftMangledContext; import ghidra.app.util.importer.MessageLog; import ghidra.program.model.address.Address; import ghidra.program.model.data.CategoryPath; -import ghidra.program.model.mem.Memory; +import ghidra.program.model.listing.Program; import ghidra.util.Msg; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; @@ -52,7 +52,7 @@ import mdemangler.typeinfo.*; */ public class MsftVxtManager extends VxtManager { - private Memory memory; + private Program program; private Map vxtAddressByMangled; private Map parentageNodeByMangled; @@ -72,11 +72,11 @@ public class MsftVxtManager extends VxtManager { /** * Constructor for this class * @param ctm the class type manager - * @param memory the memory of the program + * @param program the program */ - public MsftVxtManager(ClassTypeManager ctm, Memory memory) { + public MsftVxtManager(ClassTypeManager ctm, Program program) { super(ctm); - this.memory = memory; + this.program = program; vxtAddressByMangled = new HashMap<>(); parentageNodeByMangled = new HashMap<>(); vbtsByOwner = new HashMap<>(); @@ -110,6 +110,54 @@ public class MsftVxtManager extends VxtManager { return map.firstEntry().getValue(); } + /** + * Returns the class IDs of all owners of VBTs + * @return the IDs + */ + public ClassID[] getAllVbtOwners() { + ClassID ids[] = new ClassID[vbtsByOwner.size()]; + Set set = vbtsByOwner.keySet(); + return set.toArray(ids); + } + + /** + * Returns the class IDs of all owners of VFTs + * @return the IDs + */ + public ClassID[] getAllVftOwners() { + ClassID ids[] = new ClassID[vbtsByOwner.size()]; + Set set = vftsByOwner.keySet(); + return set.toArray(ids); + } + + /** + * Returns the ordered in-memory {@link VBTable}s for the owning class + * @param owner the owning class of the table + * @return the tables + */ + public VBTable[] getVbts(ClassID owner) { + TreeMap map = vbtsByOwner.get(owner); + if (map == null) { + return null; + } + Collection values = map.values(); + return values.toArray(new VBTable[values.size()]); + } + + /** + * Returns the ordered in-memory {@link VFTable}s for the owning class + * @param owner the owning class of the table + * @return the tables + */ + public VFTable[] getVfts(ClassID owner) { + TreeMap map = vftsByOwner.get(owner); + if (map == null) { + return null; + } + Collection values = map.values(); + return values.toArray(new VFTable[values.size()]); + } + /** * Finds the putative {@link VBTable} in memory requested for the owning class and the * specified parentage @@ -245,7 +293,7 @@ public class MsftVxtManager extends VxtManager { switch (demanglerResults.vtType()) { case VBT: ProgramVirtualBaseTable prvbt = new ProgramVirtualBaseTable(owner, parentage, - memory, address, ctm.getDefaultVbtTableElementSize(), ctm, mangled); + program, address, ctm.getDefaultVbtTableElementSize(), ctm, mangled); if (node.getVBTable() != null) { Msg.warn(this, "VBT already exists at node for " + mangled); return false; @@ -257,7 +305,7 @@ public class MsftVxtManager extends VxtManager { case VFT: ProgramVirtualFunctionTable vft = new ProgramVirtualFunctionTable(owner, parentage, - memory, address, ctm.getDefaultVftTableElementSize(), mangled); + program, address, ctm.getDefaultVftTableElementSize(), mangled); if (node.getVFTable() != null) { Msg.warn(this, "VFT already exists at node for " + mangled); return false; diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualBaseTable.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualBaseTable.java index a502a9647f..cc7d8ec90f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualBaseTable.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualBaseTable.java @@ -19,6 +19,7 @@ import java.util.*; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryAccessException; @@ -27,7 +28,7 @@ import ghidra.program.model.mem.MemoryAccessException; */ public class ProgramVirtualBaseTable extends VirtualBaseTable { - private Memory memory; + private Program program; private Address address; private int entrySize; private String mangledName; // remove? @@ -44,19 +45,19 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable { * Constructor * @param owner the class that owns the table * @param parentage the parentage of the base class(es) of the table - * @param memory the program memory + * @param program the program * @param address the address of the table * @param entrySize the size for each table entry * @param ctm the class type manager * @param mangledName the mangled name of the table */ - public ProgramVirtualBaseTable(ClassID owner, List parentage, Memory memory, + public ProgramVirtualBaseTable(ClassID owner, List parentage, Program program, Address address, int entrySize, ClassTypeManager ctm, String mangledName) { super(owner, parentage); if (entrySize != 4 && entrySize != 8) { throw new IllegalArgumentException("Invalid size (" + entrySize + "): must be 4 or 8."); } - this.memory = memory; + this.program = program; this.address = address; this.entrySize = entrySize; this.mangledName = mangledName; @@ -98,6 +99,7 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable { @Override public Long getBaseOffset(int index) throws PdbException { + Memory memory = program.getMemory(); Address entryAddress = address.add(index * entrySize); try { Long offset = (entrySize == 4) ? (long) memory.getInt(entryAddress) diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualFunctionTable.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualFunctionTable.java index 9f73ea1296..282b47c638 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualFunctionTable.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/ProgramVirtualFunctionTable.java @@ -20,14 +20,16 @@ import java.util.List; import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryAccessException; /** * Manages virtual function table lookups. */ public class ProgramVirtualFunctionTable extends VirtualFunctionTable { - private Memory memory; + private Program program; private Address address; private int defaultEntrySize; // Might go away, as would constructor param private String mangledName; @@ -36,19 +38,19 @@ public class ProgramVirtualFunctionTable extends VirtualFunctionTable { * Constructor * @param owner the owner class * @param parentage the parentage for the table - * @param memory the program memory + * @param program the program * @param address the address of the table in memory * @param defaultEntrySize the default entry size * @param mangledName the mangled name for the table */ - public ProgramVirtualFunctionTable(ClassID owner, List parentage, Memory memory, + public ProgramVirtualFunctionTable(ClassID owner, List parentage, Program program, Address address, int defaultEntrySize, String mangledName) { super(owner, parentage); if (defaultEntrySize != 4 && defaultEntrySize != 8) { throw new IllegalArgumentException( "Invalid size (" + defaultEntrySize + "): must be 4 or 8."); } - this.memory = memory; + this.program = program; this.address = address; this.defaultEntrySize = defaultEntrySize; this.mangledName = mangledName; @@ -72,7 +74,24 @@ public class ProgramVirtualFunctionTable extends VirtualFunctionTable { @Override public Address getAddress(int ordinal) throws PdbException { - throw new UnsupportedOperationException(); + Memory memory = program.getMemory(); + Address entryAddress = address.add(ordinal * defaultEntrySize); + try { + long offset = + (defaultEntrySize == 4) ? Integer.toUnsignedLong(memory.getInt(entryAddress)) + : memory.getLong(entryAddress); + if (offset == 0L) { + return null; + } + Address result = address.getNewAddress(offset, false); + return result; + } + catch (MemoryAccessException e) { + throw new PdbException( + "MemoryAccessException while trying to parse virtual function table entry at address: " + + entryAddress); + } + //throw new UnsupportedOperationException(); } @Override diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java index 0fb5e1ffad..131d876982 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java @@ -638,7 +638,7 @@ public class DefaultPdbApplicator implements PdbApplicator { if (program != null) { // Currently, this must happen after symbolGroups are created. MsftVxtManager msftVxtManager = - new MsftVxtManager(getClassTypeManager(), program.getMemory()); + new MsftVxtManager(getClassTypeManager(), program); msftVxtManager.createVirtualTables(getRootPdbCategory(), findVirtualTableSymbols(), log, monitor); vxtManager = msftVxtManager; diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/classtype/MsftVxtManagerTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/classtype/MsftVxtManagerTest.java index 5da04ca257..514316a158 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/classtype/MsftVxtManagerTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/classtype/MsftVxtManagerTest.java @@ -19,14 +19,18 @@ import static org.junit.Assert.*; import java.util.*; +import org.junit.Test; + import generic.test.AbstractGenericTest; import ghidra.app.plugin.core.checksums.MyTestMemory; import ghidra.app.util.SymbolPath; import ghidra.app.util.SymbolPathParser; import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.*; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressIterator; import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryAccessException; import ghidra.util.LittleEndianDataConverter; @@ -51,31 +55,100 @@ public class MsftVxtManagerTest extends AbstractGenericTest { private static ClassTypeManager ctm32; private static ClassTypeManager ctm64; - private ClassID a1Id = new ProgramClassID(CategoryPath.ROOT, sp("A1NS::A1")); - private ClassID a2Id = new ProgramClassID(CategoryPath.ROOT, sp("A2NS::A2")); - private ClassID aId = new ProgramClassID(CategoryPath.ROOT, sp("ANS::A")); - private ClassID b1Id = new ProgramClassID(CategoryPath.ROOT, sp("B1NS::B1")); - private ClassID b2Id = new ProgramClassID(CategoryPath.ROOT, sp("B2NS::B2")); - private ClassID bId = new ProgramClassID(CategoryPath.ROOT, sp("BNS::B")); - private ClassID cId = new ProgramClassID(CategoryPath.ROOT, sp("CNS::C")); - private ClassID dId = new ProgramClassID(CategoryPath.ROOT, sp("DNS::D")); - private ClassID eId = new ProgramClassID(CategoryPath.ROOT, sp("ENS::E")); - private ClassID fId = new ProgramClassID(CategoryPath.ROOT, sp("FNS::F")); - private ClassID gId = new ProgramClassID(CategoryPath.ROOT, sp("GNS::G")); - private ClassID hId = new ProgramClassID(CategoryPath.ROOT, sp("HNS::H")); - private ClassID iId = new ProgramClassID(CategoryPath.ROOT, sp("INS::I")); - private ClassID jId = new ProgramClassID(CategoryPath.ROOT, sp("JNS::J")); - private ClassID kId = new ProgramClassID(CategoryPath.ROOT, sp("KNS::K")); - private ClassID lId = new ProgramClassID(CategoryPath.ROOT, sp("LNS::L")); - private ClassID mId = new ProgramClassID(CategoryPath.ROOT, sp("MNS::M")); + private static int[] dummyVftMeta = new int[] { 0 }; + + private static ClassID A1_ID = new ProgramClassID(CategoryPath.ROOT, sp("A1NS::A1")); + private static ClassID A2_ID = new ProgramClassID(CategoryPath.ROOT, sp("A2NS::A2")); + private static ClassID A_ID = new ProgramClassID(CategoryPath.ROOT, sp("ANS::A")); + private static ClassID B1_ID = new ProgramClassID(CategoryPath.ROOT, sp("B1NS::B1")); + private static ClassID B2_ID = new ProgramClassID(CategoryPath.ROOT, sp("B2NS::B2")); + private static ClassID B_ID = new ProgramClassID(CategoryPath.ROOT, sp("BNS::B")); + private static ClassID C_ID = new ProgramClassID(CategoryPath.ROOT, sp("CNS::C")); + private static ClassID D_ID = new ProgramClassID(CategoryPath.ROOT, sp("DNS::D")); + private static ClassID E_ID = new ProgramClassID(CategoryPath.ROOT, sp("ENS::E")); + private static ClassID F_ID = new ProgramClassID(CategoryPath.ROOT, sp("FNS::F")); + private static ClassID G_ID = new ProgramClassID(CategoryPath.ROOT, sp("GNS::G")); + private static ClassID H_ID = new ProgramClassID(CategoryPath.ROOT, sp("HNS::H")); + private static ClassID I_ID = new ProgramClassID(CategoryPath.ROOT, sp("INS::I")); + private static ClassID J_ID = new ProgramClassID(CategoryPath.ROOT, sp("JNS::J")); + private static ClassID K_ID = new ProgramClassID(CategoryPath.ROOT, sp("KNS::K")); + private static ClassID L_ID = new ProgramClassID(CategoryPath.ROOT, sp("LNS::L")); + private static ClassID M_ID = new ProgramClassID(CategoryPath.ROOT, sp("MNS::M")); + + private static Function A1NS_A1_fa1_1 = new FunctionTestDouble("A1NS::A1::fa1_1"); + private static Function A1NS_A1_fa1_2 = new FunctionTestDouble("A1NS::A1::fa1_2"); + private static Function A1NS_A1_fa1_3 = new FunctionTestDouble("A1NS::A1::fa1_3"); + private static Function A2NS_A2_fa2_1 = new FunctionTestDouble("A2NS::A2::fa2_1"); + private static Function A2NS_A2_fa2_2 = new FunctionTestDouble("A2NS::A2::fa2_2"); + private static Function A2NS_A2_fa2_3 = new FunctionTestDouble("A2NS::A2::fa2_3"); + private static Function ANS_A_fa1_1 = new FunctionTestDouble("ANS::A::fa1_1"); + private static Function ANS_A_fa2_1 = new FunctionTestDouble("ANS::A::fa2_1"); + private static Function ANS_A_fa_1 = new FunctionTestDouble("ANS::A::fa_1"); + private static Function ANS_A_fa1_1_thunkThisMinus16 = + new FunctionTestDouble("ANS::A::fa1_1_thunkThisMinus16"); + private static Function ANS_A_fa2_1_thunkThisMinus4 = + new FunctionTestDouble("ANS::A::fa2_1_thunkThisMinus4"); + private static Function B1NS_B1_fb1_1 = new FunctionTestDouble("B1NS::B1::fb1_1"); + private static Function B1NS_B1_fb1_2 = new FunctionTestDouble("B1NS::B1::fb1_2"); + private static Function B1NS_B1_fb1_3 = new FunctionTestDouble("B1NS::B1::fb1_3"); + private static Function B2NS_B2_fb2_1 = new FunctionTestDouble("B2NS::B2::fb2_1"); + private static Function B2NS_B2_fb2_2 = new FunctionTestDouble("B2NS::B2::fb2_2"); + private static Function B2NS_B2_fb2_3 = new FunctionTestDouble("B2NS::B2::fb2_3"); + private static Function BNS_B_fb1_1 = new FunctionTestDouble("BNS::B::fb1_1"); + private static Function BNS_B_fb2_1 = new FunctionTestDouble("BNS::B::fb2_1"); + private static Function BNS_B_fb_1 = new FunctionTestDouble("BNS::B::fb_1"); + private static Function BNS_B_fb1_1_thunkThisMinus16 = + new FunctionTestDouble("BNS::B::fb1_1_thunkThisMinus16"); + private static Function BNS_B_fb1_1_thunkThisPlus28 = + new FunctionTestDouble("BNS::B::fb1_1_thunkThisPlus28"); + private static Function BNS_B_fb2_1_thunkThisPlus28 = + new FunctionTestDouble("BNS::B::fb2_1_thunkThisPlus28"); + private static Function CNS_C_fa1_2 = new FunctionTestDouble("CNS::C::fa1_2"); + private static Function CNS_C_fa2_1 = new FunctionTestDouble("CNS::C::fa2_1"); + private static Function CNS_C_fb1_2 = new FunctionTestDouble("CNS::C::fb1_2"); + private static Function CNS_C_fb2_1 = new FunctionTestDouble("CNS::C::fb2_1"); + private static Function CNS_C_fc_1 = new FunctionTestDouble("CNS::C::fc_1"); + private static Function CNS_C_fa1_2_thunkThisMinus28 = + new FunctionTestDouble("CNS::C::fa1_2_thunkThisMinus28"); + private static Function CNS_C_fb1_2_thunkThisMinus28 = + new FunctionTestDouble("CNS::C::fb1_2_thunkThisMinus28"); + private static Function CNS_C_fa1_2_thunkThisMinus84 = + new FunctionTestDouble("CNS::C::fa1_2_thunkThisMinus84"); + private static Function CNS_C_fb1_2_thunkThisMinus84 = + new FunctionTestDouble("CNS::C::fb1_2_thunkThisMinus84"); + private static Function DNS_D_fa2_1 = new FunctionTestDouble("DNS::D::fa2_1"); + private static Function DNS_D_fb2_1 = new FunctionTestDouble("DNS::D::fb2_1"); + private static Function ENS_E_fa1_1 = new FunctionTestDouble("ENS::E::fa1_1"); + private static Function FNS_F_fa1_1 = new FunctionTestDouble("FNS::F::fa1_1"); + private static Function GNS_G_fa1_1 = new FunctionTestDouble("GNS::G::fa1_1"); + private static Function HNS_H_fa1_1 = new FunctionTestDouble("HNS::H::fa1_1"); + private static Function INS_I_fa1_1 = new FunctionTestDouble("INS::I::fa1_1"); + private static Function JNS_J_fa1_1 = new FunctionTestDouble("JNS::J::fa1_1"); + private static Function KNS_K_fa1_1 = new FunctionTestDouble("KNS::K::fa1_1"); + private static Function LNS_L_fa1_1 = new FunctionTestDouble("LNS::L::fa1_1"); + private static Function N1NS_N1_fn1_1 = new FunctionTestDouble("N1NS::N1::fn1_1"); + private static Function N1NS_N1_fn1_2 = new FunctionTestDouble("N1NS::N1::fn1_2"); + private static Function N2NS_N2_fn2_1 = new FunctionTestDouble("N2NS::N2::fn2_1"); + private static Function N2NS_N2_fn2_2 = new FunctionTestDouble("N2NS::N2::fn2_2"); + private static Function MNS_M_fa1_1 = new FunctionTestDouble("MNS::M::fa1_1"); + private static Function MNS_M_fa2_1 = new FunctionTestDouble("MNS::M::fa2_1"); + private static Function MNS_M_fb1_1 = new FunctionTestDouble("MNS::M::fb1_1"); + private static Function MNS_M_fb2_1 = new FunctionTestDouble("MNS::M::fb1_2"); + private static Function MNS_M_fn1_1 = new FunctionTestDouble("MNS::M::fn1_1"); private static Memory memory32; private static Memory memory64; + private static Program program32; + private static Program program64; + private static List
addresses32; + private static List
addresses64; + + private static List functions; + private static Map offsetsByFunction32 = new HashMap<>(); + private static Map offsetsByFunction64 = new HashMap<>(); private static List vbtSymbols = new ArrayList<>(); private static List vftSymbols = new ArrayList<>(); - private static List
vxtAddresses32; - private static List
vxtAddresses64; private static Map addressByVxtMangledName32; private static Map addressByVxtMangledName64; @@ -184,10 +257,10 @@ public class MsftVxtManagerTest extends AbstractGenericTest { // vbtptr32 = new PointerDataType(new IntegerDataType(dtm32)); // vbtptr64 = new PointerDataType(new IntegerDataType(dtm64)); - createVxTables(); + createMemoryAndPrograms(); - mVxtManager32 = new MsftVxtManager(ctm32, memory32); - mVxtManager64 = new MsftVxtManager(ctm64, memory64); + mVxtManager32 = new MsftVxtManager(ctm32, program32); + mVxtManager64 = new MsftVxtManager(ctm64, program64); try { mVxtManager32.createVirtualTables(CategoryPath.ROOT, addressByVxtMangledName32, log, @@ -201,6 +274,44 @@ public class MsftVxtManagerTest extends AbstractGenericTest { } + private static class MyStubFunctionManager extends StubFunctionManager { + + private Map myFunctions; + + private MyStubFunctionManager() { + myFunctions = new HashMap<>(); + } + + private void addFunction(Address address, Function function) { + myFunctions.put(address, function); + } + + @Override + public Function getFunctionAt(Address entryPoint) { + return myFunctions.get(entryPoint); + } + } + + private static class MyStubProgram extends StubProgram { + private Memory myMemory; + private FunctionManager myFunctionManager; + + private MyStubProgram(Memory mem, FunctionManager fm) { + this.myMemory = mem; + this.myFunctionManager = fm; + } + + @Override + public FunctionManager getFunctionManager() { + return myFunctionManager; + } + + @Override + public Memory getMemory() { + return myMemory; + } + } + //============================================================================================== private static SymbolPath sp(String s) { return new SymbolPath(SymbolPathParser.parse(s)); @@ -216,46 +327,69 @@ public class MsftVxtManagerTest extends AbstractGenericTest { } } - static class MemoryPreparer { + private static class MemoryPreparer { private int nextOffset = 0; private List intArrays = new ArrayList<>(); - private List offsets = new ArrayList<>(); + private List myOffsets = new ArrayList<>(); private List
addresses = new ArrayList<>(); private MyTestMemory memory = null; private int mockAddressCounter = 0; - void addAddresses(int numAddresses, boolean is64bit) { + private int addAddresses(int[] offsetsArg, boolean is64bit) { int[] integers; + int startCount = mockAddressCounter; if (is64bit) { - integers = new int[numAddresses * 2]; - for (int i = 0; i < numAddresses; i++) { - integers[i * 2] = mockAddressCounter; + integers = new int[offsetsArg.length * 2]; + for (int i = 0; i < offsetsArg.length; i++) { + integers[i * 2] = offsetsArg[i]; integers[i * 2 + 1] = 0; } } else { + integers = offsetsArg; + } + addIntegers(integers); + return startCount; + } + + private int addAddresses(int numAddresses, boolean is64bit) { + int[] integers; + int startCount = mockAddressCounter; + if (is64bit) { integers = new int[numAddresses * 2]; for (int i = 0; i < numAddresses; i++) { - integers[i] = mockAddressCounter; + integers[i * 2] = mockAddressCounter++; + integers[i * 2 + 1] = 0; + } + } + else { + integers = new int[numAddresses]; + for (int i = 0; i < numAddresses; i++) { + integers[i] = mockAddressCounter++; } } addIntegers(integers); + return startCount; } - void addIntegers(int[] integers) { - offsets.add(nextOffset); + private int getNextOffset() { + return nextOffset; + } + + private void addIntegers(int[] integers) { + myOffsets.add(nextOffset); intArrays.add(integers); nextOffset += 4 * integers.length; } - List getOffsets() { - return offsets; + private List getOffsets() { + return myOffsets; } - void finalizeMemory() { + private void finalizeMemory() { byte[] bytes = new byte[nextOffset]; - for (int index = 0; index < offsets.size(); index++) { - addBytesForIntegers(intArrays.get(index), bytes, offsets.get(index)); + for (int index = 0; index < myOffsets.size(); index++) { + addBytesForIntegers(intArrays.get(index), bytes, myOffsets.get(index)); } memory = new CppCompositeTestMemory(bytes); AddressIterator iter = memory.getAddresses(true); @@ -263,16 +397,16 @@ public class MsftVxtManagerTest extends AbstractGenericTest { return; } Address address = iter.next(); - for (Integer offset : offsets) { + for (Integer offset : myOffsets) { addresses.add(address.add(offset)); } } - Memory getMemory() { + private Memory getMemory() { return memory; } - List
getAddresses() { + private List
getAddresses() { return addresses; } @@ -299,7 +433,30 @@ public class MsftVxtManagerTest extends AbstractGenericTest { } } - static void createVxTables() { + /** + * Prepares Virtual Function Table for 32-bit and 64-bit memory models + * @param preparer32 the MemoryPreparer for 32-bit + * @param preparer64 the MemoryPreparer for 64-bit + * @param mangledName the mangled name for the table + * @param functionsArg varargs of functions for the table + */ + private static void prepareVfts(MemoryPreparer preparer32, MemoryPreparer preparer64, + String mangledName, Function... functionsArg) { + int offsets32[] = new int[functionsArg.length]; + int offsets64[] = new int[functionsArg.length]; + for (int i = 0; i < functionsArg.length; i++) { + Function fn = functionsArg[i]; + offsets32[i] = offsetsByFunction32.get(fn); + offsets64[i] = offsetsByFunction32.get(fn); + } + preparer32.addAddresses(dummyVftMeta, false); + preparer64.addAddresses(dummyVftMeta, true); + vftSymbols.add(mangledName); + preparer32.addAddresses(offsets32, false); + preparer64.addAddresses(offsets64, true); + } + + private static void createMemoryAndPrograms() { MemoryPreparer preparer32 = new MemoryPreparer(); MemoryPreparer preparer64 = new MemoryPreparer(); @@ -308,6 +465,30 @@ public class MsftVxtManagerTest extends AbstractGenericTest { //========================================================================================== + functions = List.of(A1NS_A1_fa1_1, A1NS_A1_fa1_2, A1NS_A1_fa1_3, A2NS_A2_fa2_1, + A2NS_A2_fa2_2, A2NS_A2_fa2_3, ANS_A_fa1_1, ANS_A_fa2_1, ANS_A_fa_1, + ANS_A_fa1_1_thunkThisMinus16, ANS_A_fa2_1_thunkThisMinus4, B1NS_B1_fb1_1, B1NS_B1_fb1_2, + B1NS_B1_fb1_3, B2NS_B2_fb2_1, B2NS_B2_fb2_2, B2NS_B2_fb2_3, BNS_B_fb1_1, BNS_B_fb2_1, + BNS_B_fb_1, BNS_B_fb1_1_thunkThisMinus16, BNS_B_fb1_1_thunkThisPlus28, + BNS_B_fb2_1_thunkThisPlus28, CNS_C_fa1_2, CNS_C_fa2_1, CNS_C_fb1_2, CNS_C_fb2_1, + CNS_C_fc_1, CNS_C_fa1_2_thunkThisMinus28, CNS_C_fb1_2_thunkThisMinus28, + CNS_C_fa1_2_thunkThisMinus84, CNS_C_fb1_2_thunkThisMinus84, DNS_D_fa2_1, DNS_D_fb2_1, + ENS_E_fa1_1, FNS_F_fa1_1, GNS_G_fa1_1, HNS_H_fa1_1, INS_I_fa1_1, JNS_J_fa1_1, + KNS_K_fa1_1, LNS_L_fa1_1, N1NS_N1_fn1_1, N1NS_N1_fn1_2, N2NS_N2_fn2_1, N2NS_N2_fn2_2, + MNS_M_fa1_1, MNS_M_fa2_1, MNS_M_fb1_1, MNS_M_fb2_1, MNS_M_fn1_1); + + for (Function f : functions) { + int addressOffset32 = preparer32.getNextOffset(); + int addressOffset64 = preparer64.getNextOffset(); + int count32 = preparer32.addAddresses(1, false); + int count64 = preparer64.addAddresses(1, true); + assertEquals(count32, count64); + offsetsByFunction32.put(f, addressOffset32); + offsetsByFunction64.put(f, addressOffset64); + } + + //========================================================================================== + vbtSymbols.add("??_8A@ANS@@7B@"); preparer32.addIntegers(new int[] { -4, 8, 16 }); preparer64.addIntegers(new int[] { -8, 16, 32 }); @@ -373,32 +554,32 @@ public class MsftVxtManagerTest extends AbstractGenericTest { preparer64.addIntegers(new int[] { 0, 32 }); vbtSymbols.add("??_8M@MNS@@7BA@ANS@@E@ENS@@@"); - preparer32.addIntegers(new int[] { -4, 100, 108, 116, 124, 132 }); - preparer64.addIntegers(new int[] { -8, 200, 216, 232, 248, 264 }); + preparer32.addIntegers(new int[] { -4, 108, 116, 124, 132, 140, 100, 152 }); + preparer64.addIntegers(new int[] { -8, 216, 232, 248, 264, 280, 200, 304 }); vbtSymbols.add("??_8M@MNS@@7BC@CNS@@@"); - preparer32.addIntegers(new int[] { -4, 84, 92, 100, 108 }); - preparer64.addIntegers(new int[] { -8, 168, 184, 200, 216 }); + preparer32.addIntegers(new int[] { -4, 92, 100, 108, 116 }); + preparer64.addIntegers(new int[] { -8, 184, 200, 216, 232 }); vbtSymbols.add("??_8M@MNS@@7BA@ANS@@D@DNS@@@"); - preparer32.addIntegers(new int[] { -4, 72, 80 }); - preparer64.addIntegers(new int[] { -8, 144, 160 }); + preparer32.addIntegers(new int[] { -4, 80, 88 }); + preparer64.addIntegers(new int[] { -8, 160, 176 }); vbtSymbols.add("??_8M@MNS@@7BB@BNS@@D@DNS@@@"); - preparer32.addIntegers(new int[] { -4, 76, 84 }); - preparer64.addIntegers(new int[] { -8, 152, 168 }); + preparer32.addIntegers(new int[] { -4, 84, 92 }); + preparer64.addIntegers(new int[] { -8, 168, 184 }); vbtSymbols.add("??_8M@MNS@@7BG@GNS@@@"); - preparer32.addIntegers(new int[] { 0, 48 }); - preparer64.addIntegers(new int[] { 0, 96 }); + preparer32.addIntegers(new int[] { 0, 56 }); + preparer64.addIntegers(new int[] { 0, 112 }); vbtSymbols.add("??_8M@MNS@@7BH@HNS@@@"); - preparer32.addIntegers(new int[] { 0, 36 }); - preparer64.addIntegers(new int[] { 0, 72 }); + preparer32.addIntegers(new int[] { 0, 44 }); + preparer64.addIntegers(new int[] { 0, 88 }); vbtSymbols.add("??_8M@MNS@@7B@"); - preparer32.addIntegers(new int[] { 0, 20 }); - preparer64.addIntegers(new int[] { 0, 40 }); + preparer32.addIntegers(new int[] { 0, 28 }); + preparer64.addIntegers(new int[] { 0, 56 }); vbtSymbols.add("??_8M@MNS@@7BB@BNS@@E@ENS@@@"); preparer32.addIntegers(new int[] { -4, -20, -12 }); @@ -408,181 +589,133 @@ public class MsftVxtManagerTest extends AbstractGenericTest { // Below: writing one int to simulate one address for 32-bit and tow ints for 64-bit (lsb) // Later... mock up even better - vftSymbols.add("??_7A1@A1NS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7A1@A1NS@@6B@", A1NS_A1_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7A2@A2NS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7A2@A2NS@@6B@", A2NS_A2_fa2_1, A2NS_A2_fa2_2, + A2NS_A2_fa2_3); - vftSymbols.add("??_7A@ANS@@6B01@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7A@ANS@@6B01@@", ANS_A_fa_1); - vftSymbols.add("??_7A@ANS@@6BA1@A1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7A@ANS@@6BA1@A1NS@@@", ANS_A_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7A@ANS@@6BA2@A2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7A@ANS@@6BA2@A2NS@@@", ANS_A_fa2_1, A2NS_A2_fa2_2, + A2NS_A2_fa2_3); - vftSymbols.add("??_7B1@B1NS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7B1@B1NS@@6B@", B1NS_B1_fb1_1, B1NS_B1_fb1_2, + B1NS_B1_fb1_3); - vftSymbols.add("??_7B2@B2NS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7B2@B2NS@@6B@", B2NS_B2_fb2_1, B2NS_B2_fb2_2, + B2NS_B2_fb2_3); - vftSymbols.add("??_7B@BNS@@6B01@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7B@BNS@@6B01@@", BNS_B_fb_1); - vftSymbols.add("??_7B@BNS@@6BB1@B1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7B@BNS@@6BB1@B1NS@@@", BNS_B_fb1_1, B1NS_B1_fb1_2, + B1NS_B1_fb1_3); - vftSymbols.add("??_7B@BNS@@6BB2@B2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7B@BNS@@6BB2@B2NS@@@", BNS_B_fb2_1, B2NS_B2_fb2_2, + B2NS_B2_fb2_3); - vftSymbols.add("??_7C@CNS@@6B01@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7C@CNS@@6B01@@", CNS_C_fc_1); - vftSymbols.add("??_7C@CNS@@6BA1@A1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7C@CNS@@6BA1@A1NS@@@", A1NS_A1_fa1_1, CNS_C_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7C@CNS@@6BA2@A2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7C@CNS@@6BA2@A2NS@@@", CNS_C_fa2_1, A2NS_A2_fa2_2, + A2NS_A2_fa2_3); - vftSymbols.add("??_7C@CNS@@6BB1@B1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7C@CNS@@6BB1@B1NS@@@", B1NS_B1_fb1_1, CNS_C_fb1_2, + B1NS_B1_fb1_3); - vftSymbols.add("??_7C@CNS@@6BB2@B2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7C@CNS@@6BB2@B2NS@@@", CNS_C_fb2_1, B2NS_B2_fb2_2, + B2NS_B2_fb2_3); - vftSymbols.add("??_7D@DNS@@6BC@CNS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7D@DNS@@6BC@CNS@@@", CNS_C_fc_1); - vftSymbols.add("??_7D@DNS@@6BA@ANS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7D@DNS@@6BA@ANS@@@", ANS_A_fa_1); - vftSymbols.add("??_7D@DNS@@6BB@BNS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7D@DNS@@6BB@BNS@@@", BNS_B_fb_1); - vftSymbols.add("??_7D@DNS@@6BA1@A1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7D@DNS@@6BA1@A1NS@@@", ANS_A_fa1_1_thunkThisMinus16, + CNS_C_fa1_2_thunkThisMinus28, A1NS_A1_fa1_3); - vftSymbols.add("??_7D@DNS@@6BA2@A2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7D@DNS@@6BA2@A2NS@@@", DNS_D_fa2_1, A2NS_A2_fa2_2, + A2NS_A2_fa2_3); - vftSymbols.add("??_7D@DNS@@6BB1@B1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7D@DNS@@6BB1@B1NS@@@", BNS_B_fb1_1_thunkThisMinus16, + CNS_C_fb1_2_thunkThisMinus28, B1NS_B1_fb1_3); - vftSymbols.add("??_7D@DNS@@6BB2@B2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7D@DNS@@6BB2@B2NS@@@", DNS_D_fb2_1, B2NS_B2_fb2_2, + B2NS_B2_fb2_3); - vftSymbols.add("??_7E@ENS@@6BA@ANS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7E@ENS@@6BA@ANS@@@", ANS_A_fa_1); - vftSymbols.add("??_7E@ENS@@6BA1@A1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7E@ENS@@6BA1@A1NS@@@", ENS_E_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7E@ENS@@6BA2@A2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7E@ENS@@6BA2@A2NS@@@", ANS_A_fa2_1_thunkThisMinus4, + A2NS_A2_fa2_2, A2NS_A2_fa2_3); - vftSymbols.add("??_7E@ENS@@6BB1@B1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7E@ENS@@6BB1@B1NS@@@", BNS_B_fb1_1_thunkThisPlus28, + B1NS_B1_fb1_2, B1NS_B1_fb1_3); - vftSymbols.add("??_7E@ENS@@6BB2@B2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7E@ENS@@6BB2@B2NS@@@", BNS_B_fb2_1_thunkThisPlus28, + B2NS_B2_fb2_2, B2NS_B2_fb2_3); - vftSymbols.add("??_7E@ENS@@6BB@BNS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7E@ENS@@6BB@BNS@@@", BNS_B_fb_1); - vftSymbols.add("??_7F@FNS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7F@FNS@@6B@", FNS_F_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7G@GNS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7G@GNS@@6B@", GNS_G_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7H@HNS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7H@HNS@@6B@", HNS_H_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7I@INS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7I@INS@@6B@", INS_I_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7J@JNS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7J@JNS@@6B@", JNS_J_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7K@KNS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7K@KNS@@6B@", KNS_K_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7L@LNS@@6B@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7L@LNS@@6B@", LNS_L_fa1_1, A1NS_A1_fa1_2, + A1NS_A1_fa1_3); - vftSymbols.add("??_7M@MNS@@6BA@ANS@@E@ENS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7N1@N1NS@@6B@", N1NS_N1_fn1_1, N1NS_N1_fn1_2); - vftSymbols.add("??_7M@MNS@@6BC@CNS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7N2@N2NS@@6B@", N2NS_N2_fn2_1, N2NS_N2_fn2_2); - vftSymbols.add("??_7M@MNS@@6BA@ANS@@D@DNS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BA@ANS@@E@ENS@@@", ANS_A_fa_1); - vftSymbols.add("??_7M@MNS@@6BB@BNS@@D@DNS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BC@CNS@@@", CNS_C_fc_1); - vftSymbols.add("??_7M@MNS@@6BA1@A1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BA@ANS@@D@DNS@@@", ANS_A_fa_1); - vftSymbols.add("??_7M@MNS@@6BA2@A2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BB@BNS@@D@DNS@@@", BNS_B_fb_1); - vftSymbols.add("??_7M@MNS@@6BB1@B1NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BN1@N1NS@@@", MNS_M_fn1_1, N1NS_N1_fn1_2); - vftSymbols.add("??_7M@MNS@@6BB2@B2NS@@@"); - preparer32.addAddresses(3, false); - preparer64.addAddresses(3, true); + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BA1@A1NS@@@", MNS_M_fa1_1, + CNS_C_fa1_2_thunkThisMinus84, A1NS_A1_fa1_3); - vftSymbols.add("??_7M@MNS@@6BB@BNS@@E@ENS@@@"); - preparer32.addAddresses(1, false); - preparer64.addAddresses(1, true); + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BA2@A2NS@@@", MNS_M_fa2_1, A2NS_A2_fa2_2, + A2NS_A2_fa2_3); + + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BB1@B1NS@@@", MNS_M_fb1_1, + CNS_C_fb1_2_thunkThisMinus84, B1NS_B1_fb1_3); + + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BB2@B2NS@@@", MNS_M_fb2_1, B2NS_B2_fb2_2, + B2NS_B2_fb2_3); + + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BB@BNS@@E@ENS@@@", BNS_B_fb_1); + + prepareVfts(preparer32, preparer64, "??_7M@MNS@@6BN2@N2NS@@@", N2NS_N2_fn2_1, + N2NS_N2_fn2_2); //========================================================================================== @@ -592,32 +725,79 @@ public class MsftVxtManagerTest extends AbstractGenericTest { memory32 = preparer32.getMemory(); memory64 = preparer64.getMemory(); - vxtAddresses32 = preparer32.getAddresses(); - vxtAddresses64 = preparer64.getAddresses(); + MyStubFunctionManager functionManager32 = new MyStubFunctionManager(); + MyStubFunctionManager functionManager64 = new MyStubFunctionManager(); + + program32 = new MyStubProgram(memory32, functionManager32); + program64 = new MyStubProgram(memory64, functionManager64); + + addresses32 = preparer32.getAddresses(); + addresses64 = preparer64.getAddresses(); addressByVxtMangledName32 = new HashMap<>(); addressByVxtMangledName64 = new HashMap<>(); - if (vbtSymbols.size() + vftSymbols.size() != vxtAddresses32.size() || - vbtSymbols.size() + vftSymbols.size() != vxtAddresses64.size()) { + if (functions.size() + vbtSymbols.size() + 2 * vftSymbols.size() != addresses32.size() || + functions.size() + vbtSymbols.size() + 2 * vftSymbols.size() != addresses64.size()) { throw new AssertException("Fatal: list sizes do not match"); } - int aCount = 0; + int accumulatedCount = 0; + for (Function f : functions) { + functionManager32.addFunction(addresses32.get(accumulatedCount), f); + functionManager64.addFunction(addresses64.get(accumulatedCount), f); + accumulatedCount++; + } for (String vbtSymbol : vbtSymbols) { - addressByVxtMangledName32.put(vbtSymbol, vxtAddresses32.get(aCount)); - addressByVxtMangledName64.put(vbtSymbol, vxtAddresses64.get(aCount)); - aCount++; + addressByVxtMangledName32.put(vbtSymbol, addresses32.get(accumulatedCount)); + addressByVxtMangledName64.put(vbtSymbol, addresses64.get(accumulatedCount)); + accumulatedCount++; } for (String vftSymbol : vftSymbols) { - addressByVxtMangledName32.put(vftSymbol, vxtAddresses32.get(aCount)); - addressByVxtMangledName64.put(vftSymbol, vxtAddresses64.get(aCount)); - aCount++; + // skip an extra for each meta + addressByVxtMangledName32.put(vftSymbol, addresses32.get(accumulatedCount + 1)); + addressByVxtMangledName64.put(vftSymbol, addresses64.get(accumulatedCount + 1)); + accumulatedCount += 2; } } //============================================================================================== //============================================================================================== - // No tests at this point because of need to rework the design + // Not many tests at this point because of need to rework the design of finding tables + // based on parentage (which is not the necessarily the same as nesting in the layout). + + @Test + public void testMVbt_temp() throws Exception { + + ProgramVirtualBaseTable vbt; + + vbt = (ProgramVirtualBaseTable) mVxtManager32.findVbt(M_ID, List.of(M_ID)); + assertEquals(addresses32.get(73), vbt.getAddress()); + // Not certain that this one is a valid query... depends on the design work that needs + // to be done +// vbt = (ProgramVirtualBaseTable) mVxtManager32.findVbt(mId, List.of(eId)); +// assertEquals(addresses32.get(73), vbt.getAddress()); + } + + //============================================================================================== + @Test + public void testMVft_temp() throws Exception { + + ProgramVirtualFunctionTable vft; + Address address; + Function function; + + // Test with and without parentage referencing owner type. We are treating them as the + // same for now. If we can tease out more information or encounter difficulties, we + // need to split these out accordingly (within the work of findVft (and findVbt)). + vft = (ProgramVirtualFunctionTable) mVxtManager32.findVft(A_ID, List.of(A_ID)); + assertEquals(addresses32.get(80), vft.getAddress()); + address = vft.getAddress(0); + function = program32.getFunctionManager().getFunctionAt(address); + assertEquals(ANS_A_fa_1, function); + function.getName().equals(ANS_A_fa_1.getName()); + vft = (ProgramVirtualFunctionTable) mVxtManager32.findVft(A_ID, List.of()); + assertEquals(addresses32.get(80), vft.getAddress()); + } } diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java index 74b5bfd3c6..f179c01a43 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeTypeTest.java @@ -27,9 +27,12 @@ import ghidra.app.plugin.core.checksums.MyTestMemory; import ghidra.app.util.SymbolPath; import ghidra.app.util.importer.MessageLog; import ghidra.app.util.pdb.classtype.*; +import ghidra.program.model.StubFunctionManager; +import ghidra.program.model.StubProgram; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressIterator; import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryAccessException; import ghidra.util.LittleEndianDataConverter; @@ -54,6 +57,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { private static ClassTypeManager ctm64; private static Memory memory32; private static Memory memory64; + private static Program program32; + private static Program program64; private static Map addressByMangledName32; private static Map addressByMangledName64; private static DataType vftptr32; @@ -180,8 +185,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest { createVbTables(); - msftVxtManager32 = new MsftVxtManager(ctm32, memory32); - msftVxtManager64 = new MsftVxtManager(ctm64, memory64); + msftVxtManager32 = new MsftVxtManager(ctm32, program32); + msftVxtManager64 = new MsftVxtManager(ctm64, program64); try { msftVxtManager32.createVirtualTables(CategoryPath.ROOT, addressByMangledName32, log, monitor); @@ -268,6 +273,44 @@ public class CppCompositeTypeTest extends AbstractGenericTest { } } + private static class MyStubFunctionManager extends StubFunctionManager { + + private Map myFunctions; + + private MyStubFunctionManager() { + myFunctions = new HashMap<>(); + } + + private void addFunction(Address address, Function function) { + myFunctions.put(address, function); + } + + @Override + public Function getFunctionAt(Address entryPoint) { + return null; + } + } + + private static class MyStubProgram extends StubProgram { + private Memory myMemory; + private FunctionManager myFunctionManager; + + private MyStubProgram(Memory mem, FunctionManager fm) { + this.myMemory = mem; + this.myFunctionManager = fm; + } + + @Override + public FunctionManager getFunctionManager() { + return myFunctionManager; + } + + @Override + public Memory getMemory() { + return myMemory; + } + } + static void createVbTables() { MemoryPreparer preparer32 = new MemoryPreparer(); MemoryPreparer preparer64 = new MemoryPreparer(); @@ -484,6 +527,12 @@ public class CppCompositeTypeTest extends AbstractGenericTest { memory32 = preparer32.getMemory(); memory64 = preparer64.getMemory(); + MyStubFunctionManager functionManager32 = new MyStubFunctionManager(); + MyStubFunctionManager functionManager64 = new MyStubFunctionManager(); + + program32 = new MyStubProgram(memory32, functionManager32); + program64 = new MyStubProgram(memory64, functionManager64); + List
addresses32 = preparer32.getAddresses(); List
addresses64 = preparer64.getAddresses();