mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-5074 - CPP PDB vxtable datatype composition
This commit is contained in:
parent
ce6bef1e12
commit
edb277177d
27 changed files with 1545 additions and 533 deletions
|
@ -58,6 +58,8 @@ public class ClassFieldAttributes {
|
||||||
};
|
};
|
||||||
Property myProperty = switch (msAtts.getProperty()) {
|
Property myProperty = switch (msAtts.getProperty()) {
|
||||||
case VIRTUAL -> Property.VIRTUAL;
|
case VIRTUAL -> Property.VIRTUAL;
|
||||||
|
case INTRO -> Property.VIRTUAL; // VIRTUAL for now; consider change, consider ELF
|
||||||
|
case INTRO_PURE -> Property.VIRTUAL; // VIRTUAL for now; consider change, consider ELF
|
||||||
case STATIC -> Property.STATIC;
|
case STATIC -> Property.STATIC;
|
||||||
case FRIEND -> Property.FRIEND;
|
case FRIEND -> Property.FRIEND;
|
||||||
case BLANK -> Property.BLANK;
|
case BLANK -> Property.BLANK;
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
import ghidra.app.util.SymbolPath;
|
import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Type Manager
|
* Class Type Manager
|
||||||
|
@ -44,10 +45,7 @@ public class ClassTypeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SymbolPath getSymbolPath(ClassID classId) {
|
public SymbolPath getSymbolPath(ClassID classId) {
|
||||||
if (classId instanceof ProgramClassID gId) {
|
return classId.getSymbolPath();
|
||||||
return gId.getSymbolPath();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,6 +25,9 @@ import ghidra.app.util.demangler.microsoft.MicrosoftMangledContext;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.CategoryPath;
|
import ghidra.program.model.data.CategoryPath;
|
||||||
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
import ghidra.program.model.gclass.ClassUtils;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
@ -121,8 +124,8 @@ public class MsftVxtManager extends VxtManager {
|
||||||
// memory are the same order that their pointers appear in the classes... this is based solely
|
// 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
|
// 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
|
// of using the parentage. We will try to use the parentage as a litmus test on retrieval
|
||||||
private Map<ClassID, TreeMap<Address, VBTable>> vbtsByOwner;
|
private Map<ClassID, TreeMap<Address, VirtualBaseTable>> vbtsByOwner;
|
||||||
private Map<ClassID, TreeMap<Address, VFTable>> vftsByOwner;
|
private Map<ClassID, TreeMap<Address, VirtualFunctionTable>> vftsByOwner;
|
||||||
|
|
||||||
// Used for locating vft and vbt
|
// Used for locating vft and vbt
|
||||||
// These are explicitly used for storing/retrieving the "program" versions which result from
|
// These are explicitly used for storing/retrieving the "program" versions which result from
|
||||||
|
@ -131,6 +134,9 @@ public class MsftVxtManager extends VxtManager {
|
||||||
private ParentageNode vbtRoot;
|
private ParentageNode vbtRoot;
|
||||||
private ParentageNode vftRoot;
|
private ParentageNode vftRoot;
|
||||||
|
|
||||||
|
private Map<OwnerParentage, VirtualBaseTable> vbtsByOwnerParentage;
|
||||||
|
private Map<OwnerParentage, VirtualFunctionTable> vftsByOwnerParentage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for this class
|
* Constructor for this class
|
||||||
* @param ctm the class type manager
|
* @param ctm the class type manager
|
||||||
|
@ -145,15 +151,32 @@ public class MsftVxtManager extends VxtManager {
|
||||||
vftsByOwner = new HashMap<>();
|
vftsByOwner = new HashMap<>();
|
||||||
vbtRoot = new ParentageNode(null);
|
vbtRoot = new ParentageNode(null);
|
||||||
vftRoot = new ParentageNode(null);
|
vftRoot = new ParentageNode(null);
|
||||||
|
vbtsByOwnerParentage = new HashMap<>();
|
||||||
|
vftsByOwnerParentage = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the putative {@link VBTable} in memory requested for the owning class
|
* Create the vxtable structures
|
||||||
|
* @param dtm the data type manager
|
||||||
|
*/
|
||||||
|
public void doTableLayouts(DataTypeManager dtm) {
|
||||||
|
for (VirtualBaseTable vbt : vbtsByOwnerParentage.values()) {
|
||||||
|
ClassID id = vbt.getOwner();
|
||||||
|
vbt.getLayout(dtm, ClassUtils.getClassInternalsPath(id));
|
||||||
|
}
|
||||||
|
for (VirtualFunctionTable vft : vftsByOwnerParentage.values()) {
|
||||||
|
ClassID id = vft.getOwner();
|
||||||
|
vft.getLayout(dtm, ClassUtils.getClassInternalsPath(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the putative {@link VirtualBaseTable} in memory requested for the owning class
|
||||||
* @param owner the owning class of the table
|
* @param owner the owning class of the table
|
||||||
* @return the table
|
* @return the table
|
||||||
*/
|
*/
|
||||||
public VBTable findPrimaryVbt(ClassID owner) {
|
public VirtualBaseTable findPrimaryVbt(ClassID owner) {
|
||||||
TreeMap<Address, VBTable> map = vbtsByOwner.get(owner);
|
TreeMap<Address, VirtualBaseTable> map = vbtsByOwner.get(owner);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -161,12 +184,12 @@ public class MsftVxtManager extends VxtManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the putative {@link VFTable} in memory requested for the owning class
|
* Finds the putative {@link VirtualFunctionTable} in memory requested for the owning class
|
||||||
* @param owner the owning class of the table
|
* @param owner the owning class of the table
|
||||||
* @return the table
|
* @return the table
|
||||||
*/
|
*/
|
||||||
public VFTable findPrimaryVft(ClassID owner) {
|
public VirtualFunctionTable findPrimaryVft(ClassID owner) {
|
||||||
TreeMap<Address, VFTable> map = vftsByOwner.get(owner);
|
TreeMap<Address, VirtualFunctionTable> map = vftsByOwner.get(owner);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -194,35 +217,35 @@ public class MsftVxtManager extends VxtManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ordered in-memory {@link VBTable}s for the owning class
|
* Returns the ordered in-memory {@link VirtualBaseTable}s for the owning class
|
||||||
* @param owner the owning class of the table
|
* @param owner the owning class of the table
|
||||||
* @return the tables
|
* @return the tables
|
||||||
*/
|
*/
|
||||||
public VBTable[] getVbts(ClassID owner) {
|
public VirtualBaseTable[] getVbts(ClassID owner) {
|
||||||
TreeMap<Address, VBTable> map = vbtsByOwner.get(owner);
|
TreeMap<Address, VirtualBaseTable> map = vbtsByOwner.get(owner);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Collection<VBTable> values = map.values();
|
Collection<VirtualBaseTable> values = map.values();
|
||||||
return values.toArray(new VBTable[values.size()]);
|
return values.toArray(new VirtualBaseTable[values.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ordered in-memory {@link VFTable}s for the owning class
|
* Returns the ordered in-memory {@link VirtualFunctionTable}s for the owning class
|
||||||
* @param owner the owning class of the table
|
* @param owner the owning class of the table
|
||||||
* @return the tables
|
* @return the tables
|
||||||
*/
|
*/
|
||||||
public VFTable[] getVfts(ClassID owner) {
|
public VirtualFunctionTable[] getVfts(ClassID owner) {
|
||||||
TreeMap<Address, VFTable> map = vftsByOwner.get(owner);
|
TreeMap<Address, VirtualFunctionTable> map = vftsByOwner.get(owner);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Collection<VFTable> values = map.values();
|
Collection<VirtualFunctionTable> values = map.values();
|
||||||
return values.toArray(new VFTable[values.size()]);
|
return values.toArray(new VirtualFunctionTable[values.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the putative {@link VBTable} in memory requested for the owning class and the
|
* Finds the putative {@link VirtualBaseTable} in memory requested for the owning class and the
|
||||||
* specified parentage
|
* specified parentage
|
||||||
* @param owner the owning class of the table
|
* @param owner the owning class of the table
|
||||||
* @param parentage the parentage for the desired table. The parentage must start with the
|
* @param parentage the parentage for the desired table. The parentage must start with the
|
||||||
|
@ -230,12 +253,26 @@ public class MsftVxtManager extends VxtManager {
|
||||||
* that class through all of its decendents to the owner, excluding the owner
|
* that class through all of its decendents to the owner, excluding the owner
|
||||||
* @return the table
|
* @return the table
|
||||||
*/
|
*/
|
||||||
public VBTable findVbt(ClassID owner, List<ClassID> parentage) {
|
public VirtualBaseTable findVbt(ClassID owner, List<ClassID> parentage) {
|
||||||
|
OwnerParentage op = new OwnerParentage(owner, parentage);
|
||||||
|
VirtualBaseTable vbt = vbtsByOwnerParentage.get(op);
|
||||||
|
if (vbt != null) {
|
||||||
|
return vbt;
|
||||||
|
}
|
||||||
|
vbt = searchVbtTree(owner, parentage);
|
||||||
|
if (vbt == null) {
|
||||||
|
vbt = new PlaceholderVirtualBaseTable(owner, parentage);
|
||||||
|
}
|
||||||
|
vbtsByOwnerParentage.put(op, vbt);
|
||||||
|
return vbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private VirtualBaseTable searchVbtTree(ClassID owner, List<ClassID> parentage) {
|
||||||
ParentageNode node = findNode(owner, parentage, vbtRoot);
|
ParentageNode node = findNode(owner, parentage, vbtRoot);
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
VBTable vbTable = node.getVBTable();
|
VirtualBaseTable vbTable = node.getVBTable();
|
||||||
if (vbTable != null || !parentage.isEmpty()) { // see note below
|
if (vbTable != null || !parentage.isEmpty()) { // see note below
|
||||||
return vbTable;
|
return vbTable;
|
||||||
}
|
}
|
||||||
|
@ -253,20 +290,35 @@ public class MsftVxtManager extends VxtManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the putative {@link VFTable} in memory requested for the owning class and the
|
* Finds the putative {@link VirtualFunctionTable} in memory requested for the owning class
|
||||||
* specified parentage
|
* and the specified parentage
|
||||||
* @param owner the owning class of the table
|
* @param owner the owning class of the table
|
||||||
* @param parentage the parentage for the desired table. The parentage must start with the
|
* @param parentage the parentage for the desired table. The parentage must start with the
|
||||||
* parent that contains the pointer to the table and should include the ordered lineage from
|
* parent that contains the pointer to the table and should include the ordered lineage from
|
||||||
* that class through all of its decendents to the owner, excluding the owner
|
* that class through all of its decendents to the owner, excluding the owner
|
||||||
* @return the table
|
* @return the table
|
||||||
*/
|
*/
|
||||||
public VFTable findVft(ClassID owner, List<ClassID> parentage) {
|
public VirtualFunctionTable findVft(ClassID owner, List<ClassID> parentage) {
|
||||||
|
OwnerParentage op = new OwnerParentage(owner, parentage);
|
||||||
|
VirtualFunctionTable vft = vftsByOwnerParentage.get(op);
|
||||||
|
if (vft != null) {
|
||||||
|
return vft;
|
||||||
|
}
|
||||||
|
vft = searchVftTree(owner, parentage);
|
||||||
|
if (vft == null) {
|
||||||
|
vft = new PlaceholderVirtualFunctionTable(owner, parentage);
|
||||||
|
}
|
||||||
|
vftsByOwnerParentage.put(op, vft);
|
||||||
|
return vft;
|
||||||
|
}
|
||||||
|
|
||||||
|
private VirtualFunctionTable searchVftTree(ClassID owner, List<ClassID> parentage) {
|
||||||
|
|
||||||
ParentageNode node = findNode(owner, parentage, vftRoot);
|
ParentageNode node = findNode(owner, parentage, vftRoot);
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
VFTable vfTable = node.getVFTable();
|
VirtualFunctionTable vfTable = node.getVFTable();
|
||||||
if (vfTable != null || !parentage.isEmpty()) { // see note below
|
if (vfTable != null || !parentage.isEmpty()) { // see note below
|
||||||
return vfTable;
|
return vfTable;
|
||||||
}
|
}
|
||||||
|
@ -357,7 +409,8 @@ public class MsftVxtManager extends VxtManager {
|
||||||
switch (demanglerResults.vtType()) {
|
switch (demanglerResults.vtType()) {
|
||||||
case VBT:
|
case VBT:
|
||||||
ProgramVirtualBaseTable prvbt = new ProgramVirtualBaseTable(owner, parentage,
|
ProgramVirtualBaseTable prvbt = new ProgramVirtualBaseTable(owner, parentage,
|
||||||
program, address, ctm.getDefaultVbtTableElementSize(), ctm, mangled);
|
program, address, ClassUtils.getVbtEntrySize(ctm.getDataTypeManager()),
|
||||||
|
mangled);
|
||||||
if (node.getVBTable() != null) {
|
if (node.getVBTable() != null) {
|
||||||
Msg.warn(this, "VBT already exists at node for " + mangled);
|
Msg.warn(this, "VBT already exists at node for " + mangled);
|
||||||
return false;
|
return false;
|
||||||
|
@ -385,8 +438,8 @@ public class MsftVxtManager extends VxtManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeVbt(ClassID owner, Address address, VBTable vbt) {
|
private void storeVbt(ClassID owner, Address address, VirtualBaseTable vbt) {
|
||||||
TreeMap<Address, VBTable> map = vbtsByOwner.get(owner);
|
TreeMap<Address, VirtualBaseTable> map = vbtsByOwner.get(owner);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
map = new TreeMap<>();
|
map = new TreeMap<>();
|
||||||
vbtsByOwner.put(owner, map);
|
vbtsByOwner.put(owner, map);
|
||||||
|
@ -394,8 +447,8 @@ public class MsftVxtManager extends VxtManager {
|
||||||
map.put(address, vbt);
|
map.put(address, vbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeVft(ClassID owner, Address address, VFTable vft) {
|
private void storeVft(ClassID owner, Address address, VirtualFunctionTable vft) {
|
||||||
TreeMap<Address, VFTable> map = vftsByOwner.get(owner);
|
TreeMap<Address, VirtualFunctionTable> map = vftsByOwner.get(owner);
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
map = new TreeMap<>();
|
map = new TreeMap<>();
|
||||||
vftsByOwner.put(owner, map);
|
vftsByOwner.put(owner, map);
|
||||||
|
@ -404,10 +457,7 @@ public class MsftVxtManager extends VxtManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ParentageNode findNode(ClassID owner, List<ClassID> parentage, ParentageNode root) {
|
private ParentageNode findNode(ClassID owner, List<ClassID> parentage, ParentageNode root) {
|
||||||
if (!(owner instanceof ProgramClassID ownerGId)) {
|
SymbolPath ownerSp = owner.getSymbolPath();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
SymbolPath ownerSp = ownerGId.getSymbolPath();
|
|
||||||
ParentageNode ownerNode = root.getBranch(ownerSp.toString());
|
ParentageNode ownerNode = root.getBranch(ownerSp.toString());
|
||||||
if (ownerNode == null) {
|
if (ownerNode == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -415,10 +465,7 @@ public class MsftVxtManager extends VxtManager {
|
||||||
ParentageNode resultNode = null;
|
ParentageNode resultNode = null;
|
||||||
ParentageNode node = ownerNode;
|
ParentageNode node = ownerNode;
|
||||||
for (ClassID id : parentage) {
|
for (ClassID id : parentage) {
|
||||||
if (!(id instanceof ProgramClassID gId)) {
|
SymbolPath sp = id.getSymbolPath();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
SymbolPath sp = gId.getSymbolPath();
|
|
||||||
ParentageNode next = node.getBranch(sp.toString());
|
ParentageNode next = node.getBranch(sp.toString());
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
node = next;
|
node = next;
|
||||||
|
@ -445,19 +492,9 @@ public class MsftVxtManager extends VxtManager {
|
||||||
|
|
||||||
ClassID owner = ownerAndParentage.owner(); // owner should be same as first on list
|
ClassID owner = ownerAndParentage.owner(); // owner should be same as first on list
|
||||||
List<ClassID> parentage = ownerAndParentage.parentage();
|
List<ClassID> parentage = ownerAndParentage.parentage();
|
||||||
if (!(owner instanceof ProgramClassID)) {
|
node = node.getOrAddBranch(owner.getSymbolPath().toString());
|
||||||
Msg.error(this, "ClassID error for " + ownerAndParentage);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ProgramClassID gId = (ProgramClassID) owner;
|
|
||||||
node = node.getOrAddBranch(gId.getSymbolPath().toString());
|
|
||||||
for (ClassID id : parentage) {
|
for (ClassID id : parentage) {
|
||||||
if (!(id instanceof ProgramClassID)) {
|
node = node.getOrAddBranch(id.getSymbolPath().toString());
|
||||||
Msg.error(this, "ClassID error for " + ownerAndParentage);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
gId = (ProgramClassID) id;
|
|
||||||
node = node.getOrAddBranch(gId.getSymbolPath().toString());
|
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -511,9 +548,9 @@ public class MsftVxtManager extends VxtManager {
|
||||||
List<SymbolPath> parentageSps = getParentageSymbolPaths(vxTable.getNestedQualifications());
|
List<SymbolPath> parentageSps = getParentageSymbolPaths(vxTable.getNestedQualifications());
|
||||||
|
|
||||||
List<ClassID> parentage = new ArrayList<>();
|
List<ClassID> parentage = new ArrayList<>();
|
||||||
ClassID owner = new ProgramClassID(categoryPath, ownerSp);
|
ClassID owner = new ClassID(categoryPath, ownerSp);
|
||||||
for (SymbolPath sp : parentageSps) {
|
for (SymbolPath sp : parentageSps) {
|
||||||
ClassID user = new ProgramClassID(categoryPath, sp);
|
ClassID user = new ClassID(categoryPath, sp);
|
||||||
parentage.add(user); // owner is the parentage if parentageSps was empty
|
parentage.add(user); // owner is the parentage if parentageSps was empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,8 +597,8 @@ public class MsftVxtManager extends VxtManager {
|
||||||
private String name;
|
private String name;
|
||||||
// Might want to store more than just one VXT... could store generic, pdb, program
|
// Might want to store more than just one VXT... could store generic, pdb, program
|
||||||
// versions... could mix function and base too (one tree instead of two)?
|
// versions... could mix function and base too (one tree instead of two)?
|
||||||
private VFTable vft;
|
private VirtualFunctionTable vft;
|
||||||
private VBTable vbt;
|
private VirtualBaseTable vbt;
|
||||||
|
|
||||||
private ParentageNode(String name) {
|
private ParentageNode(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -582,19 +619,19 @@ public class MsftVxtManager extends VxtManager {
|
||||||
return branches.get(branchName);
|
return branches.get(branchName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setVFTable(VFTable vftArg) {
|
private void setVFTable(VirtualFunctionTable vftArg) {
|
||||||
vft = vftArg;
|
vft = vftArg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setVBTable(VBTable vbtArg) {
|
private void setVBTable(VirtualBaseTable vbtArg) {
|
||||||
vbt = vbtArg;
|
vbt = vbtArg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private VFTable getVFTable() {
|
private VirtualFunctionTable getVFTable() {
|
||||||
return vft;
|
return vft;
|
||||||
}
|
}
|
||||||
|
|
||||||
private VBTable getVBTable() {
|
private VirtualBaseTable getVBTable() {
|
||||||
return vbt;
|
return vbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,17 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unique ID of a ClassType. Not sure if there will be different implementation for definition
|
* Owner-Parentage combination for identifying a vxtable, its pointer, or a base class
|
||||||
* vs. compiled vs. program vs. debug. Need to come to grips with this
|
* @param owner the owning class
|
||||||
|
* @param parentage the parentage of the base class or vxtable or vxtable pointer
|
||||||
*/
|
*/
|
||||||
public interface ClassID extends Comparable<ClassID> {
|
public record OwnerParentage(ClassID owner, List<ClassID> parentage) {}
|
||||||
|
|
||||||
// For compareTo() method of classes in this hierarchy (for Comparable<ClassID>)
|
|
||||||
/**
|
|
||||||
* For internal use
|
|
||||||
* @return hash of java class in ClassID hierarchy
|
|
||||||
*/
|
|
||||||
public int getClassNameHash();
|
|
||||||
|
|
||||||
}
|
|
|
@ -15,110 +15,76 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Virtual Base Table without a program
|
* Virtual Base Table without a program
|
||||||
*/
|
*/
|
||||||
public class PlaceholderVirtualBaseTable extends VirtualBaseTable {
|
public class PlaceholderVirtualBaseTable extends VirtualBaseTable {
|
||||||
|
|
||||||
private int entrySize;
|
|
||||||
|
|
||||||
private int maxIndexSeen = -1;
|
|
||||||
private Map<Integer, VBTableEntry> entriesByIndex = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param owner the class that owns the table
|
* @param owner the class that owns the table
|
||||||
* @param parentage the parentage of the base class(es) of the table
|
* @param parentage the parentage of the base class(es) of the table
|
||||||
* @param entrySize the size of the index field for each table entry as it would be in memory
|
|
||||||
*/
|
*/
|
||||||
public PlaceholderVirtualBaseTable(ClassID owner, List<ClassID> parentage, int entrySize) {
|
public PlaceholderVirtualBaseTable(ClassID owner, List<ClassID> parentage) {
|
||||||
super(owner, parentage);
|
super(owner, parentage);
|
||||||
if (entrySize != 4 && entrySize != 8) {
|
|
||||||
throw new IllegalArgumentException("Invalid size (" + entrySize + "): must be 4 or 8.");
|
|
||||||
}
|
|
||||||
this.entrySize = entrySize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
public void setBaseClassOffsetAndId(int tableIndex, Long offset, ClassID baseId) {
|
||||||
* For the next method below... once we determine the number of virtual bases (virtual and
|
PlaceholderVirtualBaseTableEntry entry = entry(tableIndex);
|
||||||
* indirect virtual) for each class (from PDB or other), we can determine the number of
|
|
||||||
* entries in each VBT. For a VBT for the main class, the number is equal... if for some
|
|
||||||
* parentage, then the number can reflect the number of the parent.
|
|
||||||
* TODO: can VBT overlay/extend one from parent????????????????????????????????????????????
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* TBD: need to determine table size to do this. Might want to place a symbol (diff method?).
|
|
||||||
*/
|
|
||||||
void createTableDataType(int numEntries) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int getMaxIndex() {
|
|
||||||
return maxIndexSeen;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBaseClassOffsetAndId(int index, Long offset, ClassID baseId) {
|
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new VirtualBaseTableEntry(offset, baseId);
|
entry = new PlaceholderVirtualBaseTableEntry(offset, baseId);
|
||||||
entriesByIndex.put(index, entry);
|
entryByTableIndex.put(tableIndex, entry);
|
||||||
|
maxTableIndexSeen = Integer.max(maxTableIndexSeen, tableIndex);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
entry.setOffset(offset);
|
entry.setOffset(offset);
|
||||||
entry.setClassId(baseId);
|
entry.setClassId(baseId);
|
||||||
}
|
}
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBaseClassId(int index, ClassID baseId) {
|
public void setBaseOffset(int tableIndex, Long offset) {
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
PlaceholderVirtualBaseTableEntry entry = entry(tableIndex);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = new VirtualBaseTableEntry(baseId);
|
entry = new PlaceholderVirtualBaseTableEntry(offset);
|
||||||
entriesByIndex.put(index, entry);
|
entryByTableIndex.put(tableIndex, entry);
|
||||||
}
|
maxTableIndexSeen = Integer.max(maxTableIndexSeen, tableIndex);
|
||||||
else {
|
|
||||||
entry.setClassId(baseId);
|
|
||||||
}
|
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBaseOffset(int index, Long offset) {
|
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
|
||||||
if (entry == null) {
|
|
||||||
entry = new VirtualBaseTableEntry(offset);
|
|
||||||
entriesByIndex.put(index, entry);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
entry.setOffset(offset);
|
entry.setOffset(offset);
|
||||||
}
|
}
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getBaseOffset(int index) throws PdbException {
|
public PlaceholderVirtualBaseTableEntry getEntry(int tableIndex) {
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
return (PlaceholderVirtualBaseTableEntry) entryByTableIndex.get(tableIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getBaseOffset(int tableIndex) throws PdbException {
|
||||||
|
PlaceholderVirtualBaseTableEntry entry = entry(tableIndex);
|
||||||
Long offset = (entry == null) ? null : entry.getOffset();
|
Long offset = (entry == null) ? null : entry.getOffset();
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassID getBaseClassId(int index) {
|
protected PlaceholderVirtualBaseTableEntry getNewEntry(ClassID baseId) {
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
return new PlaceholderVirtualBaseTableEntry(baseId);
|
||||||
ClassID id = (entry == null) ? null : entry.getClassId();
|
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private PlaceholderVirtualBaseTableEntry entry(int tableIndex) {
|
||||||
public VBTableEntry getBase(int index) throws PdbException {
|
return (PlaceholderVirtualBaseTableEntry) entryByTableIndex.get(tableIndex);
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
}
|
||||||
if (entry != null) {
|
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
private PlaceholderVirtualBaseTableEntry existing(int tableIndex) throws PdbException {
|
||||||
|
PlaceholderVirtualBaseTableEntry entry = entry(tableIndex);
|
||||||
|
if (entry == null) {
|
||||||
|
throw new PdbException(
|
||||||
|
"No entry in Virtual Base Table for table index: " + tableIndex);
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* ###
|
||||||
|
* 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.classtype;
|
||||||
|
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the Entry for a Virtual Base Table
|
||||||
|
*/
|
||||||
|
public class PlaceholderVirtualBaseTableEntry extends VirtualBaseTableEntry {
|
||||||
|
private Long offset;
|
||||||
|
|
||||||
|
// Re-evaluate which constructors and setters we need
|
||||||
|
|
||||||
|
public PlaceholderVirtualBaseTableEntry(Long offset) {
|
||||||
|
this(offset, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaceholderVirtualBaseTableEntry(ClassID baseId) {
|
||||||
|
this(null, baseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaceholderVirtualBaseTableEntry(Long offset, ClassID baseId) {
|
||||||
|
super(baseId);
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOffset(Long offset) {
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getOffset() {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
// Info from longer-running branch
|
||||||
|
|
||||||
|
void emit(StringBuilder builder, long vbtPtrOffset) {
|
||||||
|
// emitLine(builder, offset, vbtPtrOffset,
|
||||||
|
// getClassId(compiledBaseClass, baseClassComponent).toString());
|
||||||
|
emitLine(builder, getOffset(), vbtPtrOffset, getClassId().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitHeader(StringBuilder builder, long ownerOffset, long vbtPtrOffset) {
|
||||||
|
builder.append(String.format("%-10s %-10s %-10s\n", "OffInOwner", "OffFromPtr", "Base"));
|
||||||
|
emitLine(builder, ownerOffset, vbtPtrOffset, "'ForClass'");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitLine(StringBuilder builder, long classOffset, long vbtPtrOffset, String owner) {
|
||||||
|
builder.append(
|
||||||
|
String.format("%-10d %-10d %-10s\n", classOffset, classOffset - vbtPtrOffset, owner));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.classtype;
|
||||||
|
|
||||||
|
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.data.Pointer;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
|
||||||
|
public class PlaceholderVirtualFunctionTable extends VirtualFunctionTable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* Virtual Function Table for a base (parent) class within an owner class. The owner and parent
|
||||||
|
* class can be null if not known, but methods are offered to fill them in if/when this
|
||||||
|
* information becomes available
|
||||||
|
* @param owner class that owns this VBT (can own more than one); can be {@code null}
|
||||||
|
* @param parentage parentage for which this VFT is used; can be {@code null}
|
||||||
|
*/
|
||||||
|
public PlaceholderVirtualFunctionTable(ClassID owner, List<ClassID> parentage) {
|
||||||
|
super(owner, parentage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(int tableIndex, Address address) throws PdbException {
|
||||||
|
PlaceholderVirtualFunctionTableEntry entry = existing(tableIndex);
|
||||||
|
entry.setAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address getAddress(int tableIndex) throws PdbException {
|
||||||
|
PlaceholderVirtualFunctionTableEntry entry = existing(tableIndex);
|
||||||
|
return entry.getAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VirtualFunctionTableEntry getNewEntry(SymbolPath originalMethodPath,
|
||||||
|
SymbolPath overrideMethodPath, Pointer functionPointer) {
|
||||||
|
return new PlaceholderVirtualFunctionTableEntry(originalMethodPath, overrideMethodPath,
|
||||||
|
functionPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void emit(StringBuilder builder) {
|
||||||
|
builder.append(
|
||||||
|
"Placeholder VFT for the following classes within owner:\n " + owner + "\n");
|
||||||
|
builder.append(String.format("For Classes:\n"));
|
||||||
|
for (ClassID id : parentage) {
|
||||||
|
builder.append(String.format(" %-10s\n", id.toString()));
|
||||||
|
}
|
||||||
|
builder.append("VftPtrOffset within Owner" + ptrOffsetInClass + "\n");
|
||||||
|
PlaceholderVirtualFunctionTableEntry.emitHeader(builder);
|
||||||
|
for (int tableIndex : entriesByTableIndex.keySet()) {
|
||||||
|
entry(tableIndex).emit(builder, ptrOffsetInClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
emit(builder);
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlaceholderVirtualFunctionTableEntry entry(int tableIndex) {
|
||||||
|
return (PlaceholderVirtualFunctionTableEntry) entriesByTableIndex.get(tableIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlaceholderVirtualFunctionTableEntry existing(int tableIndex) throws PdbException {
|
||||||
|
PlaceholderVirtualFunctionTableEntry entry = entry(tableIndex);
|
||||||
|
if (entry == null) {
|
||||||
|
throw new PdbException(
|
||||||
|
"No entry in Virtual Function Table for table offset: " + tableIndex);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/* ###
|
||||||
|
* 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.classtype;
|
||||||
|
|
||||||
|
import ghidra.app.util.SymbolPath;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.Pointer;
|
||||||
|
|
||||||
|
class PlaceholderVirtualFunctionTableEntry extends VirtualFunctionTableEntry {
|
||||||
|
private Address address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for placeholder virtual function table entry
|
||||||
|
* @param originalMethodPath the path of the original function
|
||||||
|
* @param overrideMethodPath the path of the overriding function
|
||||||
|
* @param functionPointer the pointer to the function definition
|
||||||
|
*/
|
||||||
|
PlaceholderVirtualFunctionTableEntry(SymbolPath originalMethodPath,
|
||||||
|
SymbolPath overrideMethodPath, Pointer functionPointer) {
|
||||||
|
this(originalMethodPath, overrideMethodPath, functionPointer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for placeholder virtual function table entry
|
||||||
|
* @param originalMethodPath the path of the original function
|
||||||
|
* @param overrideMethodPath the path of the overriding function
|
||||||
|
* @param functionPointer the pointer to the function definition
|
||||||
|
* @param address address of the function in memory; can be {@code null}
|
||||||
|
*/
|
||||||
|
PlaceholderVirtualFunctionTableEntry(SymbolPath originalMethodPath,
|
||||||
|
SymbolPath overrideMethodPath, Pointer functionPointer, Address address) {
|
||||||
|
super(originalMethodPath, overrideMethodPath, functionPointer);
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to set the address of the function in memory
|
||||||
|
* @param address the address
|
||||||
|
*/
|
||||||
|
void setAddress(Address address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the address of the function in memory, if set
|
||||||
|
* @return the address; can be {@code null}
|
||||||
|
*/
|
||||||
|
Address getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================================
|
||||||
|
// Info from longer-running branch
|
||||||
|
|
||||||
|
void emit(StringBuilder builder, long vbtPtrOffset) {
|
||||||
|
emitLine(builder, null, overrideMethodPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static void emitHeader(StringBuilder builder, long ownerOffset, long vbtPtrOffset) {
|
||||||
|
static void emitHeader(StringBuilder builder) {
|
||||||
|
builder.append(String.format("%16s %s\n", "Address", "Path"));
|
||||||
|
// TODO: see if we need something like this for PlaceholderVirtualFunctionTable
|
||||||
|
// emitLine(builder, ownerOffset, vbtPtrOffset );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitLine(StringBuilder builder, Address address, SymbolPath path) {
|
||||||
|
builder.append(String.format("%16s %10s\n",
|
||||||
|
address == null ? "<unk_addr>" : address.toString(), path.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,10 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
@ -33,12 +34,6 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable {
|
||||||
private int entrySize;
|
private int entrySize;
|
||||||
private String mangledName; // remove?
|
private String mangledName; // remove?
|
||||||
|
|
||||||
private Boolean createdFromMemory = null;
|
|
||||||
private Boolean createdFromCompiled = null;
|
|
||||||
|
|
||||||
private int maxIndexSeen = -1;
|
|
||||||
private Map<Integer, VBTableEntry> entriesByIndex = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param owner the class that owns the table
|
* @param owner the class that owns the table
|
||||||
|
@ -46,20 +41,15 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable {
|
||||||
* @param program the program
|
* @param program the program
|
||||||
* @param address the address of the table
|
* @param address the address of the table
|
||||||
* @param entrySize the size of the index field for each table entry in memory
|
* @param entrySize the size of the index field for each table entry in memory
|
||||||
* @param ctm the class type manager
|
|
||||||
* @param mangledName the mangled name of the table
|
* @param mangledName the mangled name of the table
|
||||||
*/
|
*/
|
||||||
public ProgramVirtualBaseTable(ClassID owner, List<ClassID> parentage, Program program,
|
public ProgramVirtualBaseTable(ClassID owner, List<ClassID> parentage, Program program,
|
||||||
Address address, int entrySize, ClassTypeManager ctm, String mangledName) {
|
Address address, int entrySize, String mangledName) {
|
||||||
super(owner, parentage);
|
super(owner, parentage);
|
||||||
if (entrySize != 4 && entrySize != 8) {
|
|
||||||
throw new IllegalArgumentException("Invalid size (" + entrySize + "): must be 4 or 8.");
|
|
||||||
}
|
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.entrySize = entrySize;
|
this.entrySize = entrySize;
|
||||||
this.mangledName = mangledName;
|
this.mangledName = mangledName;
|
||||||
createdFromMemory = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,27 +68,25 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable {
|
||||||
return mangledName;
|
return mangledName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* For the next method below... once we determine the number of virtual bases (virtual and
|
|
||||||
* indirect virtual) for each class (from PDB or other), we can determine the number of
|
|
||||||
* entries in each VBT. For a VBT for the main class, the number is equal... if for some
|
|
||||||
* parentage, then the number can reflect the number of the parent. TODO: can VBT overlay/extend one from parent????????????????????????????????????????????
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* TBD: need to determine table size to do this. Might want to place a symbol (diff method?).
|
|
||||||
*/
|
|
||||||
void placeTableDataType(int numEntries) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int getMaxIndex() {
|
|
||||||
return maxIndexSeen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getBaseOffset(int index) throws PdbException {
|
public Long getBaseOffset(int tableIndex) throws PdbException {
|
||||||
|
Long offset = baseOffsetByTableIndex.get(tableIndex);
|
||||||
|
if (offset != null) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
offset = getOffsetFromMemory(tableIndex);
|
||||||
|
if (offset != null) {
|
||||||
|
baseOffsetByTableIndex.put(tableIndex, offset);
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getOffsetFromMemory(int tableIndex) throws PdbException {
|
||||||
|
if (program == null || address == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Memory memory = program.getMemory();
|
Memory memory = program.getMemory();
|
||||||
Address entryAddress = address.add(index * entrySize);
|
Address entryAddress = address.add(tableIndex * entrySize);
|
||||||
try {
|
try {
|
||||||
Long offset = (entrySize == 4) ? (long) memory.getInt(entryAddress)
|
Long offset = (entrySize == 4) ? (long) memory.getInt(entryAddress)
|
||||||
: memory.getLong(entryAddress);
|
: memory.getLong(entryAddress);
|
||||||
|
@ -110,40 +98,31 @@ public class ProgramVirtualBaseTable extends VirtualBaseTable {
|
||||||
entryAddress);
|
entryAddress);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
maxTableIndexSeen = Integer.max(maxTableIndexSeen, tableIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassID getBaseClassId(int index) throws PdbException {
|
protected VirtualBaseTableEntry getNewEntry(ClassID baseId) {
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
return new VirtualBaseTableEntry(baseId);
|
||||||
if (entry == null) {
|
|
||||||
throw new PdbException("No entry in Virtual Base Table for index: " + index);
|
|
||||||
}
|
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
|
||||||
return entry.getClassId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public VBTableEntry getBase(int index) throws PdbException {
|
* Returns the entry for the table index; the table index is based at 1
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
* @param tableIndex the index location in the table
|
||||||
|
* @return the entry
|
||||||
|
*/
|
||||||
|
private VirtualBaseTableEntry entry(int tableIndex) {
|
||||||
|
return entryByTableIndex.get(tableIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VirtualBaseTableEntry existing(int tableIndex) throws PdbException {
|
||||||
|
VirtualBaseTableEntry entry = entry(tableIndex);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new PdbException("No entry in Virtual Base Table for index: " + index);
|
throw new PdbException(
|
||||||
|
"No entry in Virtual Base Table for table offset: " + tableIndex);
|
||||||
}
|
}
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBaseClassId(int index, ClassID baseId) {
|
|
||||||
VBTableEntry entry = entriesByIndex.get(index);
|
|
||||||
if (entry == null) {
|
|
||||||
entry = new VirtualBaseTableEntry(baseId);
|
|
||||||
entriesByIndex.put(index, entry);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
entry.setClassId(baseId);
|
|
||||||
}
|
|
||||||
maxIndexSeen = Integer.max(maxIndexSeen, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,13 @@
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import ghidra.app.util.SymbolPath;
|
import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.Pointer;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
@ -54,6 +57,7 @@ public class ProgramVirtualFunctionTable extends VirtualFunctionTable {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.defaultEntrySize = defaultEntrySize;
|
this.defaultEntrySize = defaultEntrySize;
|
||||||
this.mangledName = mangledName;
|
this.mangledName = mangledName;
|
||||||
|
entriesByTableIndex = new TreeMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,6 +76,13 @@ public class ProgramVirtualFunctionTable extends VirtualFunctionTable {
|
||||||
return mangledName;
|
return mangledName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VirtualFunctionTableEntry getNewEntry(SymbolPath originalMethodPath,
|
||||||
|
SymbolPath overrideMethodPath, Pointer functionPointer) {
|
||||||
|
return new VirtualFunctionTableEntry(originalMethodPath, overrideMethodPath,
|
||||||
|
functionPointer);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress(int ordinal) throws PdbException {
|
public Address getAddress(int ordinal) throws PdbException {
|
||||||
Memory memory = program.getMemory();
|
Memory memory = program.getMemory();
|
||||||
|
@ -91,11 +102,19 @@ public class ProgramVirtualFunctionTable extends VirtualFunctionTable {
|
||||||
"MemoryAccessException while trying to parse virtual function table entry at address: " +
|
"MemoryAccessException while trying to parse virtual function table entry at address: " +
|
||||||
entryAddress);
|
entryAddress);
|
||||||
}
|
}
|
||||||
//throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private VirtualFunctionTableEntry entry(int tableIndex) {
|
||||||
public SymbolPath getPath(int index) throws PdbException {
|
return (VirtualFunctionTableEntry) entriesByTableIndex.get(tableIndex);
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private VirtualFunctionTableEntry existing(int tableIndex) throws PdbException {
|
||||||
|
VirtualFunctionTableEntry entry = entry(tableIndex);
|
||||||
|
if (entry == null) {
|
||||||
|
throw new PdbException(
|
||||||
|
"No entry in Virtual Function Table for table offset: " + tableIndex);
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,6 @@ package ghidra.app.util.pdb.classtype;
|
||||||
/**
|
/**
|
||||||
* Compiler-generated virtual base table
|
* Compiler-generated virtual base table
|
||||||
*/
|
*/
|
||||||
public interface VBTable {
|
public interface VBTable extends VXT {
|
||||||
// empty for now
|
// empty for now
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,22 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an entry within a virtual base table
|
* Represents an entry within a virtual base table
|
||||||
*/
|
*/
|
||||||
public interface VBTableEntry {
|
public interface VBTableEntry extends VXTEntry {
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the entry offset value
|
|
||||||
* @param offset the offset
|
|
||||||
*/
|
|
||||||
public void setOffset(Long offset);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the entry offset value
|
|
||||||
* @return the offset value
|
|
||||||
*/
|
|
||||||
public Long getOffset();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the entry class ID
|
* Sets the entry class ID
|
||||||
|
|
|
@ -18,6 +18,6 @@ package ghidra.app.util.pdb.classtype;
|
||||||
/**
|
/**
|
||||||
* Compiler-generated virtual function table
|
* Compiler-generated virtual function table
|
||||||
*/
|
*/
|
||||||
public interface VFTable {
|
public interface VFTable extends VXT {
|
||||||
// empty for now
|
// empty for now
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* ###
|
||||||
|
* 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.classtype;
|
||||||
|
|
||||||
|
import ghidra.app.util.SymbolPath;
|
||||||
|
import ghidra.program.model.data.Pointer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an entry within a virtual function table
|
||||||
|
*/
|
||||||
|
public interface VFTableEntry extends VXTEntry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the original path of the function
|
||||||
|
* @param path the symbol path
|
||||||
|
*/
|
||||||
|
public void setOriginalPath(SymbolPath path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the original path of the function
|
||||||
|
* @return the symbol path
|
||||||
|
*/
|
||||||
|
public SymbolPath getOriginalPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the override path of the function
|
||||||
|
* @param path the symbol path
|
||||||
|
*/
|
||||||
|
public void setOverridePath(SymbolPath path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the override path of the function
|
||||||
|
* @return the symbol path
|
||||||
|
*/
|
||||||
|
public SymbolPath getOverridePath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the pointer to the function definition type
|
||||||
|
* @param pointer the pointer to the funciton definition type
|
||||||
|
*/
|
||||||
|
public void setFunctionPointer(Pointer pointer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pointer to the function definition type
|
||||||
|
* @return the pointer to the function definition type
|
||||||
|
*/
|
||||||
|
public Pointer getFunctionPointer();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* ###
|
||||||
|
* 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.classtype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiler-generated virtual "something" table -- generic v-anything-table from any toolchain
|
||||||
|
*/
|
||||||
|
public interface VXT {
|
||||||
|
// empty for now
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* ###
|
||||||
|
* 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.classtype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiler-generated virtual "something" table entry -- generic v-anything-table entry
|
||||||
|
*/
|
||||||
|
public interface VXTEntry {
|
||||||
|
// empty for now
|
||||||
|
}
|
|
@ -15,10 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
import ghidra.program.model.gclass.ClassUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class for virtual base tables
|
* Abstract class for virtual base tables
|
||||||
|
@ -28,15 +30,23 @@ public abstract class VirtualBaseTable implements VBTable {
|
||||||
protected ClassID owner; // Does this belong here in this abstract class?
|
protected ClassID owner; // Does this belong here in this abstract class?
|
||||||
protected List<ClassID> parentage; // Not sure this belongs in this abstract class
|
protected List<ClassID> parentage; // Not sure this belongs in this abstract class
|
||||||
/**
|
/**
|
||||||
* The number of entries in the table
|
* The number of entries in the table, as specified by the user
|
||||||
*/
|
*/
|
||||||
protected Integer numEntries;
|
protected Integer userSpecifiedNumEntries;
|
||||||
/**
|
/**
|
||||||
* This is the offset within the class where we expect to find the pointer that can point to
|
* This is the offset within the class where we expect to find the pointer that can point to
|
||||||
* this table
|
* this table
|
||||||
*/
|
*/
|
||||||
protected Long ptrOffsetInClass;
|
protected Long ptrOffsetInClass;
|
||||||
|
|
||||||
|
protected int maxTableIndexSeen;
|
||||||
|
protected Map<Integer, VirtualBaseTableEntry> entryByTableIndex;
|
||||||
|
protected Map<Integer, Long> baseOffsetByTableIndex;
|
||||||
|
|
||||||
|
// result of compile/build
|
||||||
|
private Structure tableStructure;
|
||||||
|
private boolean isBuilt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Virtual Base Table for a base (parent) class within an owner class. The owner and parent
|
* Virtual Base Table for a base (parent) class within an owner class. The owner and parent
|
||||||
* class can be null if not known, but methods are offered to fill them in if/when this
|
* class can be null if not known, but methods are offered to fill them in if/when this
|
||||||
|
@ -47,35 +57,82 @@ public abstract class VirtualBaseTable implements VBTable {
|
||||||
public VirtualBaseTable(ClassID owner, List<ClassID> parentage) {
|
public VirtualBaseTable(ClassID owner, List<ClassID> parentage) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.parentage = new ArrayList<>(parentage);
|
this.parentage = new ArrayList<>(parentage);
|
||||||
|
maxTableIndexSeen = -1;
|
||||||
|
entryByTableIndex = new HashMap<>();
|
||||||
|
baseOffsetByTableIndex = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract VirtualBaseTableEntry getNewEntry(ClassID baseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to add an entry to the virtual base table
|
||||||
|
* @param tableIndex the index location in the virtual base table for the entry
|
||||||
|
* @param baseId class id of the base
|
||||||
|
*/
|
||||||
|
public void addEntry(int tableIndex, ClassID baseId) {
|
||||||
|
VirtualBaseTableEntry entry = getNewEntry(baseId);
|
||||||
|
entryByTableIndex.put(tableIndex, entry);
|
||||||
|
maxTableIndexSeen = Integer.max(maxTableIndexSeen, tableIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMaxTableIndex() {
|
||||||
|
return maxTableIndexSeen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, VirtualBaseTableEntry> getEntriesByTableIndex() {
|
||||||
|
return entryByTableIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base class entry for the table tableIndex
|
||||||
|
* @param tableIndex the index location in the virtual base table for the entry
|
||||||
|
* @return the entry for the base class
|
||||||
|
*/
|
||||||
|
public VBTableEntry getEntry(int tableIndex) {
|
||||||
|
return entryByTableIndex.get(tableIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset of the base class in the layout class pertaining whose entry in the
|
* Returns the offset of the base class in the layout class pertaining whose entry in the
|
||||||
* VBTable is at the index location
|
* VBTable is at the tableIndex location
|
||||||
* VBTable
|
* @param tableIndex the index location in the virtual base table for the entry
|
||||||
* @param index the index in the table
|
|
||||||
* @return the offset in the layout class
|
* @return the offset in the layout class
|
||||||
* @throws PdbException if problem retrieving the offset value
|
* @throws PdbException if problem retrieving the offset value
|
||||||
*/
|
*/
|
||||||
public abstract Long getBaseOffset(int index) throws PdbException;
|
public abstract Long getBaseOffset(int tableIndex) throws PdbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the base class id for the table index; the table index is based at 1
|
||||||
|
* @param tableIndex the index location in the table
|
||||||
|
* @param baseId the base class id
|
||||||
|
*/
|
||||||
|
public void setBaseClassId(int tableIndex, ClassID baseId) {
|
||||||
|
VirtualBaseTableEntry entry = entryByTableIndex.get(tableIndex);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = new VirtualBaseTableEntry(baseId);
|
||||||
|
entryByTableIndex.put(tableIndex, entry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entry.setClassId(baseId);
|
||||||
|
}
|
||||||
|
maxTableIndexSeen = Integer.max(maxTableIndexSeen, tableIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ClassID of the base class in the layout class pertaining whose entry in the
|
* Returns the ClassID of the base class in the layout class pertaining whose entry in the
|
||||||
* VBTable is at the index location
|
* VBTable is at the tableIndex location; the table index is based at 1
|
||||||
* @param index the index in the table
|
* @param tableIndex the index location in the virtual base table for the entry
|
||||||
* @return the ClassID of the base class
|
* @return the ClassID of the base class
|
||||||
* @throws PdbException if an entry does not exist for the index
|
* @throws PdbException if an entry does not exist for the tableIndex
|
||||||
*/
|
*/
|
||||||
public abstract ClassID getBaseClassId(int index) throws PdbException;
|
public ClassID getBaseClassId(int tableIndex) throws PdbException {
|
||||||
|
VBTableEntry entry = entryByTableIndex.get(tableIndex);
|
||||||
/**
|
if (entry == null) {
|
||||||
* Returns a {@link VBTableEntry} for the base class in the layout class pertaining whose
|
return null;
|
||||||
* entry in the VBTable is at the index location
|
}
|
||||||
* @param index the index in the table
|
maxTableIndexSeen = Integer.max(maxTableIndexSeen, tableIndex);
|
||||||
* @return the ClassID of the base class
|
return entry.getClassId();
|
||||||
* @throws PdbException if an entry does not exist for the index
|
}
|
||||||
*/
|
|
||||||
public abstract VBTableEntry getBase(int index) throws PdbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the owning class
|
* Returns the owning class
|
||||||
|
@ -95,10 +152,18 @@ public abstract class VirtualBaseTable implements VBTable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of entries in the table
|
* Returns the number of entries in the table
|
||||||
* @return the number of entries; {@code null} if not initialized
|
* @return the number of entries
|
||||||
*/
|
*/
|
||||||
public Integer getNumEntries() {
|
public int getNumEntries() {
|
||||||
return numEntries;
|
return entryByTableIndex.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of entries in the table, as specified by the user
|
||||||
|
* @return the number of entries
|
||||||
|
*/
|
||||||
|
public int getUserSpecifiedNumEntries() {
|
||||||
|
return userSpecifiedNumEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,7 +195,7 @@ public abstract class VirtualBaseTable implements VBTable {
|
||||||
* @param numEntriesArg the number of entries
|
* @param numEntriesArg the number of entries
|
||||||
*/
|
*/
|
||||||
public void setNumEntries(Integer numEntriesArg) {
|
public void setNumEntries(Integer numEntriesArg) {
|
||||||
numEntries = numEntriesArg;
|
userSpecifiedNumEntries = numEntriesArg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,4 +215,56 @@ public abstract class VirtualBaseTable implements VBTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built data type for this vftable for the current entries
|
||||||
|
* @param dtm the data type manager
|
||||||
|
* @param categoryPath category path for the table
|
||||||
|
* @return the structure of the vftable
|
||||||
|
*/
|
||||||
|
public Structure getLayout(DataTypeManager dtm, CategoryPath categoryPath) {
|
||||||
|
if (!isBuilt) { // what if we want to rebuild... what should we do?
|
||||||
|
build(dtm, categoryPath);
|
||||||
|
}
|
||||||
|
return tableStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void build(DataTypeManager dtm, CategoryPath categoryPath) {
|
||||||
|
if (ptrOffsetInClass == null || maxTableIndexSeen == -1) {
|
||||||
|
tableStructure = null;
|
||||||
|
isBuilt = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String name = ClassUtils.getSpecialVxTableName(ptrOffsetInClass);
|
||||||
|
DataType defaultEntry = ClassUtils.getVbtDefaultEntry(dtm);
|
||||||
|
// Holding onto next line for now
|
||||||
|
//int entrySize = defaultEntry.getLength();
|
||||||
|
// Note that maxTableIndexSeen comes from addEntry() and those have what seems to be
|
||||||
|
// a base 1 "index" (vs. base 0 vs. offset)
|
||||||
|
int tableNumEntries =
|
||||||
|
(userSpecifiedNumEntries != null) ? userSpecifiedNumEntries : maxTableIndexSeen;
|
||||||
|
// Holding onto next line for now
|
||||||
|
//int tableSize = tableNumEntries * entrySize;
|
||||||
|
StructureDataType dt = new StructureDataType(categoryPath, name, 0, dtm);
|
||||||
|
int masterOrdinal = 0;
|
||||||
|
for (Map.Entry<Integer, VirtualBaseTableEntry> mapEntry : entryByTableIndex.entrySet()) {
|
||||||
|
// Note that entrie's tableIndex is based at 1 instead of 0
|
||||||
|
int ordinal = mapEntry.getKey() - 1;
|
||||||
|
VBTableEntry entry = mapEntry.getValue();
|
||||||
|
while (masterOrdinal < ordinal) {
|
||||||
|
dt.add(defaultEntry, "", "");
|
||||||
|
masterOrdinal++;
|
||||||
|
}
|
||||||
|
String comment = entry.getClassId().getSymbolPath().toString();
|
||||||
|
dt.add(defaultEntry, "", comment); // we could add a comment here
|
||||||
|
masterOrdinal++;
|
||||||
|
}
|
||||||
|
while (masterOrdinal < tableNumEntries) {
|
||||||
|
dt.add(defaultEntry, "", "");
|
||||||
|
masterOrdinal++;
|
||||||
|
}
|
||||||
|
tableStructure = (Structure) dtm.resolve(dt, null);
|
||||||
|
//System.out.println(tableStructure.toString());
|
||||||
|
isBuilt = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,38 +15,20 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the Entry for a Virtual Base Table
|
* Represents the Entry for a Virtual Base Table
|
||||||
*/
|
*/
|
||||||
public class VirtualBaseTableEntry implements VBTableEntry {
|
public class VirtualBaseTableEntry implements VBTableEntry {
|
||||||
private Long offset;
|
|
||||||
private ClassID baseId;
|
private ClassID baseId;
|
||||||
|
|
||||||
// Re-evaluate which constructors and setters we need
|
// Re-evaluate which constructors and setters we need
|
||||||
|
|
||||||
public VirtualBaseTableEntry(Long offset) {
|
|
||||||
this(offset, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public VirtualBaseTableEntry(ClassID baseId) {
|
public VirtualBaseTableEntry(ClassID baseId) {
|
||||||
this(null, baseId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public VirtualBaseTableEntry(Long offset, ClassID baseId) {
|
|
||||||
this.offset = offset;
|
|
||||||
this.baseId = baseId;
|
this.baseId = baseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOffset(Long offset) {
|
|
||||||
this.offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long getOffset() {
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setClassId(ClassID baseId) {
|
public void setClassId(ClassID baseId) {
|
||||||
this.baseId = baseId;
|
this.baseId = baseId;
|
||||||
|
|
|
@ -15,55 +15,59 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.app.util.pdb.classtype;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.app.util.SymbolPath;
|
import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
|
import ghidra.program.model.gclass.ClassUtils;
|
||||||
|
|
||||||
public abstract class VirtualFunctionTable implements VFTable {
|
public abstract class VirtualFunctionTable implements VFTable {
|
||||||
|
|
||||||
protected ClassID owner;
|
protected ClassID owner;
|
||||||
protected List<ClassID> parentage;
|
protected List<ClassID> parentage;
|
||||||
/**
|
/**
|
||||||
* The number of entries in the table
|
* The number of entries in the table, as specified by the user
|
||||||
*/
|
*/
|
||||||
protected int numEntries;
|
protected int userSpecifiedNumEntries;
|
||||||
/**
|
/**
|
||||||
* This is the offset within the class where we expect to find the pointer that can point to
|
* This is the offset within the class where we expect to find the pointer that can point to
|
||||||
* this table
|
* this table
|
||||||
*/
|
*/
|
||||||
protected int ptrOffsetInClass;
|
protected Long ptrOffsetInClass;
|
||||||
|
|
||||||
|
protected int maxTableIndexSeen;
|
||||||
|
protected Map<Integer, VirtualFunctionTableEntry> entriesByTableIndex;
|
||||||
|
|
||||||
|
// result of compile/build
|
||||||
|
private Structure tableStructure;
|
||||||
|
private boolean isBuilt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Constructor.
|
||||||
* Virtual Function Table for a base (parent) class within an owner class. The owner and parent
|
* Virtual Function Table for a base (parent) class within an owner class. The owner and parent
|
||||||
* class can be null if not known, but methods are offered to fill them in if/when this
|
* class can be null if not known, but methods are offered to fill them in if/when this
|
||||||
* information becomes available
|
* information becomes available
|
||||||
* @param owner class that owns this VBT (can own more than one). Can be null
|
* @param owner class that owns this VBT (can own more than one); can be {@code null}
|
||||||
* @param parentage parentage for which this VBT is used. Can be null
|
* @param parentage parentage for which this VFT is used; can be {@code null}
|
||||||
*/
|
*/
|
||||||
VirtualFunctionTable(ClassID owner, List<ClassID> parentage) {
|
VirtualFunctionTable(ClassID owner, List<ClassID> parentage) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.parentage = new ArrayList<>(parentage);
|
this.parentage = new ArrayList<>(parentage);
|
||||||
numEntries = 0;
|
userSpecifiedNumEntries = 0;
|
||||||
|
maxTableIndexSeen = -1;
|
||||||
|
entriesByTableIndex = new TreeMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the address value at the index in the table
|
* Returns the address value at the table offset
|
||||||
* @param index the index
|
* @param tableIndex the index location in the virtual function table for the entry; based at 1
|
||||||
* @return the address
|
* @return the address
|
||||||
* @throws PdbException upon error retrieving the value
|
* @throws PdbException upon error retrieving the value
|
||||||
*/
|
*/
|
||||||
public abstract Address getAddress(int index) throws PdbException;
|
public abstract Address getAddress(int tableIndex) throws PdbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the symbol path of the function at the index in the table
|
|
||||||
* @param index the index
|
|
||||||
* @return the symbol path
|
|
||||||
* @throws PdbException upon error retrieving the value
|
|
||||||
*/
|
|
||||||
public abstract SymbolPath getPath(int index) throws PdbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the owning class
|
* Returns the owning class
|
||||||
|
@ -81,20 +85,55 @@ public abstract class VirtualFunctionTable implements VFTable {
|
||||||
return parentage;
|
return parentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset within the class for the pointer that can point to this table
|
||||||
|
* @return the offset
|
||||||
|
*/
|
||||||
|
public Long getPtrOffsetInClass() {
|
||||||
|
return ptrOffsetInClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract VirtualFunctionTableEntry getNewEntry(SymbolPath originalMethodPath,
|
||||||
|
SymbolPath overrideMethodPath, Pointer functionPointer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to add an entry to the virtual function table
|
||||||
|
* @param tableIndex the index location in the virtual function table for the entry; based at 1
|
||||||
|
* @param originalMethodPath the symbol path of the method
|
||||||
|
* @param overrideMethodPath the symbol path of the override method
|
||||||
|
* @param functionPointer pointer to the function definition of the method
|
||||||
|
*/
|
||||||
|
public void addEntry(int tableIndex, SymbolPath originalMethodPath,
|
||||||
|
SymbolPath overrideMethodPath, Pointer functionPointer) {
|
||||||
|
VirtualFunctionTableEntry entry =
|
||||||
|
getNewEntry(originalMethodPath, overrideMethodPath, functionPointer);
|
||||||
|
entriesByTableIndex.put(tableIndex, entry);
|
||||||
|
maxTableIndexSeen = Integer.max(maxTableIndexSeen, tableIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entry for the table offset
|
||||||
|
* @param tableIndex the index location in the virtual function table for the entry; based at 1
|
||||||
|
* @return the entry
|
||||||
|
*/
|
||||||
|
public VirtualFunctionTableEntry getEntry(int tableIndex) {
|
||||||
|
return entriesByTableIndex.get(tableIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of entries in the table
|
* Returns the number of entries in the table
|
||||||
* @return the number of entries
|
* @return the number of entries
|
||||||
*/
|
*/
|
||||||
public int getNumEntries() {
|
public int getNumEntries() {
|
||||||
return numEntries;
|
return entriesByTableIndex.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the offset within the class for the pointer that can point to this table
|
* Returns the number of entries in the table, as specified by the user
|
||||||
* @return the offset
|
* @return the number of entries
|
||||||
*/
|
*/
|
||||||
public int getPtrOffsetInClass() {
|
public int getUserSpecifiedNumEntries() {
|
||||||
return ptrOffsetInClass;
|
return userSpecifiedNumEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,22 +152,22 @@ public abstract class VirtualFunctionTable implements VFTable {
|
||||||
this.parentage = parentage;
|
this.parentage = parentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the number of entries for the table
|
|
||||||
* @param numEntriesArg the number of entries
|
|
||||||
*/
|
|
||||||
public void setNumEntries(int numEntriesArg) {
|
|
||||||
numEntries = numEntriesArg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the offset within the class for the pointer that can point to this table
|
* Sets the offset within the class for the pointer that can point to this table
|
||||||
* @param offset the offset
|
* @param offset the offset
|
||||||
*/
|
*/
|
||||||
public void setPtrOffsetInClass(int offset) {
|
public void setPtrOffsetInClass(Long offset) {
|
||||||
ptrOffsetInClass = offset;
|
ptrOffsetInClass = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the "expected" number of entries for the table
|
||||||
|
* @param numEntriesArg the number of entries
|
||||||
|
*/
|
||||||
|
public void setNumEntries(int numEntriesArg) {
|
||||||
|
userSpecifiedNumEntries = numEntriesArg;
|
||||||
|
}
|
||||||
|
|
||||||
void emit(StringBuilder builder) {
|
void emit(StringBuilder builder) {
|
||||||
builder.append("VBT for the following classes within: " + owner);
|
builder.append("VBT for the following classes within: " + owner);
|
||||||
builder.append("\n");
|
builder.append("\n");
|
||||||
|
@ -137,4 +176,57 @@ public abstract class VirtualFunctionTable implements VFTable {
|
||||||
builder.append("\n");
|
builder.append("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return entriesByTableIndex.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxTableIndex() {
|
||||||
|
return maxTableIndexSeen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, VirtualFunctionTableEntry> getEntriesByTableIndex() {
|
||||||
|
return entriesByTableIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the built data type for this vftable for the current entries
|
||||||
|
* @param dtm the data type manager
|
||||||
|
* @param categoryPath category path for the table
|
||||||
|
* @return the structure of the vftable
|
||||||
|
*/
|
||||||
|
public Structure getLayout(DataTypeManager dtm, CategoryPath categoryPath) {
|
||||||
|
if (!isBuilt) { // what if we want to rebuild... what should we do?
|
||||||
|
build(dtm, categoryPath);
|
||||||
|
}
|
||||||
|
return tableStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void build(DataTypeManager dtm, CategoryPath categoryPath) {
|
||||||
|
if (ptrOffsetInClass == null || maxTableIndexSeen == -1) {
|
||||||
|
tableStructure = null;
|
||||||
|
isBuilt = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String name = ClassUtils.getSpecialVxTableName(ptrOffsetInClass);
|
||||||
|
DataType defaultEntry = ClassUtils.getVftDefaultEntry(dtm);
|
||||||
|
int entrySize = defaultEntry.getLength();
|
||||||
|
StructureDataType dt = new StructureDataType(categoryPath, name, 0, dtm);
|
||||||
|
int masterOffset = 0;
|
||||||
|
for (Map.Entry<Integer, VirtualFunctionTableEntry> mapEntry : entriesByTableIndex
|
||||||
|
.entrySet()) {
|
||||||
|
int tableIndex = mapEntry.getKey();
|
||||||
|
VFTableEntry tableEntry = mapEntry.getValue();
|
||||||
|
while (masterOffset < tableIndex) {
|
||||||
|
dt.add(defaultEntry, "", "");
|
||||||
|
masterOffset += entrySize;
|
||||||
|
}
|
||||||
|
dt.add(tableEntry.getFunctionPointer(), tableEntry.getOverridePath().toString(), "");
|
||||||
|
masterOffset += entrySize;
|
||||||
|
}
|
||||||
|
tableStructure = (Structure) dtm.resolve(dt, null);
|
||||||
|
//System.out.println(tableStructure.toString());
|
||||||
|
isBuilt = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.classtype;
|
||||||
|
|
||||||
|
import ghidra.app.util.SymbolPath;
|
||||||
|
import ghidra.program.model.data.Pointer;
|
||||||
|
|
||||||
|
public class VirtualFunctionTableEntry implements VFTableEntry {
|
||||||
|
SymbolPath originalMethodPath;
|
||||||
|
SymbolPath overrideMethodPath;
|
||||||
|
Pointer functionPointer;
|
||||||
|
|
||||||
|
public VirtualFunctionTableEntry(SymbolPath originalMethodPath, SymbolPath overrideMethodPath,
|
||||||
|
Pointer functionPointer) {
|
||||||
|
this.originalMethodPath = originalMethodPath;
|
||||||
|
this.overrideMethodPath = overrideMethodPath;
|
||||||
|
this.functionPointer = functionPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOriginalPath(SymbolPath path) {
|
||||||
|
originalMethodPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SymbolPath getOriginalPath() {
|
||||||
|
return originalMethodPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOverridePath(SymbolPath path) {
|
||||||
|
overrideMethodPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SymbolPath getOverridePath() {
|
||||||
|
return overrideMethodPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFunctionPointer(Pointer pointer) {
|
||||||
|
functionPointer = pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pointer getFunctionPointer() {
|
||||||
|
return functionPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,8 +23,7 @@ import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.app.util.bin.format.pdb.DefaultCompositeMember;
|
import ghidra.app.util.bin.format.pdb.DefaultCompositeMember;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||||
import ghidra.app.util.pdb.classtype.Access;
|
import ghidra.app.util.pdb.classtype.*;
|
||||||
import ghidra.app.util.pdb.classtype.ClassFieldAttributes;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
@ -195,6 +194,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||||
addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers);
|
addVftPtrs(composite, classType, lists.vftPtrs(), type, myMembers);
|
||||||
addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers);
|
addMembers(composite, classType, lists.nonstaticMembers(), type, myMembers);
|
||||||
|
|
||||||
|
addMethods(combo, lists.methods());
|
||||||
|
|
||||||
if (!classType.validate()) {
|
if (!classType.validate()) {
|
||||||
// TODO: Investigate. We should do this check for some classes somewhere. Should
|
// TODO: Investigate. We should do this check for some classes somewhere. Should
|
||||||
// we do it here. Set breakpoint here to investigate.
|
// we do it here. Set breakpoint here to investigate.
|
||||||
|
@ -241,8 +242,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||||
throws PdbException, CancelledException {
|
throws PdbException, CancelledException {
|
||||||
|
|
||||||
AbstractCompositeMsType cType = (AbstractCompositeMsType) type;
|
AbstractCompositeMsType cType = (AbstractCompositeMsType) type;
|
||||||
Access defaultAccess = (type instanceof AbstractClassMsType) ? Access.PRIVATE
|
Access defaultAccess = myClassType.getDefaultAccess();
|
||||||
: Access.PUBLIC;
|
|
||||||
|
|
||||||
for (AbstractMsType baseType : msBases) {
|
for (AbstractMsType baseType : msBases) {
|
||||||
applicator.checkCancelled();
|
applicator.checkCancelled();
|
||||||
|
@ -364,6 +364,90 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||||
return dataType;
|
return dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addMethods(ComboType combo, List<AbstractMsType> methods)
|
||||||
|
throws CancelledException {
|
||||||
|
|
||||||
|
if (methods.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CppCompositeType cppCompositeType = combo.ct();
|
||||||
|
SymbolPath classSymbolPath = cppCompositeType.getSymbolPath();
|
||||||
|
Access defaultAccess = cppCompositeType.getDefaultAccess();
|
||||||
|
|
||||||
|
for (AbstractMsType methodType : methods) {
|
||||||
|
applicator.checkCancelled();
|
||||||
|
if (methodType instanceof AbstractOneMethodMsType oneMethodType) {
|
||||||
|
String name = oneMethodType.getName();
|
||||||
|
ClassFieldMsAttributes attributes = oneMethodType.getAttributes();
|
||||||
|
AbstractMsType t =
|
||||||
|
applicator.getPdb().getTypeRecord(oneMethodType.getProcedureTypeRecordNumber());
|
||||||
|
int adjuster = 0;
|
||||||
|
if (t instanceof AbstractMemberFunctionMsType memberFunc) {
|
||||||
|
adjuster = memberFunc.getThisAdjuster();
|
||||||
|
}
|
||||||
|
Long offset = oneMethodType.getOffsetInVFTableIfIntroVirtual();
|
||||||
|
RecordNumber procedureTypeRn = oneMethodType.getProcedureTypeRecordNumber();
|
||||||
|
DataType dt = applicator.getDataType(procedureTypeRn);
|
||||||
|
if (!(dt instanceof FunctionDefinition def)) {
|
||||||
|
Msg.warn(this,
|
||||||
|
"MemberFunction expected, but found: " + dt.getClass().getSimpleName());
|
||||||
|
// Put something in its place? Or abort the whole class?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SymbolPath methodSymbolPath =
|
||||||
|
classSymbolPath.append(new SymbolPath(name)).replaceInvalidChars();
|
||||||
|
ClassFieldAttributes atts = ClassFieldAttributes.convert(attributes, defaultAccess);
|
||||||
|
if (atts.getProperty() == Property.VIRTUAL) {
|
||||||
|
cppCompositeType.addVirtualMethod(adjuster, offset.intValue(), methodSymbolPath,
|
||||||
|
def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (methodType instanceof AbstractOverloadedMethodMsType overloadedMethodType) {
|
||||||
|
String name = overloadedMethodType.getName();
|
||||||
|
RecordNumber methodsListRn = overloadedMethodType.getTypeMethodListRecordNumber();
|
||||||
|
AbstractMsType methodsListTry = applicator.getTypeRecord(methodsListRn);
|
||||||
|
if (methodsListTry instanceof AbstractMethodListMsType methodsListType) {
|
||||||
|
SymbolPath methodSymbolPath =
|
||||||
|
classSymbolPath.append(new SymbolPath(name)).replaceInvalidChars();
|
||||||
|
List<AbstractMethodRecordMs> recordList = methodsListType.getList();
|
||||||
|
for (AbstractMethodRecordMs methodRecord : recordList) {
|
||||||
|
applicator.checkCancelled();
|
||||||
|
Long offset = methodRecord.getOptionalOffset();
|
||||||
|
RecordNumber procedureTypeRn = methodRecord.getProcedureTypeRecordNumber();
|
||||||
|
ClassFieldMsAttributes attributes = methodRecord.getAttributes();
|
||||||
|
AbstractMsType t = applicator.getPdb().getTypeRecord(procedureTypeRn);
|
||||||
|
int adjuster = 0;
|
||||||
|
if (t instanceof AbstractMemberFunctionMsType memberFunc) {
|
||||||
|
adjuster = memberFunc.getThisAdjuster();
|
||||||
|
}
|
||||||
|
DataType dt = applicator.getDataType(procedureTypeRn);
|
||||||
|
if (!(dt instanceof FunctionDefinition def)) {
|
||||||
|
Msg.warn(this,
|
||||||
|
"MemberFunction expected, but found: " +
|
||||||
|
dt.getClass().getSimpleName());
|
||||||
|
// Put something in its place? Or abort the whole class?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ClassFieldAttributes atts =
|
||||||
|
ClassFieldAttributes.convert(attributes, defaultAccess);
|
||||||
|
if (atts.getProperty() == Property.VIRTUAL) {
|
||||||
|
cppCompositeType.addVirtualMethod(adjuster, offset.intValue(),
|
||||||
|
methodSymbolPath, def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.warn(this, "Unexexpected method list type: " +
|
||||||
|
methodsListTry.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.warn(this,
|
||||||
|
"Unexexpected method type: " + methodType.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addMembers(Composite composite, CppCompositeType myClassType,
|
private void addMembers(Composite composite, CppCompositeType myClassType,
|
||||||
List<AbstractMemberMsType> msMembers, AbstractCompositeMsType type,
|
List<AbstractMemberMsType> msMembers, AbstractCompositeMsType type,
|
||||||
List<DefaultPdbUniversalMember> myMembers) throws CancelledException, PdbException {
|
List<DefaultPdbUniversalMember> myMembers) throws CancelledException, PdbException {
|
||||||
|
|
|
@ -25,6 +25,7 @@ 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.PdbLog;
|
||||||
import ghidra.app.util.pdb.classtype.*;
|
import ghidra.app.util.pdb.classtype.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
import ghidra.program.model.gclass.ClassUtils;
|
import ghidra.program.model.gclass.ClassUtils;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -41,7 +42,6 @@ public class CppCompositeType {
|
||||||
private static final String VIRTUAL_BASE_COMMENT = "Virtual Base";
|
private static final String VIRTUAL_BASE_COMMENT = "Virtual Base";
|
||||||
private static final String VIRTUAL_BASE_SPECULATIVE_COMMENT =
|
private static final String VIRTUAL_BASE_SPECULATIVE_COMMENT =
|
||||||
"Virtual Base - Speculative Placement";
|
"Virtual Base - Speculative Placement";
|
||||||
//private static final String INDIRECT_VIRTUAL_BASE_CLASS_COMMENT = "Indirect Virtual Base Class";
|
|
||||||
|
|
||||||
private boolean isFinal;
|
private boolean isFinal;
|
||||||
private ClassKey classKey;
|
private ClassKey classKey;
|
||||||
|
@ -50,8 +50,7 @@ public class CppCompositeType {
|
||||||
private int size;
|
private int size;
|
||||||
private SymbolPath symbolPath;
|
private SymbolPath symbolPath;
|
||||||
private CategoryPath categoryPath;
|
private CategoryPath categoryPath;
|
||||||
private DataTypePath selfBaseDataTypePath;
|
private ClassID myId;
|
||||||
private ProgramClassID myId;
|
|
||||||
|
|
||||||
private CategoryPath baseCategoryPath;
|
private CategoryPath baseCategoryPath;
|
||||||
private CategoryPath internalsCategoryPath;
|
private CategoryPath internalsCategoryPath;
|
||||||
|
@ -71,6 +70,13 @@ public class CppCompositeType {
|
||||||
private List<AbstractMember> myMembers;
|
private List<AbstractMember> myMembers;
|
||||||
private List<Member> layoutMembers;
|
private List<Member> layoutMembers;
|
||||||
|
|
||||||
|
private static record VirtualFunctionInfo(Integer tableOffset, Integer thisAdjuster,
|
||||||
|
SymbolPath name, FunctionDefinition definition) {}
|
||||||
|
|
||||||
|
private List<VirtualFunctionInfo> virtualFunctionInfo;
|
||||||
|
|
||||||
|
//----
|
||||||
|
|
||||||
private List<SyntacticBaseClass> syntacticBaseClasses;
|
private List<SyntacticBaseClass> syntacticBaseClasses;
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -99,6 +105,11 @@ public class CppCompositeType {
|
||||||
*/
|
*/
|
||||||
private Long mainVbtPtrOffset;
|
private Long mainVbtPtrOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the main Vft for this class
|
||||||
|
*/
|
||||||
|
private VirtualFunctionTable mainVft;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the main Vbt for this class
|
* Holds the main Vbt for this class
|
||||||
*/
|
*/
|
||||||
|
@ -126,19 +137,6 @@ public class CppCompositeType {
|
||||||
private TreeMap<ClassID, Long> baseOffsetById;
|
private TreeMap<ClassID, Long> baseOffsetById;
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// Data used for resolving main vftptr
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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<Long, PlaceholderVirtualBaseTable> placeholderVirtualBaseTables;
|
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// Data used for analyzing Vxts and their parentage
|
// Data used for analyzing Vxts and their parentage
|
||||||
|
|
||||||
|
@ -148,8 +146,10 @@ public class CppCompositeType {
|
||||||
private TreeSet<VxtPtrInfo> propagatedDirectVirtualBaseVbts;
|
private TreeSet<VxtPtrInfo> propagatedDirectVirtualBaseVbts;
|
||||||
private TreeSet<VxtPtrInfo> propagatededIndirectVirtualBaseVfts;
|
private TreeSet<VxtPtrInfo> propagatededIndirectVirtualBaseVfts;
|
||||||
private TreeSet<VxtPtrInfo> propagatedIndirectVirtualBaseVbts;
|
private TreeSet<VxtPtrInfo> propagatedIndirectVirtualBaseVbts;
|
||||||
private TreeMap<Long, VxtPtrInfo> finalLayoutVfts;
|
private TreeMap<Long, VxtPtrInfo> finalVftPtrInfoByOffset;
|
||||||
private TreeMap<Long, VxtPtrInfo> finalLayoutVbts;
|
private TreeMap<Long, VxtPtrInfo> finalVbtPtrInfoByOffset;
|
||||||
|
private TreeMap<Long, VXT> finalVftByOffset;
|
||||||
|
private TreeMap<Long, VXT> finalVbtByOffset;
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -165,13 +165,14 @@ public class CppCompositeType {
|
||||||
this.composite = composite;
|
this.composite = composite;
|
||||||
this.mangledName = mangledName;
|
this.mangledName = mangledName;
|
||||||
myId = getClassId(this);
|
myId = getClassId(this);
|
||||||
|
categoryPath = new CategoryPath(composite.getCategoryPath(), composite.getName());
|
||||||
internalsCategoryPath = ClassUtils.getClassInternalsPath(composite); // eliminate
|
internalsCategoryPath = ClassUtils.getClassInternalsPath(composite); // eliminate
|
||||||
selfBaseDataTypePath = ClassUtils.getBaseClassDataTypePath(composite);
|
|
||||||
|
|
||||||
directLayoutBaseClasses = new ArrayList<>();
|
directLayoutBaseClasses = new ArrayList<>();
|
||||||
virtualLayoutBaseClasses = new ArrayList<>();
|
virtualLayoutBaseClasses = new ArrayList<>();
|
||||||
directVirtualLayoutBaseClasses = new ArrayList<>();
|
directVirtualLayoutBaseClasses = new ArrayList<>();
|
||||||
indirectVirtualLayoutBaseClasses = new ArrayList<>();
|
indirectVirtualLayoutBaseClasses = new ArrayList<>();
|
||||||
|
virtualFunctionInfo = new ArrayList<>();
|
||||||
|
|
||||||
vftPtrTypeByOffset = new TreeMap<>();
|
vftPtrTypeByOffset = new TreeMap<>();
|
||||||
myMembers = new ArrayList<>();
|
myMembers = new ArrayList<>();
|
||||||
|
@ -343,7 +344,7 @@ public class CppCompositeType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method for adding a member to this type, to include a attribtues and comment
|
* Method for adding a member to this type, to include a attributes and comment
|
||||||
* @param memberName member name
|
* @param memberName member name
|
||||||
* @param dataType data type of member
|
* @param dataType data type of member
|
||||||
* @param isFlexibleArray {@code true} if member is a flexible array
|
* @param isFlexibleArray {@code true} if member is a flexible array
|
||||||
|
@ -359,6 +360,20 @@ public class CppCompositeType {
|
||||||
addMember(layoutMembers, newMember);
|
addMember(layoutMembers, newMember);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for adding a virtual method to this type
|
||||||
|
* @param thisAdjuster the this-adjustor offset
|
||||||
|
* @param tableOffset virtual function table offset
|
||||||
|
* @param name function name
|
||||||
|
* @param definition function definition
|
||||||
|
*/
|
||||||
|
public void addVirtualMethod(int thisAdjuster, int tableOffset, SymbolPath name,
|
||||||
|
FunctionDefinition definition) {
|
||||||
|
VirtualFunctionInfo info =
|
||||||
|
new VirtualFunctionInfo(tableOffset, thisAdjuster, name, definition);
|
||||||
|
virtualFunctionInfo.add(info);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to perform class layout from the user specified information. Note that all
|
* Method to perform class layout from the user specified information. Note that all
|
||||||
* dependency classes (parents, etc.) must have had their like-processing performed
|
* dependency classes (parents, etc.) must have had their like-processing performed
|
||||||
|
@ -368,7 +383,7 @@ public class CppCompositeType {
|
||||||
* @throws PdbException upon issue performing the layout
|
* @throws PdbException upon issue performing the layout
|
||||||
* @throws CancelledException upon user cancellation
|
* @throws CancelledException upon user cancellation
|
||||||
*/
|
*/
|
||||||
public void createLayout(ObjectOrientedClassLayout layoutOptions, VxtManager vxtManager,
|
public void createLayout(ObjectOrientedClassLayout layoutOptions, MsftVxtManager vxtManager,
|
||||||
TaskMonitor monitor) throws PdbException, CancelledException {
|
TaskMonitor monitor) throws PdbException, CancelledException {
|
||||||
switch (layoutOptions) {
|
switch (layoutOptions) {
|
||||||
case MEMBERS_ONLY:
|
case MEMBERS_ONLY:
|
||||||
|
@ -427,6 +442,14 @@ public class CppCompositeType {
|
||||||
return classKey;
|
return classKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default access of the type
|
||||||
|
* @return the default access
|
||||||
|
*/
|
||||||
|
public Access getDefaultAccess() {
|
||||||
|
return ClassKey.CLASS.equals(classKey) ? Access.PRIVATE : Access.PUBLIC;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to set the name of the composite
|
* Method to set the name of the composite
|
||||||
* @param className the name
|
* @param className the name
|
||||||
|
@ -518,7 +541,7 @@ public class CppCompositeType {
|
||||||
* Returns the ClassID for this class
|
* Returns the ClassID for this class
|
||||||
* @return the class id
|
* @return the class id
|
||||||
*/
|
*/
|
||||||
public ProgramClassID getClassId() {
|
public ClassID getClassId() {
|
||||||
return myId;
|
return myId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,6 +563,14 @@ public class CppCompositeType {
|
||||||
return selfBaseType;
|
return selfBaseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the CategoryPath of this composite
|
||||||
|
* @return the CategoryPath
|
||||||
|
*/
|
||||||
|
public CategoryPath getCategoryPath() {
|
||||||
|
return categoryPath;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: move to ClassUtils?
|
// TODO: move to ClassUtils?
|
||||||
/**
|
/**
|
||||||
* Returns the "internals" CategoryPath of this composite
|
* Returns the "internals" CategoryPath of this composite
|
||||||
|
@ -672,8 +703,8 @@ public class CppCompositeType {
|
||||||
* @param cpp the CPP type
|
* @param cpp the CPP type
|
||||||
* @return the class id
|
* @return the class id
|
||||||
*/
|
*/
|
||||||
private static ProgramClassID getClassId(CppCompositeType cpp) {
|
private static ClassID getClassId(CppCompositeType cpp) {
|
||||||
return new ProgramClassID(cpp.baseCategoryPath, cpp.getSymbolPath());
|
return new ClassID(cpp.baseCategoryPath, cpp.getSymbolPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -769,15 +800,15 @@ public class CppCompositeType {
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
private void createHierarchicalClassLayout(VxtManager vxtManager, TaskMonitor monitor)
|
private void createHierarchicalClassLayout(MsftVxtManager vxtManager, TaskMonitor monitor)
|
||||||
throws PdbException, CancelledException {
|
throws PdbException, CancelledException {
|
||||||
|
|
||||||
initLayoutAlgorithmData();
|
initLayoutAlgorithmData();
|
||||||
|
|
||||||
findDirectBaseVxtPtrs();
|
findDirectBaseVxtPtrs(vxtManager);
|
||||||
|
|
||||||
findOrAllocateMainVftPtr();
|
findOrAllocateMainVftPtr(vxtManager);
|
||||||
findOrAllocateMainVbtPtr();
|
findOrAllocateMainVbtPtr(vxtManager);
|
||||||
|
|
||||||
createClassLayout(vxtManager, monitor);
|
createClassLayout(vxtManager, monitor);
|
||||||
|
|
||||||
|
@ -803,11 +834,6 @@ public class CppCompositeType {
|
||||||
|
|
||||||
baseOffsetById = new TreeMap<>();
|
baseOffsetById = new TreeMap<>();
|
||||||
|
|
||||||
//======
|
|
||||||
// Data used for resolving main vftptr
|
|
||||||
|
|
||||||
placeholderVirtualBaseTables = new HashMap<>();
|
|
||||||
|
|
||||||
//======
|
//======
|
||||||
// Data used for analyzing Vxts and their parentage
|
// Data used for analyzing Vxts and their parentage
|
||||||
|
|
||||||
|
@ -817,8 +843,10 @@ public class CppCompositeType {
|
||||||
propagatedDirectVirtualBaseVbts = new TreeSet<>();
|
propagatedDirectVirtualBaseVbts = new TreeSet<>();
|
||||||
propagatededIndirectVirtualBaseVfts = new TreeSet<>();
|
propagatededIndirectVirtualBaseVfts = new TreeSet<>();
|
||||||
propagatedIndirectVirtualBaseVbts = new TreeSet<>();
|
propagatedIndirectVirtualBaseVbts = new TreeSet<>();
|
||||||
finalLayoutVfts = new TreeMap<>();
|
finalVftPtrInfoByOffset = new TreeMap<>();
|
||||||
finalLayoutVbts = new TreeMap<>();
|
finalVbtPtrInfoByOffset = new TreeMap<>();
|
||||||
|
finalVftByOffset = new TreeMap<>();
|
||||||
|
finalVbtByOffset = new TreeMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -838,45 +866,45 @@ public class CppCompositeType {
|
||||||
PNode childToParentNode;
|
PNode childToParentNode;
|
||||||
PNode parentToChildNode;
|
PNode parentToChildNode;
|
||||||
|
|
||||||
for (VxtPtrInfo info : finalLayoutVfts.values()) {
|
for (VxtPtrInfo info : finalVftPtrInfoByOffset.values()) {
|
||||||
List<ClassID> parentage = info.parentage();
|
List<ClassID> parentage = info.parentage();
|
||||||
childToParentNode = vftChildToParentRoot;
|
childToParentNode = vftChildToParentRoot;
|
||||||
parentToChildNode = vftParentToChildRoot;
|
parentToChildNode = vftParentToChildRoot;
|
||||||
for (ClassID id : parentage) {
|
for (ClassID id : parentage) {
|
||||||
String name = ((ProgramClassID) id).getSymbolPath().toString();
|
String name = id.getSymbolPath().toString();
|
||||||
childToParentNode.incrementPathCount();
|
childToParentNode.incrementPathCount();
|
||||||
childToParentNode = childToParentNode.getOrAddBranch(name);
|
childToParentNode = childToParentNode.getOrAddBranch(name);
|
||||||
}
|
}
|
||||||
for (ClassID id : parentage.reversed()) {
|
for (ClassID id : parentage.reversed()) {
|
||||||
String name = ((ProgramClassID) id).getSymbolPath().toString();
|
String name = id.getSymbolPath().toString();
|
||||||
parentToChildNode.incrementPathCount();
|
parentToChildNode.incrementPathCount();
|
||||||
parentToChildNode = parentToChildNode.getOrAddBranch(name);
|
parentToChildNode = parentToChildNode.getOrAddBranch(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : finalLayoutVbts.values()) {
|
for (VxtPtrInfo info : finalVbtPtrInfoByOffset.values()) {
|
||||||
List<ClassID> parentage = info.parentage();
|
List<ClassID> parentage = info.parentage();
|
||||||
childToParentNode = vbtChildToParentRoot;
|
childToParentNode = vbtChildToParentRoot;
|
||||||
parentToChildNode = vbtParentToChildRoot;
|
parentToChildNode = vbtParentToChildRoot;
|
||||||
for (ClassID id : parentage) {
|
for (ClassID id : parentage) {
|
||||||
String name = ((ProgramClassID) id).getSymbolPath().toString();
|
String name = id.getSymbolPath().toString();
|
||||||
childToParentNode.incrementPathCount();
|
childToParentNode.incrementPathCount();
|
||||||
childToParentNode = childToParentNode.getOrAddBranch(name);
|
childToParentNode = childToParentNode.getOrAddBranch(name);
|
||||||
}
|
}
|
||||||
for (ClassID id : parentage.reversed()) {
|
for (ClassID id : parentage.reversed()) {
|
||||||
String name = ((ProgramClassID) id).getSymbolPath().toString();
|
String name = id.getSymbolPath().toString();
|
||||||
parentToChildNode.incrementPathCount();
|
parentToChildNode.incrementPathCount();
|
||||||
parentToChildNode = parentToChildNode.getOrAddBranch(name);
|
parentToChildNode = parentToChildNode.getOrAddBranch(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
for (VxtPtrInfo info : finalLayoutVfts.values()) {
|
for (VxtPtrInfo info : finalVftPtrInfoByOffset.values()) {
|
||||||
List<ClassID> altParentage =
|
List<ClassID> altParentage =
|
||||||
finalizeVxtPtrParentage(vftChildToParentRoot, vftParentToChildRoot, info);
|
finalizeVxtPtrParentage(vftChildToParentRoot, vftParentToChildRoot, info);
|
||||||
builder.append(dumpVxtPtrResult("vft", info, altParentage));
|
builder.append(dumpVxtPtrResult("vft", info, altParentage));
|
||||||
|
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : finalLayoutVbts.values()) {
|
for (VxtPtrInfo info : finalVbtPtrInfoByOffset.values()) {
|
||||||
List<ClassID> altParentage =
|
List<ClassID> altParentage =
|
||||||
finalizeVxtPtrParentage(vbtChildToParentRoot, vbtParentToChildRoot, info);
|
finalizeVxtPtrParentage(vbtChildToParentRoot, vbtParentToChildRoot, info);
|
||||||
builder.append(dumpVxtPtrResult("vbt", info, altParentage));
|
builder.append(dumpVxtPtrResult("vbt", info, altParentage));
|
||||||
|
@ -901,7 +929,7 @@ public class CppCompositeType {
|
||||||
String startNode = null;
|
String startNode = null;
|
||||||
|
|
||||||
for (ClassID id : parentage) {
|
for (ClassID id : parentage) {
|
||||||
String name = ((ProgramClassID) id).getSymbolPath().toString();
|
String name = id.getSymbolPath().toString();
|
||||||
childToParentNode = childToParentNode.getBranch(name);
|
childToParentNode = childToParentNode.getBranch(name);
|
||||||
if (childToParentNode.getPathCount() == 1) {
|
if (childToParentNode.getPathCount() == 1) {
|
||||||
startNode = name;
|
startNode = name;
|
||||||
|
@ -913,7 +941,7 @@ public class CppCompositeType {
|
||||||
// (use all nodes)
|
// (use all nodes)
|
||||||
boolean foundStart = (startNode == null);
|
boolean foundStart = (startNode == null);
|
||||||
for (ClassID id : parentage.reversed()) {
|
for (ClassID id : parentage.reversed()) {
|
||||||
String name = ((ProgramClassID) id).getSymbolPath().toString();
|
String name = id.getSymbolPath().toString();
|
||||||
if (name.equals(startNode)) {
|
if (name.equals(startNode)) {
|
||||||
foundStart = true;
|
foundStart = true;
|
||||||
}
|
}
|
||||||
|
@ -940,12 +968,12 @@ public class CppCompositeType {
|
||||||
private String dumpVxtPtrResult(String vxt, VxtPtrInfo info, List<ClassID> altParentage) {
|
private String dumpVxtPtrResult(String vxt, VxtPtrInfo info, List<ClassID> altParentage) {
|
||||||
List<String> r1 = new ArrayList<>();
|
List<String> r1 = new ArrayList<>();
|
||||||
for (ClassID id : altParentage.reversed()) {
|
for (ClassID id : altParentage.reversed()) {
|
||||||
String name = ((ProgramClassID) id).getSymbolPath().toString();
|
String name = id.getSymbolPath().toString();
|
||||||
r1.add(name);
|
r1.add(name);
|
||||||
}
|
}
|
||||||
List<String> r2 = new ArrayList<>();
|
List<String> r2 = new ArrayList<>();
|
||||||
for (ClassID id : info.parentage().reversed()) {
|
for (ClassID id : info.parentage().reversed()) {
|
||||||
String name = ((ProgramClassID) id).getSymbolPath().toString();
|
String name = id.getSymbolPath().toString();
|
||||||
r2.add(name);
|
r2.add(name);
|
||||||
}
|
}
|
||||||
return String.format(" %4d %s %s\t%s\n", info.finalOffset(), vxt, r1.toString(),
|
return String.format(" %4d %s %s\t%s\n", info.finalOffset(), vxt, r1.toString(),
|
||||||
|
@ -990,9 +1018,17 @@ public class CppCompositeType {
|
||||||
* @throws CancelledException upon user cancellation
|
* @throws CancelledException upon user cancellation
|
||||||
* @throws PdbException up issue with finding the vbt or assigning offsets to virtual bases
|
* @throws PdbException up issue with finding the vbt or assigning offsets to virtual bases
|
||||||
*/
|
*/
|
||||||
private void createClassLayout(VxtManager vxtManager, TaskMonitor monitor)
|
private void createClassLayout(MsftVxtManager vxtManager, TaskMonitor monitor)
|
||||||
throws CancelledException, PdbException {
|
throws CancelledException, PdbException {
|
||||||
List<ClassPdbMember> selfBaseMembers = getSelfBaseClassMembers();
|
List<ClassPdbMember> selfBaseMembers = getSelfBaseClassMembers();
|
||||||
|
mainVft = getMainVft(vxtManager);
|
||||||
|
if (mainVft != null) {
|
||||||
|
updateMainVft();
|
||||||
|
for (VXT t : finalVftByOffset.values()) {
|
||||||
|
VirtualFunctionTable vft = (VirtualFunctionTable) t;
|
||||||
|
updateVftFromSelf(vft);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (getNumLayoutVirtualBaseClasses() == 0) {
|
if (getNumLayoutVirtualBaseClasses() == 0) {
|
||||||
if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, false, size,
|
if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, false, size,
|
||||||
selfBaseMembers, msg -> Msg.warn(this, msg), monitor)) {
|
selfBaseMembers, msg -> Msg.warn(this, msg), monitor)) {
|
||||||
|
@ -1010,13 +1046,22 @@ public class CppCompositeType {
|
||||||
new ClassPdbMember("", selfBaseType, false, 0, SELF_BASE_COMMENT);
|
new ClassPdbMember("", selfBaseType, false, 0, SELF_BASE_COMMENT);
|
||||||
|
|
||||||
mainVbt = getMainVbt(vxtManager);
|
mainVbt = getMainVbt(vxtManager);
|
||||||
|
if (mainVbt != null) {
|
||||||
|
updateMainVbt();
|
||||||
|
// If there was any updating to do for secondary tables, we would do it here.
|
||||||
|
// Something to consider in the future
|
||||||
|
// for (VXT t : finalVbtByOffset.values()) {
|
||||||
|
// VirtualBaseTable vbt = (VirtualBaseTable) t;
|
||||||
|
// updateVbtFromSelf(vbt);
|
||||||
|
// }
|
||||||
|
}
|
||||||
assignVirtualBaseOffsets();
|
assignVirtualBaseOffsets();
|
||||||
|
|
||||||
String baseComment = (mainVbt instanceof ProgramVirtualBaseTable) ? VIRTUAL_BASE_COMMENT
|
String baseComment = (mainVbt instanceof ProgramVirtualBaseTable) ? VIRTUAL_BASE_COMMENT
|
||||||
: VIRTUAL_BASE_SPECULATIVE_COMMENT;
|
: VIRTUAL_BASE_SPECULATIVE_COMMENT;
|
||||||
TreeMap<Long, ClassPdbMember> virtualBasePdbMembers =
|
TreeMap<Long, ClassPdbMember> virtualBasePdbMembers =
|
||||||
getVirtualBaseClassMembers(baseComment);
|
getVirtualBaseClassMembers(baseComment);
|
||||||
findVirtualBaseVxtPtrs();
|
findVirtualBaseVxtPtrs(vxtManager);
|
||||||
|
|
||||||
TreeMap<Long, ClassPdbMember> allMembers = new TreeMap<>();
|
TreeMap<Long, ClassPdbMember> allMembers = new TreeMap<>();
|
||||||
allMembers.put(0L, directClassPdbMember);
|
allMembers.put(0L, directClassPdbMember);
|
||||||
|
@ -1178,22 +1223,26 @@ public class CppCompositeType {
|
||||||
* Finds all virtual base and virtual function pointers in the hierarchy of this class's
|
* Finds all virtual base and virtual function pointers in the hierarchy of this class's
|
||||||
* self base.
|
* self base.
|
||||||
*/
|
*/
|
||||||
private void findDirectBaseVxtPtrs() {
|
private void findDirectBaseVxtPtrs(VxtManager vxtManager) {
|
||||||
for (DirectLayoutBaseClass base : directLayoutBaseClasses) {
|
for (DirectLayoutBaseClass base : directLayoutBaseClasses) {
|
||||||
CppCompositeType cppBaseType = base.getBaseClassType();
|
CppCompositeType cppBaseType = base.getBaseClassType();
|
||||||
ProgramClassID baseId = cppBaseType.getClassId();
|
ClassID baseId = cppBaseType.getClassId();
|
||||||
long baseOffset = base.getOffset();
|
long baseOffset = base.getOffset();
|
||||||
// Note that if the parent has already had its layout done, it will not have
|
// 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
|
// used the vxtManager that we are passing in here; it will have used whatever
|
||||||
// was passed to the layout method for that class
|
// was passed to the layout method for that class
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVfts()) {
|
for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVfts()) {
|
||||||
VxtPtrInfo newInfo = createSelfOwnedDirectVxtPtrInfo(info, baseId, baseOffset);
|
VxtPtrInfo newInfo =
|
||||||
storeVxtInfo(propagatedSelfBaseVfts, finalLayoutVfts, vftTableIdByOffset,
|
createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset);
|
||||||
|
updateVft(vxtManager, baseId, newInfo, parentInfo);
|
||||||
|
storeVxtInfo(propagatedSelfBaseVfts, finalVftPtrInfoByOffset, vftTableIdByOffset,
|
||||||
vftOffsetByTableId, newInfo);
|
vftOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVbts()) {
|
for (VxtPtrInfo parentInfo : cppBaseType.getPropagatedSelfBaseVbts()) {
|
||||||
VxtPtrInfo newInfo = createSelfOwnedDirectVxtPtrInfo(info, baseId, baseOffset);
|
VxtPtrInfo newInfo =
|
||||||
storeVxtInfo(propagatedSelfBaseVbts, finalLayoutVbts, vbtTableIdByOffset,
|
createSelfOwnedDirectVxtPtrInfo(parentInfo, baseId, baseOffset);
|
||||||
|
updateVbt(vxtManager, baseId, newInfo, parentInfo);
|
||||||
|
storeVxtInfo(propagatedSelfBaseVbts, finalVbtPtrInfoByOffset, vbtTableIdByOffset,
|
||||||
vbtOffsetByTableId, newInfo);
|
vbtOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1205,32 +1254,36 @@ public class CppCompositeType {
|
||||||
* we are not relying on the "indirect" virtual base class information from the PDB. This
|
* 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.
|
* is done this way so that we can collect parentage information for the pointers.
|
||||||
*/
|
*/
|
||||||
private void findVirtualBaseVxtPtrs() {
|
private void findVirtualBaseVxtPtrs(MsftVxtManager vxtManager) {
|
||||||
// Walk direct bases to find vxts of virtual bases. TODO: also notate all rolled up
|
// Walk direct bases to find vxts of virtual bases. TODO: also notate all rolled up
|
||||||
// virtuals for each direct base.
|
// virtuals for each direct base.
|
||||||
for (DirectLayoutBaseClass base : directLayoutBaseClasses) {
|
for (DirectLayoutBaseClass base : directLayoutBaseClasses) {
|
||||||
|
|
||||||
CppCompositeType cppBaseType = base.getBaseClassType();
|
CppCompositeType cppBaseType = base.getBaseClassType();
|
||||||
|
ClassID baseId = cppBaseType.getClassId();
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVfts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVfts()) {
|
||||||
VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info);
|
VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info);
|
||||||
storeVxtInfo(propagatedDirectVirtualBaseVfts, finalLayoutVfts, vftTableIdByOffset,
|
updateVft(vxtManager, baseId, newInfo, info);
|
||||||
vftOffsetByTableId, newInfo);
|
storeVxtInfo(propagatedDirectVirtualBaseVfts, finalVftPtrInfoByOffset,
|
||||||
|
vftTableIdByOffset, vftOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVbts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVbts()) {
|
||||||
VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info);
|
VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info);
|
||||||
storeVxtInfo(propagatedDirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset,
|
updateVbt(vxtManager, baseId, newInfo, info);
|
||||||
vbtOffsetByTableId, newInfo);
|
storeVxtInfo(propagatedDirectVirtualBaseVbts, finalVbtPtrInfoByOffset,
|
||||||
|
vbtTableIdByOffset, vbtOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVfts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVfts()) {
|
||||||
VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info);
|
VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info);
|
||||||
storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalLayoutVfts,
|
updateVft(vxtManager, baseId, newInfo, info);
|
||||||
|
storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalVftPtrInfoByOffset,
|
||||||
vftTableIdByOffset, vftOffsetByTableId, newInfo);
|
vftTableIdByOffset, vftOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVbts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVbts()) {
|
||||||
VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info);
|
VxtPtrInfo newInfo = createSelfOwnedVirtualVxtPtrInfo(info);
|
||||||
storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset,
|
updateVbt(vxtManager, baseId, newInfo, info);
|
||||||
vbtOffsetByTableId, newInfo);
|
storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalVbtPtrInfoByOffset,
|
||||||
|
vbtTableIdByOffset, vbtOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1240,40 +1293,46 @@ public class CppCompositeType {
|
||||||
for (DirectVirtualLayoutBaseClass base : directVirtualLayoutBaseClasses) {
|
for (DirectVirtualLayoutBaseClass base : directVirtualLayoutBaseClasses) {
|
||||||
|
|
||||||
CppCompositeType cppBaseType = base.getBaseClassType();
|
CppCompositeType cppBaseType = base.getBaseClassType();
|
||||||
ProgramClassID baseId = cppBaseType.getClassId();
|
ClassID baseId = cppBaseType.getClassId();
|
||||||
|
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVfts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVfts()) {
|
||||||
VxtPtrInfo newInfo = createVirtualOwnedSelfVxtPtrInfo(info, baseId);
|
VxtPtrInfo newInfo = createVirtualOwnedSelfVxtPtrInfo(info, baseId);
|
||||||
storeVxtInfo(propagatedDirectVirtualBaseVfts, finalLayoutVfts, vftTableIdByOffset,
|
updateVft(vxtManager, baseId, newInfo, info);
|
||||||
vftOffsetByTableId, newInfo);
|
storeVxtInfo(propagatedDirectVirtualBaseVfts, finalVftPtrInfoByOffset,
|
||||||
|
vftTableIdByOffset, vftOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVbts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedSelfBaseVbts()) {
|
||||||
VxtPtrInfo newInfo = createVirtualOwnedSelfVxtPtrInfo(info, baseId);
|
VxtPtrInfo newInfo = createVirtualOwnedSelfVxtPtrInfo(info, baseId);
|
||||||
storeVxtInfo(propagatedDirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset,
|
updateVbt(vxtManager, baseId, newInfo, info);
|
||||||
vbtOffsetByTableId, newInfo);
|
storeVxtInfo(propagatedDirectVirtualBaseVbts, finalVbtPtrInfoByOffset,
|
||||||
|
vbtTableIdByOffset, vbtOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVfts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVfts()) {
|
||||||
VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info);
|
VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info);
|
||||||
storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalLayoutVfts,
|
updateVft(vxtManager, baseId, newInfo, info);
|
||||||
|
storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalVftPtrInfoByOffset,
|
||||||
vftTableIdByOffset, vftOffsetByTableId, newInfo);
|
vftTableIdByOffset, vftOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVbts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedDirectVirtualBaseVbts()) {
|
||||||
VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info);
|
VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info);
|
||||||
storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset,
|
updateVbt(vxtManager, baseId, newInfo, info);
|
||||||
vbtOffsetByTableId, newInfo);
|
storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalVbtPtrInfoByOffset,
|
||||||
|
vbtTableIdByOffset, vbtOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVfts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVfts()) {
|
||||||
VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info);
|
VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info);
|
||||||
storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalLayoutVfts,
|
updateVft(vxtManager, baseId, newInfo, info);
|
||||||
|
storeVxtInfo(propagatededIndirectVirtualBaseVfts, finalVftPtrInfoByOffset,
|
||||||
vftTableIdByOffset, vftOffsetByTableId, newInfo);
|
vftTableIdByOffset, vftOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVbts()) {
|
for (VxtPtrInfo info : cppBaseType.getPropagatedIndirectVirtualBaseVbts()) {
|
||||||
VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info);
|
VxtPtrInfo newInfo = createVirtualOwnedVirtualVxtPtrInfo(info);
|
||||||
storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalLayoutVbts, vbtTableIdByOffset,
|
updateVbt(vxtManager, baseId, newInfo, info);
|
||||||
vbtOffsetByTableId, newInfo);
|
storeVxtInfo(propagatedIndirectVirtualBaseVbts, finalVbtPtrInfoByOffset,
|
||||||
|
vbtTableIdByOffset, vbtOffsetByTableId, newInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note sure what the final information will look like when we are done. For this stopping
|
// Note sure what the final information will look like when we are done. For this stopping
|
||||||
|
@ -1284,7 +1343,6 @@ public class CppCompositeType {
|
||||||
* @param finalInfo the final info tree
|
* @param finalInfo the final info tree
|
||||||
* @param tableIdByOffset the table-id-by-offset map
|
* @param tableIdByOffset the table-id-by-offset map
|
||||||
* @param offsetByTableId the offset-by-table-id map
|
* @param offsetByTableId the offset-by-table-id map
|
||||||
* @param info the vxt ptr info
|
|
||||||
*/
|
*/
|
||||||
private void storeVxtInfo(TreeSet<VxtPtrInfo> propagate, TreeMap<Long, VxtPtrInfo> finalInfo,
|
private void storeVxtInfo(TreeSet<VxtPtrInfo> propagate, TreeMap<Long, VxtPtrInfo> finalInfo,
|
||||||
Map<Long, OwnerParentage> tableIdByOffset, Map<OwnerParentage, Long> offsetByTableId,
|
Map<Long, OwnerParentage> tableIdByOffset, Map<OwnerParentage, Long> offsetByTableId,
|
||||||
|
@ -1364,7 +1422,7 @@ public class CppCompositeType {
|
||||||
throw new PdbException("Cannot place base class");
|
throw new PdbException("Cannot place base class");
|
||||||
}
|
}
|
||||||
baseOffset += base.getBasePointerOffset();
|
baseOffset += base.getBasePointerOffset();
|
||||||
ProgramClassID baseId = cppBaseType.getClassId();
|
ClassID baseId = cppBaseType.getClassId();
|
||||||
baseOffsetById.put(baseId, baseOffset);
|
baseOffsetById.put(baseId, baseOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1373,7 +1431,7 @@ public class CppCompositeType {
|
||||||
* Finds or allocates (if needed) the Virtual Function Table "Pointer" within the class
|
* Finds or allocates (if needed) the Virtual Function Table "Pointer" within the class
|
||||||
* structure
|
* structure
|
||||||
*/
|
*/
|
||||||
private void findOrAllocateMainVftPtr() {
|
private void findOrAllocateMainVftPtr(MsftVxtManager vxtManager) {
|
||||||
if (propagatedSelfBaseVfts.isEmpty()) {
|
if (propagatedSelfBaseVfts.isEmpty()) {
|
||||||
if (!vftPtrTypeByOffset.isEmpty()) {
|
if (!vftPtrTypeByOffset.isEmpty()) {
|
||||||
if (vftPtrTypeByOffset.size() > 1) {
|
if (vftPtrTypeByOffset.size() > 1) {
|
||||||
|
@ -1382,8 +1440,21 @@ public class CppCompositeType {
|
||||||
myVftPtrOffset = vftPtrTypeByOffset.firstKey();
|
myVftPtrOffset = vftPtrTypeByOffset.firstKey();
|
||||||
VxtPtrInfo info =
|
VxtPtrInfo info =
|
||||||
new VxtPtrInfo(myVftPtrOffset, myVftPtrOffset, myId, List.of(myId));
|
new VxtPtrInfo(myVftPtrOffset, myVftPtrOffset, myId, List.of(myId));
|
||||||
propagatedSelfBaseVfts.add(info);
|
VirtualFunctionTable myVft =
|
||||||
finalLayoutVfts.put(info.accumOffset(), info);
|
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);
|
||||||
|
}
|
||||||
|
finalVftPtrInfoByOffset.put(info.accumOffset(), info);
|
||||||
OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage());
|
OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage());
|
||||||
vftTableIdByOffset.put(info.accumOffset(), op);
|
vftTableIdByOffset.put(info.accumOffset(), op);
|
||||||
vftOffsetByTableId.put(op, info.accumOffset());
|
vftOffsetByTableId.put(op, info.accumOffset());
|
||||||
|
@ -1391,17 +1462,17 @@ public class CppCompositeType {
|
||||||
ClassFieldAttributes.UNKNOWN, myVftPtrOffset.intValue());
|
ClassFieldAttributes.UNKNOWN, myVftPtrOffset.intValue());
|
||||||
layoutVftPtrMembers.add(newMember);
|
layoutVftPtrMembers.add(newMember);
|
||||||
myMembers.add(newMember);
|
myMembers.add(newMember);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mainVftPtrOffset = finalLayoutVfts.isEmpty() ? null : finalLayoutVfts.firstKey();
|
mainVftPtrOffset =
|
||||||
|
finalVftPtrInfoByOffset.isEmpty() ? null : finalVftPtrInfoByOffset.firstKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds or allocates (if needed) the Virtual Base Table "Pointer" for within the class
|
* Finds or allocates (if needed) the Virtual Base Table "Pointer" for within the class
|
||||||
* structure
|
* structure
|
||||||
*/
|
*/
|
||||||
private void findOrAllocateMainVbtPtr() {
|
private void findOrAllocateMainVbtPtr(MsftVxtManager vxtManager) {
|
||||||
if (propagatedSelfBaseVbts.isEmpty()) {
|
if (propagatedSelfBaseVbts.isEmpty()) {
|
||||||
if (!virtualLayoutBaseClasses.isEmpty()) {
|
if (!virtualLayoutBaseClasses.isEmpty()) {
|
||||||
TreeSet<Long> vbtOffsets = new TreeSet<>();
|
TreeSet<Long> vbtOffsets = new TreeSet<>();
|
||||||
|
@ -1416,103 +1487,314 @@ public class CppCompositeType {
|
||||||
Msg.warn(this, "Mismatch vbt location for " + myId);
|
Msg.warn(this, "Mismatch vbt location for " + myId);
|
||||||
}
|
}
|
||||||
VxtPtrInfo info = new VxtPtrInfo(vbtPtrOffset, vbtPtrOffset, myId, List.of(myId));
|
VxtPtrInfo info = new VxtPtrInfo(vbtPtrOffset, vbtPtrOffset, myId, List.of(myId));
|
||||||
propagatedSelfBaseVbts.add(info);
|
VirtualBaseTable myVbt = vxtManager.findVbt(myId, List.of(myId));
|
||||||
finalLayoutVbts.put(info.accumOffset(), info);
|
if (myVbt != null) {
|
||||||
|
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());
|
OwnerParentage op = new OwnerParentage(info.baseId(), info.parentage());
|
||||||
vbtTableIdByOffset.put(info.accumOffset(), op);
|
vbtTableIdByOffset.put(info.accumOffset(), op);
|
||||||
vbtOffsetByTableId.put(op, info.accumOffset());
|
vbtOffsetByTableId.put(op, info.accumOffset());
|
||||||
myVbtPtrOffset = finalLayoutVbts.firstKey();
|
myVbtPtrOffset = finalVbtPtrInfoByOffset.firstKey();
|
||||||
Member newMember = new Member(ClassUtils.VBPTR, ClassUtils.VXPTR_TYPE, false,
|
Member newMember = new Member(ClassUtils.VBPTR, ClassUtils.VXPTR_TYPE, false,
|
||||||
ClassFieldAttributes.UNKNOWN, myVbtPtrOffset.intValue());
|
ClassFieldAttributes.UNKNOWN, myVbtPtrOffset.intValue());
|
||||||
layoutVbtPtrMembers.add(newMember);
|
layoutVbtPtrMembers.add(newMember);
|
||||||
myMembers.add(newMember);
|
myMembers.add(newMember);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mainVbtPtrOffset = finalLayoutVbts.isEmpty() ? null : finalLayoutVbts.firstKey();
|
mainVbtPtrOffset =
|
||||||
|
finalVbtPtrInfoByOffset.isEmpty() ? null : finalVbtPtrInfoByOffset.firstKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds new entries to the main vftable for this class
|
||||||
|
*/
|
||||||
|
private void updateMainVft() {
|
||||||
|
for (VirtualFunctionInfo vfInfo : virtualFunctionInfo) {
|
||||||
|
int tableOffset = vfInfo.tableOffset();
|
||||||
|
// we believe this adjuster of 0 is all we want for first direct base
|
||||||
|
// -1 signifies not intro
|
||||||
|
if (vfInfo.thisAdjuster() == 0 && vfInfo.tableOffset() != -1) {
|
||||||
|
mainVft.addEntry(tableOffset, vfInfo.name(), vfInfo.name(),
|
||||||
|
new PointerDataType(vfInfo.definition()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates vftable entries with values from this class that override those of parent classes
|
||||||
|
*/
|
||||||
|
private VirtualFunctionTable updateVft(VxtManager vxtManager, ClassID baseId, VxtPtrInfo info,
|
||||||
|
VxtPtrInfo parentInfo) {
|
||||||
|
if (!(vxtManager instanceof MsftVxtManager mvxtManager)) {
|
||||||
|
// error
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ClassID parentId;
|
||||||
|
List<ClassID> parentParentage;
|
||||||
|
if (parentInfo == null) {
|
||||||
|
parentId = info.baseId();
|
||||||
|
List<ClassID> parentage = info.parentage();
|
||||||
|
parentParentage = parentage.subList(0, parentage.size() - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parentId = baseId;
|
||||||
|
parentParentage = parentInfo.parentage();
|
||||||
|
}
|
||||||
|
|
||||||
|
Long finalOffset = info.finalOffset();
|
||||||
|
VirtualFunctionTable myVft = (VirtualFunctionTable) finalVftByOffset.get(finalOffset);
|
||||||
|
if (myVft == null) {
|
||||||
|
myVft = mvxtManager.findVft(myId, info.parentage());
|
||||||
|
if (myVft == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finalVftByOffset.put(finalOffset, myVft);
|
||||||
|
}
|
||||||
|
|
||||||
|
myVft.setPtrOffsetInClass(finalOffset);
|
||||||
|
VirtualFunctionTable parentVft =
|
||||||
|
mvxtManager.findVft(parentId, parentParentage);
|
||||||
|
|
||||||
|
if (parentVft == null) {
|
||||||
|
// this is an error
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, VirtualFunctionTableEntry> mapEntry : parentVft
|
||||||
|
.getEntriesByTableIndex()
|
||||||
|
.entrySet()) {
|
||||||
|
int tableOffset = mapEntry.getKey();
|
||||||
|
VFTableEntry e = mapEntry.getValue();
|
||||||
|
SymbolPath parentOrigPath = e.getOriginalPath();
|
||||||
|
SymbolPath parentPath = e.getOverridePath();
|
||||||
|
VFTableEntry currentEntry = myVft.getEntry(tableOffset);
|
||||||
|
if (currentEntry != null) {
|
||||||
|
SymbolPath currentOrigPath = currentEntry.getOriginalPath();
|
||||||
|
SymbolPath currentPath = currentEntry.getOverridePath();
|
||||||
|
// Note that this check also checks the method name
|
||||||
|
if (!parentOrigPath.equals(currentOrigPath)) {
|
||||||
|
// problem
|
||||||
|
}
|
||||||
|
boolean parentOverride = !parentOrigPath.equals(parentPath);
|
||||||
|
boolean currentOverride = !currentOrigPath.equals(currentPath);
|
||||||
|
if (!currentOverride && parentOverride) {
|
||||||
|
myVft.addEntry(tableOffset, parentOrigPath, parentPath, e.getFunctionPointer());
|
||||||
|
}
|
||||||
|
else if (currentOverride && !parentOverride) {
|
||||||
|
myVft.addEntry(tableOffset, currentOrigPath, currentPath,
|
||||||
|
e.getFunctionPointer());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// maybe order matters?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
myVft.addEntry(tableOffset, parentOrigPath, parentPath, e.getFunctionPointer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return myVft;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateVftFromSelf(VirtualFunctionTable vft) {
|
||||||
|
for (Map.Entry<Integer, VirtualFunctionTableEntry> mapEntry : vft.getEntriesByTableIndex()
|
||||||
|
.entrySet()) {
|
||||||
|
int tableOffset = mapEntry.getKey();
|
||||||
|
VFTableEntry e = mapEntry.getValue();
|
||||||
|
SymbolPath origPath = e.getOriginalPath();
|
||||||
|
SymbolPath methodPath = e.getOverridePath();
|
||||||
|
String methodName = methodPath.getName();
|
||||||
|
for (VirtualFunctionInfo vfInfo : virtualFunctionInfo) {
|
||||||
|
SymbolPath selfMethodPath = vfInfo.name();
|
||||||
|
String selfMethodName = selfMethodPath.getName();
|
||||||
|
if (selfMethodName.equals(methodName)) {
|
||||||
|
// potential overridden method; just replace path (could be the same)
|
||||||
|
methodPath = selfMethodPath;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vft.addEntry(tableOffset, origPath, methodPath, e.getFunctionPointer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMainVbt() {
|
||||||
|
int numEntries = virtualLayoutBaseClasses.size();
|
||||||
|
Integer existingEntries = mainVbt.getNumEntries();
|
||||||
|
if (numEntries < existingEntries) {
|
||||||
|
// error: silent for now... not sure how we want to deal with this
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (VirtualLayoutBaseClass virtualLayoutBaseClass : virtualLayoutBaseClasses) {
|
||||||
|
int tableOffset = virtualLayoutBaseClass.getOffetFromVbt();
|
||||||
|
// Value in base class is more of an index
|
||||||
|
ClassID baseId = virtualLayoutBaseClass.getBaseClassType().getClassId();
|
||||||
|
int vbtPtrOffset = virtualLayoutBaseClass.getBasePointerOffset();
|
||||||
|
if (vbtPtrOffset != mainVbtPtrOffset) {
|
||||||
|
// error
|
||||||
|
// ignoring for now... not sure how we want to deal with this
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VBTableEntry e = mainVbt.getEntry(tableOffset);
|
||||||
|
if (e == null) {
|
||||||
|
mainVbt.addEntry(tableOffset, baseId);
|
||||||
|
}
|
||||||
|
// No need to update an existing entry in base table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove? Believe that only the main VBT should ever possibly get updated. The others
|
||||||
|
// will only get updated in size when they are the main VBT within those respective base
|
||||||
|
// classes.
|
||||||
|
private VirtualBaseTable updateVbt(VxtManager vxtManager, ClassID baseId, VxtPtrInfo info,
|
||||||
|
VxtPtrInfo parentInfo) {
|
||||||
|
if (!(vxtManager instanceof MsftVxtManager mvxtManager)) {
|
||||||
|
// error
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ClassID parentId;
|
||||||
|
List<ClassID> parentParentage;
|
||||||
|
if (parentInfo == null) {
|
||||||
|
parentId = info.baseId();
|
||||||
|
List<ClassID> parentage = info.parentage();
|
||||||
|
parentParentage = parentage.subList(0, parentage.size() - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parentId = baseId;
|
||||||
|
parentParentage = parentInfo.parentage();
|
||||||
|
}
|
||||||
|
|
||||||
|
Long finalOffset = info.finalOffset();
|
||||||
|
VirtualBaseTable myVbt = (VirtualBaseTable) finalVbtByOffset.get(finalOffset);
|
||||||
|
if (myVbt == null) {
|
||||||
|
myVbt = mvxtManager.findVbt(myId, info.parentage());
|
||||||
|
if (myVbt == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finalVbtByOffset.put(finalOffset, myVbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
myVbt.setPtrOffsetInClass(finalOffset);
|
||||||
|
VirtualBaseTable parentVbt =
|
||||||
|
mvxtManager.findVbt(parentId, parentParentage);
|
||||||
|
if (parentVbt == null) {
|
||||||
|
// this is an error
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Map.Entry<Integer, VirtualBaseTableEntry> mapEntry : parentVbt.getEntriesByTableIndex()
|
||||||
|
.entrySet()) {
|
||||||
|
int tableOffset = mapEntry.getKey();
|
||||||
|
VBTableEntry e = mapEntry.getValue();
|
||||||
|
myVbt.addEntry(tableOffset, e.getClassId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return myVbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the Virtual Base Table to be used for placing virtual bases of this class
|
* Provides the Virtual Base Table to be used for placing virtual bases of this class
|
||||||
|
* @throws PdbException upon unrecognized vft type
|
||||||
*/
|
*/
|
||||||
private VirtualBaseTable getMainVbt(VxtManager vxtManager) throws PdbException {
|
private VirtualFunctionTable getMainVft(MsftVxtManager vxtManager) throws PdbException {
|
||||||
VirtualBaseTable vbt = null;
|
if (!finalVftPtrInfoByOffset.isEmpty()) {
|
||||||
if (!finalLayoutVbts.isEmpty()) {
|
VxtPtrInfo firstVftPtrInfo = finalVftPtrInfoByOffset.firstEntry().getValue();
|
||||||
VxtPtrInfo firstVbtPtrInfo = finalLayoutVbts.firstEntry().getValue();
|
VirtualFunctionTable vft = vxtManager.findVft(myId, firstVftPtrInfo.parentage());
|
||||||
List<VirtualLayoutBaseClass> reorderedVirtualBases = new ArrayList<>();
|
return vft;
|
||||||
for (ClassID bId : depthFirstVirtualBases().keySet()) {
|
// Following is for consideration for testing without a program:
|
||||||
for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) {
|
// if (vft instanceof ProgramVirtualFunctionTable pvft) {
|
||||||
CppCompositeType baseType = base.getBaseClassType();
|
// return pvft;
|
||||||
ClassID id = baseType.getClassId();
|
// }
|
||||||
if (id.equals(bId)) {
|
// else if (vft instanceof PlaceholderVirtualFunctionTable plvft) {
|
||||||
reorderedVirtualBases.add(base);
|
// return plvft;
|
||||||
}
|
// }
|
||||||
}
|
// else {
|
||||||
}
|
// throw new PdbException(
|
||||||
long offset = selfBaseType.getAlignedLength();
|
// "VFT type not expected: " + vft.getClass().getSimpleName());
|
||||||
for (VirtualLayoutBaseClass base : reorderedVirtualBases) {
|
// }
|
||||||
CppCompositeType baseType = base.getBaseClassType();
|
|
||||||
addPlaceholderVirtualBaseTableEntry(vxtManager, base, offset);
|
|
||||||
offset += baseType.getSelfBaseType().getAlignedLength();
|
|
||||||
}
|
|
||||||
if (vxtManager instanceof MsftVxtManager mvxtManager) {
|
|
||||||
VBTable table = mvxtManager.findVbt(myId, firstVbtPtrInfo.parentage());
|
|
||||||
if (table instanceof ProgramVirtualBaseTable pvbt) {
|
|
||||||
return pvbt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vbt = placeholderVirtualBaseTables.get(mainVbtPtrOffset);
|
|
||||||
}
|
}
|
||||||
return vbt;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------
|
/**
|
||||||
//----------------------------------------------------------------------------------------------
|
* Provides the Virtual Base Table to be used for placing virtual bases of this class
|
||||||
// used by find main vbt (probably should evaluate for cleanup)
|
* @throws PdbException upon unrecognized vbt type
|
||||||
private void addPlaceholderVirtualBaseTableEntry(VxtManager vxtManager,
|
*/
|
||||||
VirtualLayoutBaseClass base, Long baseOffset) throws PdbException {
|
private VirtualBaseTable getMainVbt(MsftVxtManager vxtManager) throws PdbException {
|
||||||
|
if (!finalVbtPtrInfoByOffset.isEmpty()) {
|
||||||
|
VxtPtrInfo firstVbtPtrInfo = finalVbtPtrInfoByOffset.firstEntry().getValue();
|
||||||
|
VirtualBaseTable vbt = vxtManager.findVbt(myId, firstVbtPtrInfo.parentage());
|
||||||
|
if (vbt instanceof ProgramVirtualBaseTable pvbt) {
|
||||||
|
return pvbt;
|
||||||
|
}
|
||||||
|
else if (vbt instanceof PlaceholderVirtualBaseTable plvbt) {
|
||||||
|
List<VirtualLayoutBaseClass> reorderedVirtualBases = new ArrayList<>();
|
||||||
|
for (ClassID bId : depthFirstVirtualBases().keySet()) {
|
||||||
|
for (VirtualLayoutBaseClass base : virtualLayoutBaseClasses) {
|
||||||
|
CppCompositeType baseType = base.getBaseClassType();
|
||||||
|
ClassID id = baseType.getClassId();
|
||||||
|
if (id.equals(bId)) {
|
||||||
|
reorderedVirtualBases.add(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long off = selfBaseType.getAlignedLength();
|
||||||
|
for (VirtualLayoutBaseClass base : reorderedVirtualBases) {
|
||||||
|
CppCompositeType baseType = base.getBaseClassType();
|
||||||
|
addPlaceholderVirtualBaseTableEntry(plvbt, vxtManager, base, off);
|
||||||
|
off += baseType.getSelfBaseType().getAlignedLength();
|
||||||
|
}
|
||||||
|
return plvbt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new PdbException(
|
||||||
|
"VBT type not expected: " + vbt.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
long index = base.getBasePointerOffset();
|
private void addPlaceholderVirtualBaseTableEntry(PlaceholderVirtualBaseTable ptable,
|
||||||
OwnerParentage op = vbtTableIdByOffset.get(index);
|
MsftVxtManager vxtManager, VirtualLayoutBaseClass base, long baseOffset) {
|
||||||
if (op == null) {
|
long basePtrOffset = base.getBasePointerOffset();
|
||||||
|
if (ptable.getPtrOffsetInClass() != basePtrOffset) {
|
||||||
// error
|
// error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (vxtManager instanceof MsftVxtManager mvxtManager) {
|
PlaceholderVirtualBaseTableEntry e = ptable.getEntry(base.getOffetFromVbt());
|
||||||
VBTable xtable = mvxtManager.findVbt(op.owner(), op.parentage());
|
if (e != null) {
|
||||||
if (xtable == null) {
|
e.setOffset(baseOffset);
|
||||||
int entrySize =
|
return;
|
||||||
composite.getDataTypeManager().getDataOrganization().getIntegerSize();
|
|
||||||
PlaceholderVirtualBaseTable newTable =
|
|
||||||
new PlaceholderVirtualBaseTable(op.owner(), op.parentage(), entrySize);
|
|
||||||
xtable = newTable;
|
|
||||||
placeholderVirtualBaseTables.put(index, newTable);
|
|
||||||
}
|
|
||||||
if (xtable instanceof PlaceholderVirtualBaseTable ptable) {
|
|
||||||
VBTableEntry e = ptable.getBase(base.getOffetFromVbt());
|
|
||||||
if (e != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ClassID baseId = base.getBaseClassType().getClassId();
|
|
||||||
ptable.setBaseClassOffsetAndId(base.getOffetFromVbt(), baseOffset, baseId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PlaceholderVirtualBaseTable ptable = placeholderVirtualBaseTables.get(index);
|
|
||||||
if (ptable == null) {
|
|
||||||
int entrySize =
|
|
||||||
composite.getDataTypeManager().getDataOrganization().getIntegerSize();
|
|
||||||
ptable = new PlaceholderVirtualBaseTable(op.owner(), op.parentage(), entrySize);
|
|
||||||
placeholderVirtualBaseTables.put(index, ptable);
|
|
||||||
}
|
|
||||||
VBTableEntry e = ptable.getBase(base.getOffetFromVbt());
|
|
||||||
if (e != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ClassID baseId = base.getBaseClassType().getClassId();
|
|
||||||
ptable.setBaseClassOffsetAndId(base.getOffetFromVbt(), baseOffset, baseId);
|
|
||||||
}
|
}
|
||||||
|
ClassID baseId = base.getBaseClassType().getClassId();
|
||||||
|
ptable.setBaseClassOffsetAndId(base.getOffetFromVbt(), baseOffset, baseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private void addVirtualFunctionTableEntry(MsftVxtManager vxtManager, int offsetInTable,
|
||||||
|
// SymbolPath methodPath, FunctionDefinition functionDefinition) throws PdbException {
|
||||||
|
// OwnerParentage op = vftTableIdByOffset.get(mainVftPtrOffset);
|
||||||
|
// if (op == null) {
|
||||||
|
// // error
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (vxtManager instanceof MsftVxtManager mvxtManager) {
|
||||||
|
// VFTable xtable = mvxtManager.findVft(op.owner(), op.parentage());
|
||||||
|
// VirtualFunctionTable vft;
|
||||||
|
// if (xtable != null) {
|
||||||
|
// if (!(xtable instanceof VirtualFunctionTable myvft)) {
|
||||||
|
// // error
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// vft = myvft;
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// vft = new PlaceholderVirtualFunctionTable((ProgramClassID) op.owner(),
|
||||||
|
// op.parentage(), mainVftPtrOffset.intValue());
|
||||||
|
// }
|
||||||
|
// vft.addEntry(offsetInTable, methodPath, new PointerDataType(functionDefinition));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns depth-first occurrences of ClassIDs along with their parentage with the assumption
|
* Returns depth-first occurrences of ClassIDs along with their parentage with the assumption
|
||||||
* that all direct (non-virtual) base classes occur before direct virtual base classes.
|
* that all direct (non-virtual) base classes occur before direct virtual base classes.
|
||||||
|
@ -1635,12 +1917,6 @@ public class CppCompositeType {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
|
||||||
/**
|
|
||||||
* Record holding owner and parentage using ClassIDs. These can be used for vxtptrs and
|
|
||||||
* (possibly) also for base class info
|
|
||||||
*/
|
|
||||||
private record OwnerParentage(ClassID owner, List<ClassID> parentage) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We understand the shallow immutability of records and that the contents of the List are
|
* We understand the shallow immutability of records and that the contents of the List are
|
||||||
* not used in comparison. Should we convert from record to class?
|
* not used in comparison. Should we convert from record to class?
|
||||||
|
|
|
@ -36,7 +36,8 @@ import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType;
|
||||||
import ghidra.app.util.bin.format.pe.cli.tables.CliAbstractTableRow;
|
import ghidra.app.util.bin.format.pe.cli.tables.CliAbstractTableRow;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.app.util.pdb.PdbCategories;
|
import ghidra.app.util.pdb.PdbCategories;
|
||||||
import ghidra.app.util.pdb.classtype.*;
|
import ghidra.app.util.pdb.classtype.ClassTypeManager;
|
||||||
|
import ghidra.app.util.pdb.classtype.MsftVxtManager;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.database.data.DataTypeUtilities;
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.disassemble.DisassemblerContextImpl;
|
import ghidra.program.disassemble.DisassemblerContextImpl;
|
||||||
|
@ -206,7 +207,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// If we have symbols and memory with VBTs in them, then a better VbtManager is created.
|
// If we have symbols and memory with VBTs in them, then a better VbtManager is created.
|
||||||
private VxtManager vxtManager;
|
private MsftVxtManager vxtManager;
|
||||||
private PdbRegisterNameToProgramRegisterMapper registerNameToRegisterMapper;
|
private PdbRegisterNameToProgramRegisterMapper registerNameToRegisterMapper;
|
||||||
|
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
|
@ -370,6 +371,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
case ALL:
|
case ALL:
|
||||||
processTypes();
|
processTypes();
|
||||||
processSymbols();
|
processSymbols();
|
||||||
|
vxtManager.doTableLayouts(dataTypeManager);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new PdbException("PDB: Invalid Application Control: " +
|
throw new PdbException("PDB: Invalid Application Control: " +
|
||||||
|
@ -643,16 +645,16 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
if (program != null) {
|
if (program != null) {
|
||||||
// Currently, this must happen after symbolGroups are created.
|
// Currently, this must happen after symbolGroups are created.
|
||||||
MsftVxtManager msftVxtManager =
|
MsftVxtManager msftVxtManager =
|
||||||
new MsftVxtManager(getClassTypeManager(), program);
|
new MsftVxtManager(getClassTypeManager(), program); // TODO: need to fix MsftVxtManager to work with or without a program!!!!!!!!!!
|
||||||
msftVxtManager.createVirtualTables(getRootPdbCategory(), findVirtualTableSymbols(), log,
|
msftVxtManager.createVirtualTables(getRootPdbCategory(), findVirtualTableSymbols(), log,
|
||||||
monitor);
|
monitor);
|
||||||
vxtManager = msftVxtManager;
|
vxtManager = msftVxtManager;
|
||||||
|
|
||||||
registerNameToRegisterMapper = new PdbRegisterNameToProgramRegisterMapper(program);
|
registerNameToRegisterMapper = new PdbRegisterNameToProgramRegisterMapper(program);
|
||||||
}
|
}
|
||||||
else {
|
// else {
|
||||||
vxtManager = new VxtManager(getClassTypeManager());
|
// vxtManager = new VxtManager(getClassTypeManager());
|
||||||
}
|
// }
|
||||||
preWorkDone = true;
|
preWorkDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1582,7 +1584,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
// Virtual-Base/Function-Table-related methods.
|
// Virtual-Base/Function-Table-related methods.
|
||||||
//==============================================================================================
|
//==============================================================================================
|
||||||
VxtManager getVxtManager() {
|
MsftVxtManager getVxtManager() {
|
||||||
return vxtManager;
|
return vxtManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import ghidra.program.model.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressIterator;
|
import ghidra.program.model.address.AddressIterator;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.gclass.ClassID;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
|
@ -57,30 +58,30 @@ public class MsftVxtManagerTest extends AbstractGenericTest {
|
||||||
|
|
||||||
private static int[] dummyVftMeta = new int[] { 0 };
|
private static int[] dummyVftMeta = new int[] { 0 };
|
||||||
|
|
||||||
private static ClassID A1_ID = new ProgramClassID(CategoryPath.ROOT, sp("A1NS::A1"));
|
private static ClassID A1_ID = new ClassID(CategoryPath.ROOT, sp("A1NS::A1"));
|
||||||
private static ClassID A2_ID = new ProgramClassID(CategoryPath.ROOT, sp("A2NS::A2"));
|
private static ClassID A2_ID = new ClassID(CategoryPath.ROOT, sp("A2NS::A2"));
|
||||||
private static ClassID A_ID = new ProgramClassID(CategoryPath.ROOT, sp("ANS::A"));
|
private static ClassID A_ID = new ClassID(CategoryPath.ROOT, sp("ANS::A"));
|
||||||
private static ClassID B1_ID = new ProgramClassID(CategoryPath.ROOT, sp("B1NS::B1"));
|
private static ClassID B1_ID = new ClassID(CategoryPath.ROOT, sp("B1NS::B1"));
|
||||||
private static ClassID B2_ID = new ProgramClassID(CategoryPath.ROOT, sp("B2NS::B2"));
|
private static ClassID B2_ID = new ClassID(CategoryPath.ROOT, sp("B2NS::B2"));
|
||||||
private static ClassID B_ID = new ProgramClassID(CategoryPath.ROOT, sp("BNS::B"));
|
private static ClassID B_ID = new ClassID(CategoryPath.ROOT, sp("BNS::B"));
|
||||||
private static ClassID C_ID = new ProgramClassID(CategoryPath.ROOT, sp("CNS::C"));
|
private static ClassID C_ID = new ClassID(CategoryPath.ROOT, sp("CNS::C"));
|
||||||
private static ClassID D_ID = new ProgramClassID(CategoryPath.ROOT, sp("DNS::D"));
|
private static ClassID D_ID = new ClassID(CategoryPath.ROOT, sp("DNS::D"));
|
||||||
private static ClassID E_ID = new ProgramClassID(CategoryPath.ROOT, sp("ENS::E"));
|
private static ClassID E_ID = new ClassID(CategoryPath.ROOT, sp("ENS::E"));
|
||||||
private static ClassID F_ID = new ProgramClassID(CategoryPath.ROOT, sp("FNS::F"));
|
private static ClassID F_ID = new ClassID(CategoryPath.ROOT, sp("FNS::F"));
|
||||||
private static ClassID G_ID = new ProgramClassID(CategoryPath.ROOT, sp("GNS::G"));
|
private static ClassID G_ID = new ClassID(CategoryPath.ROOT, sp("GNS::G"));
|
||||||
private static ClassID H_ID = new ProgramClassID(CategoryPath.ROOT, sp("HNS::H"));
|
private static ClassID H_ID = new ClassID(CategoryPath.ROOT, sp("HNS::H"));
|
||||||
private static ClassID I_ID = new ProgramClassID(CategoryPath.ROOT, sp("INS::I"));
|
private static ClassID I_ID = new ClassID(CategoryPath.ROOT, sp("INS::I"));
|
||||||
private static ClassID J_ID = new ProgramClassID(CategoryPath.ROOT, sp("JNS::J"));
|
private static ClassID J_ID = new ClassID(CategoryPath.ROOT, sp("JNS::J"));
|
||||||
private static ClassID K_ID = new ProgramClassID(CategoryPath.ROOT, sp("KNS::K"));
|
private static ClassID K_ID = new ClassID(CategoryPath.ROOT, sp("KNS::K"));
|
||||||
private static ClassID L_ID = new ProgramClassID(CategoryPath.ROOT, sp("LNS::L"));
|
private static ClassID L_ID = new ClassID(CategoryPath.ROOT, sp("LNS::L"));
|
||||||
private static ClassID N1_ID = new ProgramClassID(CategoryPath.ROOT, sp("N1NS::N1"));
|
private static ClassID N1_ID = new ClassID(CategoryPath.ROOT, sp("N1NS::N1"));
|
||||||
private static ClassID N2_ID = new ProgramClassID(CategoryPath.ROOT, sp("N2NS::N2"));
|
private static ClassID N2_ID = new ClassID(CategoryPath.ROOT, sp("N2NS::N2"));
|
||||||
private static ClassID M_ID = new ProgramClassID(CategoryPath.ROOT, sp("MNS::M"));
|
private static ClassID M_ID = new ClassID(CategoryPath.ROOT, sp("MNS::M"));
|
||||||
private static ClassID O1_ID = new ProgramClassID(CategoryPath.ROOT, sp("O1NS::O1"));
|
private static ClassID O1_ID = new ClassID(CategoryPath.ROOT, sp("O1NS::O1"));
|
||||||
private static ClassID O2_ID = new ProgramClassID(CategoryPath.ROOT, sp("O2NS::O2"));
|
private static ClassID O2_ID = new ClassID(CategoryPath.ROOT, sp("O2NS::O2"));
|
||||||
private static ClassID O3_ID = new ProgramClassID(CategoryPath.ROOT, sp("O3NS::O3"));
|
private static ClassID O3_ID = new ClassID(CategoryPath.ROOT, sp("O3NS::O3"));
|
||||||
private static ClassID O4_ID = new ProgramClassID(CategoryPath.ROOT, sp("O4NS::O4"));
|
private static ClassID O4_ID = new ClassID(CategoryPath.ROOT, sp("O4NS::O4"));
|
||||||
private static ClassID O_ID = new ProgramClassID(CategoryPath.ROOT, sp("ONS::O"));
|
private static ClassID O_ID = new ClassID(CategoryPath.ROOT, sp("ONS::O"));
|
||||||
|
|
||||||
private static Function A1NS_A1_fa1_1 = new FunctionTestDouble("A1NS::A1::fa1_1");
|
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_2 = new FunctionTestDouble("A1NS::A1::fa1_2");
|
||||||
|
|
|
@ -65,10 +65,10 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
|
||||||
private static DataType vftptr64;
|
private static DataType vftptr64;
|
||||||
private static DataType vbtptr32;
|
private static DataType vbtptr32;
|
||||||
private static DataType vbtptr64;
|
private static DataType vbtptr64;
|
||||||
private static MsftVxtManager msftVxtManager32;
|
private static MsftVxtManager vxtManager32;
|
||||||
private static MsftVxtManager msftVxtManager64;
|
private static MsftVxtManager vxtManager64;
|
||||||
private static VxtManager vxtManager32;
|
private static MsftVxtManager vxtManagerNoProgram32;
|
||||||
private static VxtManager vxtManager64;
|
private static MsftVxtManager vxtManagerNoProgram64;
|
||||||
// Note: Currently all test have expected results based on up the CLASS_HIERARCHY layout.
|
// Note: Currently all test have expected results based on up the CLASS_HIERARCHY layout.
|
||||||
private static ObjectOrientedClassLayout classLayoutChoice =
|
private static ObjectOrientedClassLayout classLayoutChoice =
|
||||||
ObjectOrientedClassLayout.CLASS_HIERARCHY;
|
ObjectOrientedClassLayout.CLASS_HIERARCHY;
|
||||||
|
@ -116,19 +116,19 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
|
||||||
|
|
||||||
createVbTables();
|
createVbTables();
|
||||||
|
|
||||||
msftVxtManager32 = new MsftVxtManager(ctm32, program32);
|
vxtManager32 = new MsftVxtManager(ctm32, program32);
|
||||||
msftVxtManager64 = new MsftVxtManager(ctm64, program64);
|
vxtManager64 = new MsftVxtManager(ctm64, program64);
|
||||||
try {
|
try {
|
||||||
msftVxtManager32.createVirtualTables(CategoryPath.ROOT, addressByMangledName32, log,
|
vxtManager32.createVirtualTables(CategoryPath.ROOT, addressByMangledName32, log,
|
||||||
monitor);
|
monitor);
|
||||||
msftVxtManager64.createVirtualTables(CategoryPath.ROOT, addressByMangledName64, log,
|
vxtManager64.createVirtualTables(CategoryPath.ROOT, addressByMangledName64, log,
|
||||||
monitor);
|
monitor);
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
vxtManager32 = new VxtManager(ctm32);
|
vxtManagerNoProgram32 = new MsftVxtManager(ctm32, null);
|
||||||
vxtManager64 = new VxtManager(ctm64);
|
vxtManagerNoProgram64 = new MsftVxtManager(ctm64, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,8 +227,8 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
|
||||||
private FunctionManager myFunctionManager;
|
private FunctionManager myFunctionManager;
|
||||||
|
|
||||||
private MyStubProgram(Memory mem, FunctionManager fm) {
|
private MyStubProgram(Memory mem, FunctionManager fm) {
|
||||||
this.myMemory = mem;
|
myMemory = mem;
|
||||||
this.myFunctionManager = fm;
|
myFunctionManager = fm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6994,7 +6994,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
|
||||||
public void test_32bit_vbt() throws Exception {
|
public void test_32bit_vbt() throws Exception {
|
||||||
boolean is64Bit = false;
|
boolean is64Bit = false;
|
||||||
MyTestDummyDataTypeManager dtm = dtm32;
|
MyTestDummyDataTypeManager dtm = dtm32;
|
||||||
VxtManager vxtManager = msftVxtManager32;
|
MsftVxtManager vxtManager = vxtManager32;
|
||||||
List<String> expectedResults = new ArrayList<>();
|
List<String> expectedResults = new ArrayList<>();
|
||||||
expectedResults.add(getExpectedA_32());
|
expectedResults.add(getExpectedA_32());
|
||||||
expectedResults.add(getExpectedC_32());
|
expectedResults.add(getExpectedC_32());
|
||||||
|
@ -7037,7 +7037,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
|
||||||
public void test_32bit_speculative() throws Exception {
|
public void test_32bit_speculative() throws Exception {
|
||||||
boolean is64Bit = false;
|
boolean is64Bit = false;
|
||||||
MyTestDummyDataTypeManager dtm = dtm32;
|
MyTestDummyDataTypeManager dtm = dtm32;
|
||||||
VxtManager vxtManager = vxtManager32;
|
MsftVxtManager vxtManager = vxtManagerNoProgram32;
|
||||||
List<String> expectedResults = new ArrayList<>();
|
List<String> expectedResults = new ArrayList<>();
|
||||||
expectedResults.add(getSpeculatedA_32());
|
expectedResults.add(getSpeculatedA_32());
|
||||||
expectedResults.add(getSpeculatedC_32());
|
expectedResults.add(getSpeculatedC_32());
|
||||||
|
@ -7080,7 +7080,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
|
||||||
public void test_64bit_vbt() throws Exception {
|
public void test_64bit_vbt() throws Exception {
|
||||||
boolean is64Bit = true;
|
boolean is64Bit = true;
|
||||||
MyTestDummyDataTypeManager dtm = dtm64;
|
MyTestDummyDataTypeManager dtm = dtm64;
|
||||||
VxtManager vxtManager = msftVxtManager64;
|
MsftVxtManager vxtManager = vxtManager64;
|
||||||
List<String> expectedResults = new ArrayList<>();
|
List<String> expectedResults = new ArrayList<>();
|
||||||
expectedResults.add(getExpectedA_64());
|
expectedResults.add(getExpectedA_64());
|
||||||
expectedResults.add(getExpectedC_64());
|
expectedResults.add(getExpectedC_64());
|
||||||
|
@ -7123,7 +7123,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
|
||||||
public void test_64bit_speculative() throws Exception {
|
public void test_64bit_speculative() throws Exception {
|
||||||
boolean is64Bit = true;
|
boolean is64Bit = true;
|
||||||
MyTestDummyDataTypeManager dtm = dtm64;
|
MyTestDummyDataTypeManager dtm = dtm64;
|
||||||
VxtManager vxtManager = vxtManager64;
|
MsftVxtManager vxtManager = vxtManagerNoProgram64;
|
||||||
List<String> expectedResults = new ArrayList<>();
|
List<String> expectedResults = new ArrayList<>();
|
||||||
expectedResults.add(getSpeculatedA_64());
|
expectedResults.add(getSpeculatedA_64());
|
||||||
expectedResults.add(getSpeculatedC_64());
|
expectedResults.add(getSpeculatedC_64());
|
||||||
|
@ -7159,7 +7159,7 @@ public class CppCompositeTypeTest extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createAndTestStructures(boolean is64Bit, DataTypeManager dtm,
|
private void createAndTestStructures(boolean is64Bit, DataTypeManager dtm,
|
||||||
VxtManager vxtManager, List<String> expectedResults) throws Exception {
|
MsftVxtManager vxtManager, List<String> expectedResults) throws Exception {
|
||||||
|
|
||||||
Iterator<String> iter = expectedResults.iterator();
|
Iterator<String> iter = expectedResults.iterator();
|
||||||
String expected;
|
String expected;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.classtype;
|
package ghidra.program.model.gclass;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -21,10 +21,10 @@ import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.program.model.data.CategoryPath;
|
import ghidra.program.model.data.CategoryPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unique ID of a ProgramClassType. Not sure if there will be different implementation for
|
* Unique ID of a Program Class Type. Not sure if there will be different implementation for
|
||||||
* definition vs. compiled vs. program vs. debug. See ClassID.
|
* definition vs. compiled vs. program vs. debug.
|
||||||
*/
|
*/
|
||||||
public class ProgramClassID implements ClassID {
|
public class ClassID implements Comparable<ClassID> {
|
||||||
// All of the internals of this might change, but we need something to work with for now.
|
// All of the internals of this might change, but we need something to work with for now.
|
||||||
// It might end up being a hash/guid/long value.
|
// It might end up being a hash/guid/long value.
|
||||||
// We were trying to use DataTypePath, but that doesn't work in light of conflicts, as we
|
// We were trying to use DataTypePath, but that doesn't work in light of conflicts, as we
|
||||||
|
@ -32,14 +32,14 @@ public class ProgramClassID implements ClassID {
|
||||||
// DataTypePath changed out from underneath us).
|
// DataTypePath changed out from underneath us).
|
||||||
private final SymbolPath symbolPath;
|
private final SymbolPath symbolPath;
|
||||||
private final CategoryPath categoryPath;
|
private final CategoryPath categoryPath;
|
||||||
static final int classNameHash = Objects.hash(ProgramClassID.class.getName());
|
static final int classNameHash = Objects.hash(ClassID.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param categoryPath the category path for the claass
|
* @param categoryPath the category path for the claass
|
||||||
* @param symbolPath the symbol path for the class
|
* @param symbolPath the symbol path for the class
|
||||||
*/
|
*/
|
||||||
public ProgramClassID(CategoryPath categoryPath, SymbolPath symbolPath) {
|
public ClassID(CategoryPath categoryPath, SymbolPath symbolPath) {
|
||||||
this.categoryPath = categoryPath;
|
this.categoryPath = categoryPath;
|
||||||
this.symbolPath = symbolPath;
|
this.symbolPath = symbolPath;
|
||||||
}
|
}
|
||||||
|
@ -69,11 +69,6 @@ public class ProgramClassID implements ClassID {
|
||||||
// return dataTypeID;
|
// return dataTypeID;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getClassNameHash() {
|
|
||||||
return classNameHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("%s --- %s", categoryPath, symbolPath);
|
return String.format("%s --- %s", categoryPath, symbolPath);
|
||||||
|
@ -82,18 +77,11 @@ public class ProgramClassID implements ClassID {
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ClassID o) {
|
public int compareTo(ClassID o) {
|
||||||
int ret;
|
int ret;
|
||||||
if (!(o instanceof ProgramClassID oID)) {
|
ret = symbolPath.compareTo(o.symbolPath);
|
||||||
ret = getClassNameHash() - o.getClassNameHash();
|
|
||||||
if (ret != 0) {
|
|
||||||
throw new AssertionError("Logic problem with compareTo");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
ret = symbolPath.compareTo(oID.symbolPath);
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return categoryPath.compareTo(oID.categoryPath);
|
return categoryPath.compareTo(o.categoryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,7 +100,7 @@ public class ProgramClassID implements ClassID {
|
||||||
if (getClass() != obj.getClass()) {
|
if (getClass() != obj.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ProgramClassID other = (ProgramClassID) obj;
|
ClassID other = (ClassID) obj;
|
||||||
return Objects.equals(categoryPath, other.categoryPath) &&
|
return Objects.equals(categoryPath, other.categoryPath) &&
|
||||||
Objects.equals(symbolPath, other.symbolPath);
|
Objects.equals(symbolPath, other.symbolPath);
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.gclass;
|
package ghidra.program.model.gclass;
|
||||||
|
|
||||||
|
import ghidra.app.util.SymbolPath;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,6 +41,11 @@ public class ClassUtils {
|
||||||
*/
|
*/
|
||||||
public static final PointerDataType VXPTR_TYPE = new PointerDataType();
|
public static final PointerDataType VXPTR_TYPE = new PointerDataType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The standard prefix used for the special symbol. Private for now.
|
||||||
|
*/
|
||||||
|
private static final String VTABLE_PREFIX = "VTABLE_";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* private constructor -- no instances
|
* private constructor -- no instances
|
||||||
*/
|
*/
|
||||||
|
@ -54,8 +60,27 @@ public class ClassUtils {
|
||||||
*/
|
*/
|
||||||
public static CategoryPath getClassInternalsPath(Composite composite) {
|
public static CategoryPath getClassInternalsPath(Composite composite) {
|
||||||
DataTypePath dtp = composite.getDataTypePath();
|
DataTypePath dtp = composite.getDataTypePath();
|
||||||
return new CategoryPath(new CategoryPath(dtp.getCategoryPath(), dtp.getDataTypeName()),
|
return getClassInternalsPath(dtp.getCategoryPath(), dtp.getDataTypeName());
|
||||||
"!internal");
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the category for class internals for the ClassID
|
||||||
|
* @param id the class ID
|
||||||
|
* @return the category path
|
||||||
|
*/
|
||||||
|
public static CategoryPath getClassInternalsPath(ClassID id) {
|
||||||
|
CategoryPath cp = recurseGetCategoryPath(id.getCategoryPath(), id.getSymbolPath());
|
||||||
|
return cp.extend("!internal");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the category for class internals
|
||||||
|
* @param path the category path of the class composite
|
||||||
|
* @param className the name of the class
|
||||||
|
* @return the category path
|
||||||
|
*/
|
||||||
|
public static CategoryPath getClassInternalsPath(CategoryPath path, String className) {
|
||||||
|
return new CategoryPath(new CategoryPath(path, className), "!internal");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,4 +117,46 @@ public class ClassUtils {
|
||||||
return composite;
|
return composite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the standard special name for a virtual table (e.g., vbtable, vftable) that is
|
||||||
|
* keyed off of by the Decompiler during flattening and replacing of types within a class
|
||||||
|
* structure. More details to come
|
||||||
|
* @param ptrOffsetInClass the offset of the special field within the class
|
||||||
|
* @return the special name
|
||||||
|
*/
|
||||||
|
public static String getSpecialVxTableName(long ptrOffsetInClass) {
|
||||||
|
return String.format("%s%08x", VTABLE_PREFIX, ptrOffsetInClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataType getVftDefaultEntry(DataTypeManager dtm) {
|
||||||
|
return new PointerDataType(dtm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataType getVbtDefaultEntry(DataTypeManager dtm) {
|
||||||
|
return new IntegerDataType(dtm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getVftEntrySize(DataTypeManager dtm) {
|
||||||
|
return dtm.getDataOrganization().getPointerSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getVbtEntrySize(DataTypeManager dtm) {
|
||||||
|
return dtm.getDataOrganization().getIntegerSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get a category path from a base category path and symbol path
|
||||||
|
* @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 static CategoryPath recurseGetCategoryPath(CategoryPath category,
|
||||||
|
SymbolPath symbolPath) {
|
||||||
|
SymbolPath parent = symbolPath.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
category = recurseGetCategoryPath(category, parent);
|
||||||
|
}
|
||||||
|
return new CategoryPath(category, symbolPath.getName());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue