mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-1670 Fixed bug in a class recovery helper class that in some cases was causing an exception when trying to replace a component in a structure.
This commit is contained in:
parent
8546ff5274
commit
87d6ff4db3
4 changed files with 122 additions and 131 deletions
|
@ -226,55 +226,68 @@ class EditStructureUtils {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to add a field to the given structure. If the structure already has data
|
||||
* at the given offset, don't replace. If there is undefined data there then replace
|
||||
* it with the data type. If the structure empty, insert the data type at the given offset.
|
||||
* If the structure is not big enough and not-empty, grow it so there is room to replace.
|
||||
* See {@link #canAdd(Structure, int, int, TaskMonitor)} for ensuring operation will be
|
||||
* See {@link #canAdd(Structure, int, int, boolean, TaskMonitor)} for ensuring operation will be
|
||||
* successful.
|
||||
* @param structure the given structure
|
||||
* @param offset the offset to add a field
|
||||
* @param dataType the data type to add to the field at the given offset
|
||||
* @param fieldName the name of field
|
||||
* @param monitor task monitor
|
||||
* @return the updated structure data type
|
||||
* @throws IllegalArgumentException if issue inserting data type into structure
|
||||
* @return true if the structure was updated or false if the data could not be added
|
||||
* @throws IllegalArgumentException if issue inserting or replacing data type into structure
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
static Structure addDataTypeToStructure(Structure structure, int offset,
|
||||
DataType dataType, String fieldName, TaskMonitor monitor)
|
||||
throws CancelledException, IllegalArgumentException {
|
||||
static boolean addDataTypeToStructure(Structure structure, int offset, DataType dataType,
|
||||
String fieldName, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (structure.isPackingEnabled()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Packed structures are not supported by this method");
|
||||
}
|
||||
|
||||
if (!canAdd(structure, offset, dataType.getLength(), true, monitor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (structure.isZeroLength() || offset >= structure.getLength()) {
|
||||
structure.insertAtOffset(offset, dataType, -1, fieldName, null);
|
||||
}
|
||||
else {
|
||||
// if not enough room, grow the structure
|
||||
int roomForData = structure.getLength() - (offset + dataType.getLength());
|
||||
if (roomForData < 0) {
|
||||
structure.growStructure(-roomForData);
|
||||
}
|
||||
structure.replaceAtOffset(offset, dataType, -1, fieldName, null);
|
||||
}
|
||||
return structure;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to determine if the given structure has room at the given offset to have a component
|
||||
* of the given length added to it. This is only valid for non-packed structures.
|
||||
* @param structureDataType the given structure
|
||||
* @param offset the offset to check for available room
|
||||
* @param lengthToAdd the length of bytes wanted to add at the offset
|
||||
* @param isGrowthAllowed Whether true or false, adding is only allowed if no collision will
|
||||
* happen with existing defined components. If true, allows structure to be grown beyond its end
|
||||
* if necessary. If false, it does not allow structure to be grown.
|
||||
* @param monitor task monitor
|
||||
* @return true if the given structure has room at the given offset to have a component of the
|
||||
* given length added to it or if the offset is beyond the end of the structure so that the
|
||||
* structure can be grown
|
||||
* given length added to it or if the offset is beyond the end of the defined components in the
|
||||
* the structure so that the structure can be grown
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws IllegalArgumentException if a packed structure is passed in
|
||||
*/
|
||||
static boolean canAdd(Structure structureDataType, int offset, int lengthToAdd,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
boolean isGrowthAllowed, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (structureDataType.isPackingEnabled()) {
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -283,10 +296,22 @@ class EditStructureUtils {
|
|||
|
||||
DataTypeComponent component = structureDataType.getComponentContaining(offset);
|
||||
|
||||
// structure not big enough to contain the offset so return true so it can be grown
|
||||
// structure not big enough to contain the offset
|
||||
// if growStructure flag is true, return true so structure can be grown
|
||||
// if growStructure flag is false, return false since the offset does not exist so it would
|
||||
// be impossible to add anything at that offset
|
||||
if (component == null) {
|
||||
if (isGrowthAllowed) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// if growStructure flag is false and if offset + lengthToAdd is greater than length of
|
||||
// structure then return false
|
||||
if (!isGrowthAllowed && (structureDataType.getLength() < (offset + lengthToAdd))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the offset is in the middle of an internal component then return false
|
||||
if (component.getOffset() != offset) {
|
||||
|
|
|
@ -2857,14 +2857,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress);
|
||||
|
||||
// simple case the offset for vftablePtr is 0
|
||||
if (EditStructureUtils.canAdd(classStructureDataType, 0,
|
||||
classVftablePointer.getLength(),
|
||||
monitor)) {
|
||||
classStructureDataType =
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
|
||||
0, classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
|
||||
|
||||
}
|
||||
// if can fit or grow structure, add the vftablePtr to it
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType, 0,
|
||||
classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
|
||||
}
|
||||
// if single inheritance or multi non-virtual (wouldn't have called this method if
|
||||
// it were virtually inherited) put parent struct and data into class struct
|
||||
|
@ -2905,14 +2900,11 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
" : structure should exist but doesn't.");
|
||||
}
|
||||
|
||||
if (EditStructureUtils.canAdd(classStructureDataType, parentOffset,
|
||||
baseClassStructure.getLength(), monitor)) {
|
||||
classStructureDataType =
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
|
||||
parentOffset,
|
||||
// if it fits at offset or is at the end and class structure can be grown,
|
||||
// copy the whole baseClass structure to the class Structure at the given offset
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType, parentOffset,
|
||||
baseClassStructure, baseClassStructure.getName(), monitor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -2920,9 +2912,8 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
int dataOffset = getDataOffset(recoveredClass, classStructureDataType);
|
||||
int dataLen = UNKNOWN;
|
||||
if (dataOffset != NONE) {
|
||||
dataLen =
|
||||
EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType,
|
||||
dataOffset, monitor);
|
||||
dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(
|
||||
classStructureDataType, dataOffset, monitor);
|
||||
}
|
||||
|
||||
if (dataLen != UNKNOWN && dataLen > 0) {
|
||||
|
@ -2931,9 +2922,10 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
|||
classStructureDataType, dataLen, dataOffset);
|
||||
|
||||
if (recoveredClassDataStruct != null) {
|
||||
classStructureDataType = EditStructureUtils.addDataTypeToStructure(
|
||||
classStructureDataType,
|
||||
dataOffset, recoveredClassDataStruct, "data", monitor);
|
||||
// if it fits at offset or is at the end and class structure can be grown,
|
||||
// copy the whole baseClass structure to the class Structure at the given offset
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset,
|
||||
recoveredClassDataStruct, "data", monitor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1212,7 +1212,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
/**
|
||||
* Method to get class inheritance flag from the RTTIClassHierarchyDescriptor structure
|
||||
* @param classNamespace the given class namespace
|
||||
* @return the class inheritance flag
|
||||
* @return the class inheritance flag or NONE if there isn't one
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws MemoryAccessException if memory cannot be read
|
||||
* @throws AddressOutOfBoundsException if try reading memory out of bounds
|
||||
|
@ -1432,7 +1432,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
recoveredClass.addParentToBaseTypeMapping(baseClass, false);
|
||||
}
|
||||
else {
|
||||
|
||||
if (vbaseOffset == NONE) {
|
||||
vbaseOffset = pdisp;
|
||||
}
|
||||
|
@ -2247,7 +2246,6 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
* @return the created class structure data type
|
||||
* @throws Exception if invalid data creation
|
||||
*/
|
||||
//NEW
|
||||
private Structure createClassStructureUsingRTTI(RecoveredClass recoveredClass,
|
||||
Map<Address, DataType> vfPointerDataTypes) throws Exception {
|
||||
|
||||
|
@ -2353,40 +2351,31 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
recoveredClass.getVftableAddresses().size() > 1 &&
|
||||
recoveredClass.inheritsVirtualAncestor()) {
|
||||
|
||||
//NEW
|
||||
int offsetOfVirtualParent = getSingleVirtualParentOffset(baseClass);
|
||||
int virtParentOffset = getSingleVirtualParentOffset(baseClass);
|
||||
|
||||
int dataLength;
|
||||
if (offsetOfVirtualParent == NONE) {
|
||||
if (virtParentOffset == NONE) {
|
||||
dataLength = baseClassStructure.getLength();
|
||||
}
|
||||
else {
|
||||
int lengthOfVirtualParent =
|
||||
baseClassStructure.getLength() - offsetOfVirtualParent;
|
||||
dataLength = baseClassStructure.getLength() - lengthOfVirtualParent;
|
||||
int virtParentLength = baseClassStructure.getLength() - virtParentOffset;
|
||||
dataLength = baseClassStructure.getLength() - virtParentLength;
|
||||
}
|
||||
|
||||
if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset,
|
||||
dataLength,
|
||||
monitor)) {
|
||||
classStructureDataType =
|
||||
addIndividualComponentsToStructure(classStructureDataType,
|
||||
baseClassStructure, baseClassOffset, offsetOfVirtualParent);
|
||||
}
|
||||
// if there is room add the individual parts of the base class from the top of the
|
||||
// structure up to but not including the single virtual parent offset within
|
||||
// the class structure
|
||||
addIndividualComponentsToStructure(classStructureDataType, baseClassStructure,
|
||||
baseClassOffset, dataLength);
|
||||
continue;
|
||||
}
|
||||
|
||||
// else copy whole baseClass structure to the class Structure
|
||||
if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset,
|
||||
baseClassStructure.getLength(), monitor)) {
|
||||
classStructureDataType =
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
|
||||
baseClassOffset,
|
||||
// if it fits at offset or is at the end and class structure can be grown,
|
||||
// copy the whole baseClass structure to the class Structure at the given offset
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType, baseClassOffset,
|
||||
baseClassStructure, baseClassStructure.getName(), monitor);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
// else need to fill in the virtually inherited ones
|
||||
// get the offset of this base class in the class using the vbtable
|
||||
|
@ -2397,16 +2386,12 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
baseClassOffset = api.getInt(recoveredClass.getVbtableAddress().add(vdisp)) + pdisp;
|
||||
|
||||
if (EditStructureUtils.canAdd(classStructureDataType, baseClassOffset,
|
||||
baseClassStructure.getLength(), monitor)) {
|
||||
|
||||
classStructureDataType =
|
||||
// if it fits at offset or is at the end and class structure can be grown,
|
||||
// copy the whole baseClass structure to the class Structure at the given offset
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
|
||||
baseClassOffset,
|
||||
baseClassStructure, baseClassStructure.getName(), monitor);
|
||||
baseClassOffset, baseClassStructure, baseClassStructure.getName(), monitor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}// end of base class array
|
||||
|
||||
|
@ -2430,13 +2415,10 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
DataType classVftablePointer = vfPointerDataTypes.get(vftableAddress);
|
||||
|
||||
if (EditStructureUtils.canAdd(classStructureDataType, offset.intValue(),
|
||||
classVftablePointer.getLength(), monitor)) {
|
||||
classStructureDataType = EditStructureUtils.addDataTypeToStructure(
|
||||
classStructureDataType,
|
||||
// if it fits at offset or is at the end and class structure can be grown,
|
||||
// copy the whole baseClass structure to the class Structure at the given offset
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
|
||||
offset.intValue(), classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// add the vbtable structure for single inheritance/virt parent case
|
||||
|
@ -2445,13 +2427,11 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
addVbtableToClassStructure(recoveredClass, classStructureDataType, false);
|
||||
}
|
||||
|
||||
//NEW
|
||||
int dataOffset = getDataOffset(recoveredClass, classStructureDataType);
|
||||
int dataLen = UNKNOWN;
|
||||
if (dataOffset != NONE) {
|
||||
dataLen =
|
||||
EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(classStructureDataType,
|
||||
dataOffset, monitor);
|
||||
dataLen = EditStructureUtils.getNumberOfUndefinedsStartingAtOffset(
|
||||
classStructureDataType, dataOffset, monitor);
|
||||
}
|
||||
|
||||
if (dataLen != UNKNOWN && dataLen > 0) {
|
||||
|
@ -2460,23 +2440,22 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
classStructureDataType, dataLen, dataOffset);
|
||||
|
||||
if (recoveredClassDataStruct != null) {
|
||||
classStructureDataType =
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
|
||||
dataOffset, recoveredClassDataStruct,
|
||||
classStructureDataType.getName() + "_data", monitor);
|
||||
// if it fits at offset or is at the end and class structure can be grown,
|
||||
// copy the whole baseClass structure to the class Structure at the given offset
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType, dataOffset,
|
||||
recoveredClassDataStruct, classStructureDataType.getName() + "_data", monitor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//NEW:
|
||||
classStructureDataType =
|
||||
addClassVftables(classStructureDataType, recoveredClass, vfPointerDataTypes);
|
||||
|
||||
//NEW:
|
||||
classStructureDataType =
|
||||
addVbtableToClassStructure(recoveredClass, classStructureDataType, true);
|
||||
|
||||
if (classStructureDataType.getNumComponents() == classStructureDataType.getNumDefinedComponents()) {
|
||||
if (classStructureDataType.getNumComponents() == classStructureDataType
|
||||
.getNumDefinedComponents()) {
|
||||
classStructureDataType.setPackingEnabled(true);
|
||||
}
|
||||
|
||||
|
@ -2491,8 +2470,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
/**
|
||||
* Method to return the offset of the given class's single virtual parent
|
||||
* @param recoveredClass the given class
|
||||
* @return the offset of the single virtual parent or null if there is not a single virtual parent
|
||||
* or if there is no mapping in the offset map for that parent
|
||||
* @return the offset in the given class structure of the classes single virtual parent or NONE
|
||||
* if cannot retrieve an offset value or if there is not a single virtual parent for the given
|
||||
* class.
|
||||
* @throws CancelledException if cancelled
|
||||
* @throws AddressOutOfBoundsException if trying to access an address that does not exist in program
|
||||
* @throws MemoryAccessException if trying to access memory that can't be accessed
|
||||
|
@ -2502,7 +2482,7 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
|||
|
||||
List<RecoveredClass> virtualParentClasses = getVirtualParentClasses(recoveredClass);
|
||||
if (virtualParentClasses.size() != 1) {
|
||||
return null;
|
||||
return NONE;
|
||||
}
|
||||
|
||||
Map<RecoveredClass, Integer> parentOffsetMap = getBaseClassOffsetMap(recoveredClass);
|
||||
|
|
|
@ -5489,36 +5489,39 @@ public class RecoveredClassHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* Method to add the given structcure component to the given structure at the given offset
|
||||
* @param structureDataType the structure to add to
|
||||
* @param structureToAdd the structure to add
|
||||
* @param startOffset the starting offset where to add
|
||||
* @param endOffset the ending offset of the added structure
|
||||
* @return the updated structure
|
||||
* Method to add the structure components from the given structureToAdd from the given starting
|
||||
* offset to the given ending offset of the to the given structure at the given offset
|
||||
* @param structure the structure to add to
|
||||
* @param structureToAdd the structure to add a subset of components from to the given structure
|
||||
* @param startOffset the starting offset of where to start adding in the container structure
|
||||
* @param dataLength the total length of the data components to add
|
||||
* @return true if the structure was updated or false if the components cannot be added
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public Structure addIndividualComponentsToStructure(Structure structureDataType,
|
||||
Structure structureToAdd, int startOffset, int endOffset) throws CancelledException {
|
||||
public boolean addIndividualComponentsToStructure(Structure structure, Structure structureToAdd,
|
||||
int startOffset, int dataLength) throws CancelledException {
|
||||
|
||||
DataTypeComponent[] definedComponents = structureToAdd.getDefinedComponents();
|
||||
for (int ii = 0; ii < definedComponents.length; ii++) {
|
||||
// this check does not allow growing of structure. It only allows adding to the structure if
|
||||
// the block of components to add will fit at the given offset
|
||||
if (!EditStructureUtils.canAdd(structure, startOffset, dataLength, false,
|
||||
monitor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (DataTypeComponent dataTypeComponent : structureToAdd.getDefinedComponents()) {
|
||||
|
||||
monitor.checkCanceled();
|
||||
|
||||
DataTypeComponent dataTypeComponent = structureToAdd.getComponent(ii);
|
||||
|
||||
int dataComponentOffset = dataTypeComponent.getOffset();
|
||||
if (endOffset != NONE && (dataComponentOffset + startOffset) >= endOffset) {
|
||||
return structureDataType;
|
||||
// only copy the components up to the given total dataLength to copy
|
||||
if ((dataTypeComponent.getOffset() + dataTypeComponent.getLength()) > dataLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
String fieldname = dataTypeComponent.getFieldName();
|
||||
|
||||
structureDataType = EditStructureUtils.addDataTypeToStructure(structureDataType,
|
||||
startOffset + dataComponentOffset, dataTypeComponent.getDataType(), fieldname,
|
||||
monitor);
|
||||
structure.replaceAtOffset(startOffset + dataTypeComponent.getOffset(),
|
||||
dataTypeComponent.getDataType(), -1, dataTypeComponent.getFieldName(),
|
||||
dataTypeComponent.getComment());
|
||||
}
|
||||
return structureDataType;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -6193,7 +6196,7 @@ public class RecoveredClassHelper {
|
|||
* Method to retrieve the offset of the class data in the given structure
|
||||
* @param recoveredClass the given class
|
||||
* @param structure the given structure
|
||||
* @return the offset of the class data in the given structure
|
||||
* @return the offset of the class data in the given structure or NONE if there isn't one
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
public int getDataOffset(RecoveredClass recoveredClass, Structure structure)
|
||||
|
@ -8204,22 +8207,17 @@ public class RecoveredClassHelper {
|
|||
|
||||
monitor.checkCanceled();
|
||||
|
||||
// if enough empty bytes - add class vftable pointer
|
||||
if (EditStructureUtils.canAdd(classStructureDataType, vftableOffset,
|
||||
classVftablePointer.getLength(), monitor)) {
|
||||
|
||||
classStructureDataType =
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
|
||||
vftableOffset,
|
||||
// if enough empty bytes or can grow the structure - add class vftable pointer
|
||||
boolean addedToStructure =
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType, vftableOffset,
|
||||
classVftablePointer, CLASS_VTABLE_PTR_FIELD_EXT, monitor);
|
||||
|
||||
if (addedToStructure) {
|
||||
addedVftablePointer = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if already has a base class vftable pointer replace with main class vftablePtr
|
||||
// get the item at that location
|
||||
//NEW: replaced with get containing
|
||||
// if offset is in the middle, get the top of the component
|
||||
DataTypeComponent currentComponent =
|
||||
classStructureDataType.getComponentContaining(vftableOffset);
|
||||
|
@ -8298,16 +8296,12 @@ public class RecoveredClassHelper {
|
|||
|
||||
DataType vbaseStructPointer = dataTypeManager.getPointer(vbtableStructure);
|
||||
|
||||
int dataLength = vbaseStructPointer.getLength();
|
||||
if (EditStructureUtils.canAdd(classStructureDataType, vbtableOffset, dataLength,
|
||||
monitor)) {
|
||||
|
||||
classStructureDataType =
|
||||
EditStructureUtils.addDataTypeToStructure(classStructureDataType,
|
||||
vbtableOffset, vbaseStructPointer, VBTABLE_PTR, monitor);
|
||||
|
||||
}
|
||||
else if (overwrite) {
|
||||
// if it fits at offset or is at the end and class structure can be grown,
|
||||
// copy the whole baseClass structure to the class Structure at the given offset
|
||||
boolean addedToStructure = EditStructureUtils.addDataTypeToStructure(
|
||||
classStructureDataType, vbtableOffset, vbaseStructPointer, VBTABLE_PTR, monitor);
|
||||
if (!addedToStructure && overwrite && classStructureDataType
|
||||
.getLength() >= (vbtableOffset + vbaseStructPointer.getLength())) {
|
||||
classStructureDataType.replaceAtOffset(vbtableOffset, vbaseStructPointer,
|
||||
vbaseStructPointer.getLength(), VBTABLE_PTR, "");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue