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 6ab5cb0766..04a7a7eb3d 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 @@ -124,8 +124,8 @@ public class MsftVxtManager extends VxtManager { // memory are the same order that their pointers appear in the classes... this is based solely // on limited experience. The solution stinks and would benefit from the original direction // of using the parentage. We will try to use the parentage as a litmus test on retrieval - private Map> vbtsByOwner; - private Map> vftsByOwner; + private Map> vbtsByOwner; + private Map> vftsByOwner; // Used for locating vft and vbt // These are explicitly used for storing/retrieving the "program" versions which result from @@ -173,27 +173,73 @@ public class MsftVxtManager extends VxtManager { /** * Finds the putative {@link VirtualBaseTable} in memory requested for the owning class * @param owner the owning class of the table + * @param parentage the primary parentage (only used if creating placeholder) * @return the table */ - public VirtualBaseTable findPrimaryVbt(ClassID owner) { - TreeMap map = vbtsByOwner.get(owner); - if (map == null) { + public VirtualBaseTable findPrimaryVbt(ClassID owner, List parentage) { + List list = vbtsByOwner.get(owner); + if (list == null) { return null; } - return map.firstEntry().getValue(); + VirtualBaseTable result = null; + VirtualBaseTable firstPlaceholder = null; + Address addrResult = null; + for (VirtualBaseTable table : list) { + if (table instanceof ProgramVirtualBaseTable pvbt) { + Address addr = pvbt.getAddress(); + if (addrResult == null || addr.compareTo(addrResult) < 0) { + addrResult = addr; + result = table; + } + } + else if (firstPlaceholder == null) { + firstPlaceholder = table; + } + } + if (result == null) { + if (firstPlaceholder != null) { + return firstPlaceholder; + } + result = new PlaceholderVirtualBaseTable(owner, parentage); + list.add(result); + } + return result; } /** * Finds the putative {@link VirtualFunctionTable} in memory requested for the owning class * @param owner the owning class of the table + * @param parentage the primary parentage (only used if creating placeholder) * @return the table */ - public VirtualFunctionTable findPrimaryVft(ClassID owner) { - TreeMap map = vftsByOwner.get(owner); - if (map == null) { + public VirtualFunctionTable findPrimaryVft(ClassID owner, List parentage) { + List list = vftsByOwner.get(owner); + if (list == null) { return null; } - return map.firstEntry().getValue(); + VirtualFunctionTable result = null; + VirtualFunctionTable firstPlaceholder = null; + Address addrResult = null; + for (VirtualFunctionTable table : list) { + if (table instanceof ProgramVirtualFunctionTable pvft) { + Address addr = pvft.getAddress(); + if (addrResult == null || addr.compareTo(addrResult) < 0) { + addrResult = addr; + result = table; + } + } + else if (firstPlaceholder == null) { + firstPlaceholder = table; + } + } + if (result == null) { + if (firstPlaceholder != null) { + return firstPlaceholder; + } + result = new PlaceholderVirtualFunctionTable(owner, parentage); + list.add(result); + } + return result; } /** @@ -211,7 +257,7 @@ public class MsftVxtManager extends VxtManager { * @return the IDs */ public ClassID[] getAllVftOwners() { - ClassID ids[] = new ClassID[vbtsByOwner.size()]; + ClassID ids[] = new ClassID[vftsByOwner.size()]; Set set = vftsByOwner.keySet(); return set.toArray(ids); } @@ -222,12 +268,11 @@ public class MsftVxtManager extends VxtManager { * @return the tables */ public VirtualBaseTable[] getVbts(ClassID owner) { - TreeMap map = vbtsByOwner.get(owner); - if (map == null) { + List list = vbtsByOwner.get(owner); + if (list == null) { return null; } - Collection values = map.values(); - return values.toArray(new VirtualBaseTable[values.size()]); + return list.toArray(new VirtualBaseTable[list.size()]); } /** @@ -236,12 +281,11 @@ public class MsftVxtManager extends VxtManager { * @return the tables */ public VirtualFunctionTable[] getVfts(ClassID owner) { - TreeMap map = vftsByOwner.get(owner); - if (map == null) { + List list = vftsByOwner.get(owner); + if (list == null) { return null; } - Collection values = map.values(); - return values.toArray(new VirtualFunctionTable[values.size()]); + return list.toArray(new VirtualFunctionTable[list.size()]); } /** @@ -264,6 +308,7 @@ public class MsftVxtManager extends VxtManager { vbt = new PlaceholderVirtualBaseTable(owner, parentage); } vbtsByOwnerParentage.put(op, vbt); + storeVbt(owner, vbt); return vbt; } @@ -309,6 +354,7 @@ public class MsftVxtManager extends VxtManager { vft = new PlaceholderVirtualFunctionTable(owner, parentage); } vftsByOwnerParentage.put(op, vft); + storeVft(owner, vft); return vft; } @@ -417,7 +463,7 @@ public class MsftVxtManager extends VxtManager { } node.setVBTable(prvbt); vbtByAddress.put(address, prvbt); - storeVbt(owner, address, prvbt); // temp solution? + storeVbt(owner, prvbt); // temp solution? break; case VFT: @@ -429,7 +475,7 @@ public class MsftVxtManager extends VxtManager { } node.setVFTable(vft); vftByAddress.put(address, vft); - storeVft(owner, address, vft); // temp solution? + storeVft(owner, vft); // temp solution? break; default: @@ -438,22 +484,49 @@ public class MsftVxtManager extends VxtManager { return true; } - private void storeVbt(ClassID owner, Address address, VirtualBaseTable vbt) { - TreeMap map = vbtsByOwner.get(owner); - if (map == null) { - map = new TreeMap<>(); - vbtsByOwner.put(owner, map); + private void storeVbt(ClassID owner, VirtualBaseTable vbt) { + ClassID own = vbt.getOwner(); + List list = vbtsByOwner.get(own); + if (list == null) { + list = new ArrayList<>(); + vbtsByOwner.put(owner, list); } - map.put(address, vbt); + List parentage = vbt.getParentage(); + for (VirtualBaseTable table : list) { + if (isEqual(table.getParentage(), parentage)) { + return; // return without saving + } + } + list.add(vbt); } - private void storeVft(ClassID owner, Address address, VirtualFunctionTable vft) { - TreeMap map = vftsByOwner.get(owner); - if (map == null) { - map = new TreeMap<>(); - vftsByOwner.put(owner, map); + private void storeVft(ClassID owner, VirtualFunctionTable vft) { + List list = vftsByOwner.get(owner); + if (list == null) { + list = new ArrayList<>(); + vftsByOwner.put(owner, list); } - map.put(address, vft); + List parentage = vft.getParentage(); + for (VirtualFunctionTable table : list) { + if (isEqual(table.getParentage(), parentage)) { + return; // return without saving + } + } + list.add(vft); + } + + private boolean isEqual(List parentage1, List parentage2) { + int diff = parentage1.size() - parentage2.size(); + if (diff != 0) { + return false; + } + Iterator iter2 = parentage2.iterator(); + for (ClassID element : parentage1) { + if (!element.equals(iter2.next())) { + return false; + } + } + return true; } private ParentageNode findNode(ClassID owner, List parentage, ParentageNode root) { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java index ef1b066ee1..d527e500ae 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java @@ -1231,19 +1231,25 @@ public class CppCompositeType { // Note that if the parent has already had its layout done, it will not have // used the vxtManager that we are passing in here; it will have used whatever // was passed to the layout method for that class - for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVfts()) { - VxtPtrInfo newInfo = - createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset); - updateVft(vxtManager, baseId, newInfo, parentInfo); - storeVxtInfo(propagatedSelfBaseVfts, finalVftPtrInfoByOffset, vftTableIdByOffset, - vftOffsetByTableId, newInfo); + if (cppBaseType.getPropagatedSelfBaseVfts() != null) { + for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVfts()) { + VxtPtrInfo newInfo = + createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset); + updateVft(vxtManager, baseId, newInfo, parentInfo); + storeVxtInfo(propagatedSelfBaseVfts, finalVftPtrInfoByOffset, + vftTableIdByOffset, + vftOffsetByTableId, newInfo); + } } - for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVbts()) { - VxtPtrInfo newInfo = - createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset); - updateVbt(vxtManager, baseId, newInfo, parentInfo); - storeVxtInfo(propagatedSelfBaseVbts, finalVbtPtrInfoByOffset, vbtTableIdByOffset, - vbtOffsetByTableId, newInfo); + if (cppBaseType.getPropagatedSelfBaseVbts() != null) { + for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVbts()) { + VxtPtrInfo newInfo = + createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset); + updateVbt(vxtManager, baseId, newInfo, parentInfo); + storeVxtInfo(propagatedSelfBaseVbts, finalVbtPtrInfoByOffset, + vbtTableIdByOffset, + vbtOffsetByTableId, newInfo); + } } } } @@ -1253,8 +1259,9 @@ public class CppCompositeType { * virtual bases. Gathers results from the accumulation of all "direct" virtual base classes; * we are not relying on the "indirect" virtual base class information from the PDB. This * is done this way so that we can collect parentage information for the pointers. + * @throws PdbException upon issue finding base offset */ - private void findVirtualBaseVxtPtrs(MsftVxtManager vxtManager) { + private void findVirtualBaseVxtPtrs(MsftVxtManager vxtManager) throws PdbException { // Walk direct bases to find vxts of virtual bases. TODO: also notate all rolled up // virtuals for each direct base. for (DirectLayoutBaseClass base : directLayoutBaseClasses) { @@ -1396,10 +1403,16 @@ public class CppCompositeType { * Converts VxtPtrInfo from virtual-based-owned direct or indirect virtual base for this class * @param baseInfo the vxt info from the base * @return the new VxtPtrInfo for this class + * @throws PdbException upon issue getting base offset */ - private VxtPtrInfo createVirtualOwnedVirtualVxtPtrInfo(VxtPtrInfo baseInfo) { + private VxtPtrInfo createVirtualOwnedVirtualVxtPtrInfo(VxtPtrInfo baseInfo) + throws PdbException { Long accumOffset = baseInfo.accumOffset(); - Long finalOffset = accumOffset + baseOffsetById.get(baseInfo.baseId()); + Long baseOffset = baseOffsetById.get(baseInfo.baseId()); + if (baseOffset == null) { + throw new PdbException("Cannot find base offset"); + } + Long finalOffset = accumOffset + baseOffset; return new VxtPtrInfo(finalOffset, accumOffset, baseInfo.baseId(), updateParentage(baseInfo)); } @@ -1440,20 +1453,10 @@ public class CppCompositeType { myVftPtrOffset = vftPtrTypeByOffset.firstKey(); VxtPtrInfo info = new VxtPtrInfo(myVftPtrOffset, myVftPtrOffset, myId, List.of(myId)); - VirtualFunctionTable myVft = - vxtManager.findVft(myId, List.of(myId)); - if (myVft != null) { - myVft.setPtrOffsetInClass(info.finalOffset()); - propagatedSelfBaseVfts.add(info); - finalVftByOffset.put(info.finalOffset(), myVft); - } - else { - PlaceholderVirtualFunctionTable t = new PlaceholderVirtualFunctionTable( - myId, List.of(myId)); - t.setPtrOffsetInClass(info.finalOffset()); - propagatedSelfBaseVfts.add(info); - finalVftByOffset.put(info.finalOffset(), t); - } + VirtualFunctionTable myVft = vxtManager.findVft(myId, info.parentage()); + myVft.setPtrOffsetInClass(info.finalOffset()); + propagatedSelfBaseVfts.add(info); + finalVftByOffset.put(info.finalOffset(), myVft); finalVftPtrInfoByOffset.put(info.accumOffset(), info); OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage()); vftTableIdByOffset.put(info.accumOffset(), op); @@ -1473,8 +1476,8 @@ public class CppCompositeType { * structure */ private void findOrAllocateMainVbtPtr(MsftVxtManager vxtManager) { - if (propagatedSelfBaseVbts.isEmpty()) { - if (!virtualLayoutBaseClasses.isEmpty()) { + if (propagatedSelfBaseVbts.isEmpty()) { // a pointer might be available in a direct base + if (!virtualLayoutBaseClasses.isEmpty()) { // there is a need for a main vbtptr TreeSet vbtOffsets = new TreeSet<>(); for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) { vbtOffsets.add((long) base.getBasePointerOffset()); @@ -1487,12 +1490,10 @@ public class CppCompositeType { Msg.warn(this, "Mismatch vbt location for " + myId); } VxtPtrInfo info = new VxtPtrInfo(vbtPtrOffset, vbtPtrOffset, myId, List.of(myId)); - VirtualBaseTable myVbt = vxtManager.findVbt(myId, List.of(myId)); - if (myVbt != null) { - myVbt.setPtrOffsetInClass(info.finalOffset()); - propagatedSelfBaseVbts.add(info); - finalVbtByOffset.put(info.finalOffset(), myVbt); - } + VirtualBaseTable myVbt = vxtManager.findVbt(myId, info.parentage()); + myVbt.setPtrOffsetInClass(info.finalOffset()); + propagatedSelfBaseVbts.add(info); + finalVbtByOffset.put(info.finalOffset(), myVbt); finalVbtPtrInfoByOffset.put(info.accumOffset(), info); OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage()); vbtTableIdByOffset.put(info.accumOffset(), op); @@ -1699,7 +1700,7 @@ public class CppCompositeType { private VirtualFunctionTable getMainVft(MsftVxtManager vxtManager) throws PdbException { if (!finalVftPtrInfoByOffset.isEmpty()) { VxtPtrInfo firstVftPtrInfo = finalVftPtrInfoByOffset.firstEntry().getValue(); - VirtualFunctionTable vft = vxtManager.findVft(myId, firstVftPtrInfo.parentage()); + VirtualFunctionTable vft = vxtManager.findPrimaryVft(myId, firstVftPtrInfo.parentage()); return vft; // Following is for consideration for testing without a program: // if (vft instanceof ProgramVirtualFunctionTable pvft) { @@ -1723,7 +1724,7 @@ public class CppCompositeType { private VirtualBaseTable getMainVbt(MsftVxtManager vxtManager) throws PdbException { if (!finalVbtPtrInfoByOffset.isEmpty()) { VxtPtrInfo firstVbtPtrInfo = finalVbtPtrInfoByOffset.firstEntry().getValue(); - VirtualBaseTable vbt = vxtManager.findVbt(myId, firstVbtPtrInfo.parentage()); + VirtualBaseTable vbt = vxtManager.findPrimaryVbt(myId, firstVbtPtrInfo.parentage()); if (vbt instanceof ProgramVirtualBaseTable pvbt) { return pvbt; } @@ -1747,8 +1748,10 @@ public class CppCompositeType { return plvbt; } else { - throw new PdbException( - "VBT type not expected: " + vbt.getClass().getSimpleName()); + if (vbt != null) { + throw new PdbException( + "VBT type not expected: " + vbt.getClass().getSimpleName()); + } } } return null;