Skip to content

Commit c32bc2a

Browse files
committed
GP-5559 - PDB - Work around issue with finding primary vxt by symbol
1 parent e4036f0 commit c32bc2a

File tree

2 files changed

+150
-74
lines changed

2 files changed

+150
-74
lines changed

Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/classtype/MsftVxtManager.java

Lines changed: 106 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ public class MsftVxtManager extends VxtManager {
124124
// memory are the same order that their pointers appear in the classes... this is based solely
125125
// on limited experience. The solution stinks and would benefit from the original direction
126126
// of using the parentage. We will try to use the parentage as a litmus test on retrieval
127-
private Map<ClassID, TreeMap<Address, VirtualBaseTable>> vbtsByOwner;
128-
private Map<ClassID, TreeMap<Address, VirtualFunctionTable>> vftsByOwner;
127+
private Map<ClassID, List<VirtualBaseTable>> vbtsByOwner;
128+
private Map<ClassID, List<VirtualFunctionTable>> vftsByOwner;
129129

130130
// Used for locating vft and vbt
131131
// These are explicitly used for storing/retrieving the "program" versions which result from
@@ -173,27 +173,73 @@ public void doTableLayouts(DataTypeManager dtm) {
173173
/**
174174
* Finds the putative {@link VirtualBaseTable} in memory requested for the owning class
175175
* @param owner the owning class of the table
176+
* @param parentage the primary parentage (only used if creating placeholder)
176177
* @return the table
177178
*/
178-
public VirtualBaseTable findPrimaryVbt(ClassID owner) {
179-
TreeMap<Address, VirtualBaseTable> map = vbtsByOwner.get(owner);
180-
if (map == null) {
179+
public VirtualBaseTable findPrimaryVbt(ClassID owner, List<ClassID> parentage) {
180+
List<VirtualBaseTable> list = vbtsByOwner.get(owner);
181+
if (list == null) {
181182
return null;
182183
}
183-
return map.firstEntry().getValue();
184+
VirtualBaseTable result = null;
185+
VirtualBaseTable firstPlaceholder = null;
186+
Address addrResult = null;
187+
for (VirtualBaseTable table : list) {
188+
if (table instanceof ProgramVirtualBaseTable pvbt) {
189+
Address addr = pvbt.getAddress();
190+
if (addrResult == null || addr.compareTo(addrResult) < 0) {
191+
addrResult = addr;
192+
result = table;
193+
}
194+
}
195+
else if (firstPlaceholder == null) {
196+
firstPlaceholder = table;
197+
}
198+
}
199+
if (result == null) {
200+
if (firstPlaceholder != null) {
201+
return firstPlaceholder;
202+
}
203+
result = new PlaceholderVirtualBaseTable(owner, parentage);
204+
list.add(result);
205+
}
206+
return result;
184207
}
185208

186209
/**
187210
* Finds the putative {@link VirtualFunctionTable} in memory requested for the owning class
188211
* @param owner the owning class of the table
212+
* @param parentage the primary parentage (only used if creating placeholder)
189213
* @return the table
190214
*/
191-
public VirtualFunctionTable findPrimaryVft(ClassID owner) {
192-
TreeMap<Address, VirtualFunctionTable> map = vftsByOwner.get(owner);
193-
if (map == null) {
215+
public VirtualFunctionTable findPrimaryVft(ClassID owner, List<ClassID> parentage) {
216+
List<VirtualFunctionTable> list = vftsByOwner.get(owner);
217+
if (list == null) {
194218
return null;
195219
}
196-
return map.firstEntry().getValue();
220+
VirtualFunctionTable result = null;
221+
VirtualFunctionTable firstPlaceholder = null;
222+
Address addrResult = null;
223+
for (VirtualFunctionTable table : list) {
224+
if (table instanceof ProgramVirtualFunctionTable pvft) {
225+
Address addr = pvft.getAddress();
226+
if (addrResult == null || addr.compareTo(addrResult) < 0) {
227+
addrResult = addr;
228+
result = table;
229+
}
230+
}
231+
else if (firstPlaceholder == null) {
232+
firstPlaceholder = table;
233+
}
234+
}
235+
if (result == null) {
236+
if (firstPlaceholder != null) {
237+
return firstPlaceholder;
238+
}
239+
result = new PlaceholderVirtualFunctionTable(owner, parentage);
240+
list.add(result);
241+
}
242+
return result;
197243
}
198244

199245
/**
@@ -211,7 +257,7 @@ public ClassID[] getAllVbtOwners() {
211257
* @return the IDs
212258
*/
213259
public ClassID[] getAllVftOwners() {
214-
ClassID ids[] = new ClassID[vbtsByOwner.size()];
260+
ClassID ids[] = new ClassID[vftsByOwner.size()];
215261
Set<ClassID> set = vftsByOwner.keySet();
216262
return set.toArray(ids);
217263
}
@@ -222,12 +268,11 @@ public ClassID[] getAllVftOwners() {
222268
* @return the tables
223269
*/
224270
public VirtualBaseTable[] getVbts(ClassID owner) {
225-
TreeMap<Address, VirtualBaseTable> map = vbtsByOwner.get(owner);
226-
if (map == null) {
271+
List<VirtualBaseTable> list = vbtsByOwner.get(owner);
272+
if (list == null) {
227273
return null;
228274
}
229-
Collection<VirtualBaseTable> values = map.values();
230-
return values.toArray(new VirtualBaseTable[values.size()]);
275+
return list.toArray(new VirtualBaseTable[list.size()]);
231276
}
232277

233278
/**
@@ -236,12 +281,11 @@ public VirtualBaseTable[] getVbts(ClassID owner) {
236281
* @return the tables
237282
*/
238283
public VirtualFunctionTable[] getVfts(ClassID owner) {
239-
TreeMap<Address, VirtualFunctionTable> map = vftsByOwner.get(owner);
240-
if (map == null) {
284+
List<VirtualFunctionTable> list = vftsByOwner.get(owner);
285+
if (list == null) {
241286
return null;
242287
}
243-
Collection<VirtualFunctionTable> values = map.values();
244-
return values.toArray(new VirtualFunctionTable[values.size()]);
288+
return list.toArray(new VirtualFunctionTable[list.size()]);
245289
}
246290

247291
/**
@@ -264,6 +308,7 @@ public VirtualBaseTable findVbt(ClassID owner, List<ClassID> parentage) {
264308
vbt = new PlaceholderVirtualBaseTable(owner, parentage);
265309
}
266310
vbtsByOwnerParentage.put(op, vbt);
311+
storeVbt(owner, vbt);
267312
return vbt;
268313
}
269314

@@ -309,6 +354,7 @@ public VirtualFunctionTable findVft(ClassID owner, List<ClassID> parentage) {
309354
vft = new PlaceholderVirtualFunctionTable(owner, parentage);
310355
}
311356
vftsByOwnerParentage.put(op, vft);
357+
storeVft(owner, vft);
312358
return vft;
313359
}
314360

@@ -417,7 +463,7 @@ public boolean createVirtualTable(CategoryPath categoryPath, String mangled, Add
417463
}
418464
node.setVBTable(prvbt);
419465
vbtByAddress.put(address, prvbt);
420-
storeVbt(owner, address, prvbt); // temp solution?
466+
storeVbt(owner, prvbt); // temp solution?
421467
break;
422468

423469
case VFT:
@@ -429,7 +475,7 @@ public boolean createVirtualTable(CategoryPath categoryPath, String mangled, Add
429475
}
430476
node.setVFTable(vft);
431477
vftByAddress.put(address, vft);
432-
storeVft(owner, address, vft); // temp solution?
478+
storeVft(owner, vft); // temp solution?
433479
break;
434480

435481
default:
@@ -438,22 +484,49 @@ public boolean createVirtualTable(CategoryPath categoryPath, String mangled, Add
438484
return true;
439485
}
440486

441-
private void storeVbt(ClassID owner, Address address, VirtualBaseTable vbt) {
442-
TreeMap<Address, VirtualBaseTable> map = vbtsByOwner.get(owner);
443-
if (map == null) {
444-
map = new TreeMap<>();
445-
vbtsByOwner.put(owner, map);
487+
private void storeVbt(ClassID owner, VirtualBaseTable vbt) {
488+
ClassID own = vbt.getOwner();
489+
List<VirtualBaseTable> list = vbtsByOwner.get(own);
490+
if (list == null) {
491+
list = new ArrayList<>();
492+
vbtsByOwner.put(owner, list);
493+
}
494+
List<ClassID> parentage = vbt.getParentage();
495+
for (VirtualBaseTable table : list) {
496+
if (isEqual(table.getParentage(), parentage)) {
497+
return; // return without saving
498+
}
499+
}
500+
list.add(vbt);
501+
}
502+
503+
private void storeVft(ClassID owner, VirtualFunctionTable vft) {
504+
List<VirtualFunctionTable> list = vftsByOwner.get(owner);
505+
if (list == null) {
506+
list = new ArrayList<>();
507+
vftsByOwner.put(owner, list);
508+
}
509+
List<ClassID> parentage = vft.getParentage();
510+
for (VirtualFunctionTable table : list) {
511+
if (isEqual(table.getParentage(), parentage)) {
512+
return; // return without saving
513+
}
446514
}
447-
map.put(address, vbt);
515+
list.add(vft);
448516
}
449517

450-
private void storeVft(ClassID owner, Address address, VirtualFunctionTable vft) {
451-
TreeMap<Address, VirtualFunctionTable> map = vftsByOwner.get(owner);
452-
if (map == null) {
453-
map = new TreeMap<>();
454-
vftsByOwner.put(owner, map);
518+
private boolean isEqual(List<ClassID> parentage1, List<ClassID> parentage2) {
519+
int diff = parentage1.size() - parentage2.size();
520+
if (diff != 0) {
521+
return false;
522+
}
523+
Iterator<ClassID> iter2 = parentage2.iterator();
524+
for (ClassID element : parentage1) {
525+
if (!element.equals(iter2.next())) {
526+
return false;
527+
}
455528
}
456-
map.put(address, vft);
529+
return true;
457530
}
458531

459532
private ParentageNode findNode(ClassID owner, List<ClassID> parentage, ParentageNode root) {

Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,19 +1231,25 @@ private void findDirectBaseVxtPtrs(VxtManager vxtManager) {
12311231
// Note that if the parent has already had its layout done, it will not have
12321232
// used the vxtManager that we are passing in here; it will have used whatever
12331233
// was passed to the layout method for that class
1234-
for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVfts()) {
1235-
VxtPtrInfo newInfo =
1236-
createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset);
1237-
updateVft(vxtManager, baseId, newInfo, parentInfo);
1238-
storeVxtInfo(propagatedSelfBaseVfts, finalVftPtrInfoByOffset, vftTableIdByOffset,
1239-
vftOffsetByTableId, newInfo);
1234+
if (cppBaseType.getPropagatedSelfBaseVfts() != null) {
1235+
for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVfts()) {
1236+
VxtPtrInfo newInfo =
1237+
createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset);
1238+
updateVft(vxtManager, baseId, newInfo, parentInfo);
1239+
storeVxtInfo(propagatedSelfBaseVfts, finalVftPtrInfoByOffset,
1240+
vftTableIdByOffset,
1241+
vftOffsetByTableId, newInfo);
1242+
}
12401243
}
1241-
for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVbts()) {
1242-
VxtPtrInfo newInfo =
1243-
createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset);
1244-
updateVbt(vxtManager, baseId, newInfo, parentInfo);
1245-
storeVxtInfo(propagatedSelfBaseVbts, finalVbtPtrInfoByOffset, vbtTableIdByOffset,
1246-
vbtOffsetByTableId, newInfo);
1244+
if (cppBaseType.getPropagatedSelfBaseVbts() != null) {
1245+
for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVbts()) {
1246+
VxtPtrInfo newInfo =
1247+
createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset);
1248+
updateVbt(vxtManager, baseId, newInfo, parentInfo);
1249+
storeVxtInfo(propagatedSelfBaseVbts, finalVbtPtrInfoByOffset,
1250+
vbtTableIdByOffset,
1251+
vbtOffsetByTableId, newInfo);
1252+
}
12471253
}
12481254
}
12491255
}
@@ -1253,8 +1259,9 @@ private void findDirectBaseVxtPtrs(VxtManager vxtManager) {
12531259
* virtual bases. Gathers results from the accumulation of all "direct" virtual base classes;
12541260
* we are not relying on the "indirect" virtual base class information from the PDB. This
12551261
* is done this way so that we can collect parentage information for the pointers.
1262+
* @throws PdbException upon issue finding base offset
12561263
*/
1257-
private void findVirtualBaseVxtPtrs(MsftVxtManager vxtManager) {
1264+
private void findVirtualBaseVxtPtrs(MsftVxtManager vxtManager) throws PdbException {
12581265
// Walk direct bases to find vxts of virtual bases. TODO: also notate all rolled up
12591266
// virtuals for each direct base.
12601267
for (DirectLayoutBaseClass base : directLayoutBaseClasses) {
@@ -1396,10 +1403,16 @@ private VxtPtrInfo createVirtualOwnedSelfVxtPtrInfo(VxtPtrInfo baseInfo, ClassID
13961403
* Converts VxtPtrInfo from virtual-based-owned direct or indirect virtual base for this class
13971404
* @param baseInfo the vxt info from the base
13981405
* @return the new VxtPtrInfo for this class
1406+
* @throws PdbException upon issue getting base offset
13991407
*/
1400-
private VxtPtrInfo createVirtualOwnedVirtualVxtPtrInfo(VxtPtrInfo baseInfo) {
1408+
private VxtPtrInfo createVirtualOwnedVirtualVxtPtrInfo(VxtPtrInfo baseInfo)
1409+
throws PdbException {
14011410
Long accumOffset = baseInfo.accumOffset();
1402-
Long finalOffset = accumOffset + baseOffsetById.get(baseInfo.baseId());
1411+
Long baseOffset = baseOffsetById.get(baseInfo.baseId());
1412+
if (baseOffset == null) {
1413+
throw new PdbException("Cannot find base offset");
1414+
}
1415+
Long finalOffset = accumOffset + baseOffset;
14031416
return new VxtPtrInfo(finalOffset, accumOffset, baseInfo.baseId(),
14041417
updateParentage(baseInfo));
14051418
}
@@ -1440,20 +1453,10 @@ private void findOrAllocateMainVftPtr(MsftVxtManager vxtManager) {
14401453
myVftPtrOffset = vftPtrTypeByOffset.firstKey();
14411454
VxtPtrInfo info =
14421455
new VxtPtrInfo(myVftPtrOffset, myVftPtrOffset, myId, List.of(myId));
1443-
VirtualFunctionTable myVft =
1444-
vxtManager.findVft(myId, List.of(myId));
1445-
if (myVft != null) {
1446-
myVft.setPtrOffsetInClass(info.finalOffset());
1447-
propagatedSelfBaseVfts.add(info);
1448-
finalVftByOffset.put(info.finalOffset(), myVft);
1449-
}
1450-
else {
1451-
PlaceholderVirtualFunctionTable t = new PlaceholderVirtualFunctionTable(
1452-
myId, List.of(myId));
1453-
t.setPtrOffsetInClass(info.finalOffset());
1454-
propagatedSelfBaseVfts.add(info);
1455-
finalVftByOffset.put(info.finalOffset(), t);
1456-
}
1456+
VirtualFunctionTable myVft = vxtManager.findVft(myId, info.parentage());
1457+
myVft.setPtrOffsetInClass(info.finalOffset());
1458+
propagatedSelfBaseVfts.add(info);
1459+
finalVftByOffset.put(info.finalOffset(), myVft);
14571460
finalVftPtrInfoByOffset.put(info.accumOffset(), info);
14581461
OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage());
14591462
vftTableIdByOffset.put(info.accumOffset(), op);
@@ -1473,8 +1476,8 @@ private void findOrAllocateMainVftPtr(MsftVxtManager vxtManager) {
14731476
* structure
14741477
*/
14751478
private void findOrAllocateMainVbtPtr(MsftVxtManager vxtManager) {
1476-
if (propagatedSelfBaseVbts.isEmpty()) {
1477-
if (!virtualLayoutBaseClasses.isEmpty()) {
1479+
if (propagatedSelfBaseVbts.isEmpty()) { // a pointer might be available in a direct base
1480+
if (!virtualLayoutBaseClasses.isEmpty()) { // there is a need for a main vbtptr
14781481
TreeSet<Long> vbtOffsets = new TreeSet<>();
14791482
for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) {
14801483
vbtOffsets.add((long) base.getBasePointerOffset());
@@ -1487,12 +1490,10 @@ private void findOrAllocateMainVbtPtr(MsftVxtManager vxtManager) {
14871490
Msg.warn(this, "Mismatch vbt location for " + myId);
14881491
}
14891492
VxtPtrInfo info = new VxtPtrInfo(vbtPtrOffset, vbtPtrOffset, myId, List.of(myId));
1490-
VirtualBaseTable myVbt = vxtManager.findVbt(myId, List.of(myId));
1491-
if (myVbt != null) {
1492-
myVbt.setPtrOffsetInClass(info.finalOffset());
1493-
propagatedSelfBaseVbts.add(info);
1494-
finalVbtByOffset.put(info.finalOffset(), myVbt);
1495-
}
1493+
VirtualBaseTable myVbt = vxtManager.findVbt(myId, info.parentage());
1494+
myVbt.setPtrOffsetInClass(info.finalOffset());
1495+
propagatedSelfBaseVbts.add(info);
1496+
finalVbtByOffset.put(info.finalOffset(), myVbt);
14961497
finalVbtPtrInfoByOffset.put(info.accumOffset(), info);
14971498
OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage());
14981499
vbtTableIdByOffset.put(info.accumOffset(), op);
@@ -1699,7 +1700,7 @@ private VirtualBaseTable updateVbt(VxtManager vxtManager, ClassID baseId, VxtPtr
16991700
private VirtualFunctionTable getMainVft(MsftVxtManager vxtManager) throws PdbException {
17001701
if (!finalVftPtrInfoByOffset.isEmpty()) {
17011702
VxtPtrInfo firstVftPtrInfo = finalVftPtrInfoByOffset.firstEntry().getValue();
1702-
VirtualFunctionTable vft = vxtManager.findVft(myId, firstVftPtrInfo.parentage());
1703+
VirtualFunctionTable vft = vxtManager.findPrimaryVft(myId, firstVftPtrInfo.parentage());
17031704
return vft;
17041705
// Following is for consideration for testing without a program:
17051706
// if (vft instanceof ProgramVirtualFunctionTable pvft) {
@@ -1723,7 +1724,7 @@ private VirtualFunctionTable getMainVft(MsftVxtManager vxtManager) throws PdbExc
17231724
private VirtualBaseTable getMainVbt(MsftVxtManager vxtManager) throws PdbException {
17241725
if (!finalVbtPtrInfoByOffset.isEmpty()) {
17251726
VxtPtrInfo firstVbtPtrInfo = finalVbtPtrInfoByOffset.firstEntry().getValue();
1726-
VirtualBaseTable vbt = vxtManager.findVbt(myId, firstVbtPtrInfo.parentage());
1727+
VirtualBaseTable vbt = vxtManager.findPrimaryVbt(myId, firstVbtPtrInfo.parentage());
17271728
if (vbt instanceof ProgramVirtualBaseTable pvbt) {
17281729
return pvbt;
17291730
}
@@ -1747,8 +1748,10 @@ else if (vbt instanceof PlaceholderVirtualBaseTable plvbt) {
17471748
return plvbt;
17481749
}
17491750
else {
1750-
throw new PdbException(
1751-
"VBT type not expected: " + vbt.getClass().getSimpleName());
1751+
if (vbt != null) {
1752+
throw new PdbException(
1753+
"VBT type not expected: " + vbt.getClass().getSimpleName());
1754+
}
17521755
}
17531756
}
17541757
return null;

0 commit comments

Comments
 (0)