mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
Merge remote-tracking branch
'origin/GP-656_jmlagor_Process_pointers,_function_pointers,_mark_up_valuetypes_and_custommods--SQUASHED' Conflicts: Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/streams/CliStreamMetadata.java
This commit is contained in:
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -107,12 +107,12 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
ELEMENT_TYPE_VALUETYPE(0x11),
|
||||
ELEMENT_TYPE_VAR(0x13), // "Class type variable VAR"
|
||||
(0x16),
|
||||
|
||||
|
||||
ELEMENT_TYPE_MVAR(0x1e), // Method type variable MVAR
|
||||
|
||||
|
||||
ELEMENT_TYPE_INTERNAL(0x21), // Internal (generated internally, "will not be persisted in any way")
|
||||
ELEMENT_TYPE_MAX(0x22),
|
||||
|
||||
|
||||
*/
|
||||
|
||||
switch (typeCode) {
|
||||
@@ -431,32 +431,95 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
}
|
||||
|
||||
public class CliTypeFnPtr extends CliSigType {
|
||||
private CliAbstractSig sig;
|
||||
private boolean isDefSig; // true => MethodDef, false => MethodRef
|
||||
private long dataOffset;
|
||||
|
||||
private CliRetType retType;
|
||||
private CliParam params[];
|
||||
private int sizeOfCount;
|
||||
private byte flags;
|
||||
private int genericParamCount;
|
||||
private int sizeOfGenericCount;
|
||||
|
||||
private int sentinelIndex; // SENTINEL is before the parameter index in this field
|
||||
|
||||
private final int FNPTR_FLAGS_DEFAULT = 0x00;
|
||||
private final int FNPTR_FLAGS_VARARG = 0x05;
|
||||
private final int FNPTR_FLAGS_GENERIC = 0x10;
|
||||
private final int FNPTR_FLAGS_HASTHIS = 0x20;
|
||||
private final int FNPTR_FLAGS_EXPLICITTHIS = 0x40;
|
||||
|
||||
public CliTypeFnPtr(BinaryReader reader, CliElementType typeCode) throws IOException {
|
||||
super(typeCode);
|
||||
// TODO: MethodDef and MethodRef sig need to have static isX(reader) methods so I can tell the difference
|
||||
//sig = new CliSigMethodRef(blob); // MethodRef is just Def plus possible sentinel and minus potential XORed args in the first byte
|
||||
|
||||
sentinelIndex = -1;
|
||||
|
||||
dataOffset = reader.getPointerIndex();
|
||||
|
||||
// Flags is similar to a MethodDef unless vararg is used.
|
||||
flags = reader.readNextByte();
|
||||
|
||||
if ((flags & FNPTR_FLAGS_GENERIC) == FNPTR_FLAGS_GENERIC) {
|
||||
long origIndex = reader.getPointerIndex();
|
||||
genericParamCount = decodeCompressedUnsignedInt(reader);
|
||||
sizeOfGenericCount = (int) (reader.getPointerIndex() - origIndex);
|
||||
}
|
||||
|
||||
long origIndex = reader.getPointerIndex();
|
||||
int paramCount = decodeCompressedUnsignedInt(reader);
|
||||
this.sizeOfCount = (int) (reader.getPointerIndex() - origIndex);
|
||||
|
||||
try {
|
||||
retType = new CliRetType(reader);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
retType = null;
|
||||
}
|
||||
params = new CliParam[paramCount];
|
||||
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
if (reader.peekNextByte() == CliElementType.ELEMENT_TYPE_SENTINEL.id()) {
|
||||
reader.readNextByte();
|
||||
sentinelIndex = i;
|
||||
}
|
||||
try {
|
||||
params[i] = new CliParam(reader);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
params[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation() {
|
||||
return "FnPtr " + sig.getRepresentation();
|
||||
return "FnPtr " /*+ sig.getRepresentation()*/;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortRepresentation() {
|
||||
return "FnPtr " + sig.getShortRepresentation();
|
||||
return "FnPtr " /*+ sig.getShortRepresentation()*/;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDefinitionDataType() {
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), "FnPtr", 0);
|
||||
struct.add(CliTypeCodeDataType.dataType, "FnPtr", "FnPtr");
|
||||
struct.add(DWORD, "MethodDefOrRef", "index into blob heap");
|
||||
StructureDataType struct =
|
||||
new StructureDataType(new CategoryPath(PATH), "FnPtr_" + dataOffset, 0);
|
||||
struct.add(CliTypeCodeDataType.dataType, CliElementType.ELEMENT_TYPE_FNPTR.toString(),
|
||||
"");
|
||||
struct.add(BYTE, "Flags", "ORed VARARG/GENERIC/HASTHIS/EXPLICITTHIS");
|
||||
|
||||
if (genericParamCount > 0) {
|
||||
struct.add(getDataTypeForBytes(sizeOfGenericCount), "GenParamCount",
|
||||
"Number of generic paramameters for the method");
|
||||
}
|
||||
struct.add(getDataTypeForBytes(sizeOfCount), "ParamCount",
|
||||
"Number of parameter types to follow RetType");
|
||||
struct.add(retType.getDefinitionDataType(), "RetType", null);
|
||||
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
struct.add(params[i].getDefinitionDataType(), "Param" + i, null);
|
||||
}
|
||||
return struct;
|
||||
// TODO: Return the correct size of a signature reference (always 4B in this context perchance?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,17 +615,18 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
}
|
||||
|
||||
public class CliTypeVarOrMvar extends CliSigType {
|
||||
private long dataOffset;
|
||||
private int number;
|
||||
private int numberBytes;
|
||||
|
||||
public CliTypeVarOrMvar(BinaryReader reader, CliElementType typeCode) throws IOException {
|
||||
super(typeCode);
|
||||
|
||||
long origIndex = reader.getPointerIndex();
|
||||
dataOffset = reader.getPointerIndex();
|
||||
number = decodeCompressedUnsignedInt(reader);
|
||||
|
||||
long endIndex = reader.getPointerIndex();
|
||||
numberBytes = (int) (endIndex - origIndex);
|
||||
numberBytes = (int) (endIndex - dataOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -572,9 +636,9 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
|
||||
@Override
|
||||
public DataType getDefinitionDataType() {
|
||||
StructureDataType struct =
|
||||
new StructureDataType(new CategoryPath(PATH), "VarOrMvar", 0);
|
||||
struct.add(BYTE, "Type", "Var or Mvar");
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH),
|
||||
baseTypeCode.toString() + "_" + dataOffset, 0);
|
||||
struct.add(CliTypeCodeDataType.dataType, baseTypeCode.toString(), "");
|
||||
struct.add(getDataTypeForBytes(numberBytes), "number", null);
|
||||
return struct;
|
||||
}
|
||||
@@ -582,16 +646,24 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
|
||||
public class CliTypePtr extends CliSigType {
|
||||
private List<CliCustomMod> customMods = new ArrayList<>();
|
||||
private CliElementType typeCode;
|
||||
private CliSigType type;
|
||||
private long dataOffset;
|
||||
|
||||
public CliTypePtr(BinaryReader reader, CliElementType typeCode) throws IOException {
|
||||
public CliTypePtr(BinaryReader reader, CliElementType typeCode)
|
||||
throws IOException, InvalidInputException {
|
||||
super(typeCode);
|
||||
|
||||
dataOffset = reader.getPointerIndex();
|
||||
|
||||
while (CliCustomMod.isCustomMod(reader)) {
|
||||
customMods.add(new CliCustomMod(reader));
|
||||
}
|
||||
|
||||
typeCode = CliElementType.fromInt(reader.readNextByte());
|
||||
type = readCliType(reader);
|
||||
}
|
||||
|
||||
public CliSigType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -601,17 +673,22 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
modsRep += mod.toString() + ", ";
|
||||
}
|
||||
modsRep = modsRep.substring(0, modsRep.length() - 2);
|
||||
return String.format("Ptr %s %s", modsRep, typeCode.toString());
|
||||
return String.format("Ptr %s %s", modsRep, type.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDefinitionDataType() {
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), "Ptr", 0);
|
||||
struct.add(CliTypeCodeDataType.dataType, "TypeCode", "Ptr");
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH),
|
||||
CliElementType.ELEMENT_TYPE_PTR.toString() + "_" + dataOffset, 0);
|
||||
struct.add(CliTypeCodeDataType.dataType, CliElementType.ELEMENT_TYPE_PTR.toString(),
|
||||
"");
|
||||
|
||||
for (CliCustomMod mod : customMods) {
|
||||
struct.add(mod.getDefinitionDataType());
|
||||
}
|
||||
struct.add(CliTypeCodeDataType.dataType, "Type", "type or void");
|
||||
|
||||
struct.add(type.getDefinitionDataType(), type.baseTypeCode.toString(), "");
|
||||
|
||||
return struct;
|
||||
}
|
||||
}
|
||||
@@ -682,6 +759,19 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
typeBytes = (int) (endIndex - origIndex);
|
||||
}
|
||||
|
||||
public CliTypeTable getTable() {
|
||||
try {
|
||||
return CliIndexTypeDefOrRef.getTableName(encodedType);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getRowIndex() {
|
||||
return CliIndexTypeDefOrRef.getRowIndex(encodedType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation() {
|
||||
return "ValueType " + Integer.toHexString(encodedType);
|
||||
@@ -714,12 +804,17 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
|
||||
@Override
|
||||
public DataType getDefinitionDataType() {
|
||||
String tableName = getTable().name();
|
||||
|
||||
StructureDataType struct =
|
||||
new StructureDataType(new CategoryPath(PATH), "ValueType", 0);
|
||||
struct.add(CliTypeCodeDataType.dataType, "ValueType", "ValueType");
|
||||
struct.add(getDataTypeForBytes(typeBytes), "Type", "TypeDefOrRefOrSpecEncoded");
|
||||
struct.add(getDataTypeForBytes(typeBytes), "TypeDefOrRefEncoded",
|
||||
tableName + ": Row 0x" + Integer.toHexString(getRowIndex()));
|
||||
|
||||
return struct;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public CliSigType readCliType(BinaryReader reader) throws IOException, InvalidInputException {
|
||||
@@ -761,10 +856,11 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
}
|
||||
}
|
||||
|
||||
// The CustomMod signature part contains a required CMOD option (CMOD_OPT or CMOD_REQD) then a compressed TypeDefOrRefOrSpecEncoded
|
||||
public static class CliCustomMod {
|
||||
// The CustomMod signature part contains a required CMOD
|
||||
// option (CMOD_OPT or CMOD_REQD) then a compressed TypeDefOrRefOrSpecEncoded
|
||||
public static class CliCustomMod implements CliRepresentable {
|
||||
private CliElementType cmod;
|
||||
private int typeEncoded;
|
||||
private int encodedType;
|
||||
private int sizeOfCount;
|
||||
|
||||
public static boolean isCustomMod(BinaryReader reader) throws IOException {
|
||||
@@ -776,7 +872,7 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
cmod = CliElementType.fromInt(reader.readNextByte());
|
||||
|
||||
long origIndex = reader.getPointerIndex();
|
||||
typeEncoded = decodeCompressedUnsignedInt(reader);
|
||||
encodedType = decodeCompressedUnsignedInt(reader);
|
||||
|
||||
long endIndex = reader.getPointerIndex();
|
||||
sizeOfCount = (int) (endIndex - origIndex);
|
||||
@@ -787,12 +883,12 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
}
|
||||
|
||||
public int getTypeEncoded() {
|
||||
return typeEncoded;
|
||||
return encodedType;
|
||||
}
|
||||
|
||||
public CliTypeTable getTable() {
|
||||
try {
|
||||
return CliIndexTypeDefOrRef.getTableName(typeEncoded);
|
||||
return CliIndexTypeDefOrRef.getTableName(encodedType);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
return null;
|
||||
@@ -800,7 +896,7 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
}
|
||||
|
||||
public int getRowIndex() {
|
||||
return CliIndexTypeDefOrRef.getRowIndex(typeEncoded);
|
||||
return CliIndexTypeDefOrRef.getRowIndex(encodedType);
|
||||
}
|
||||
|
||||
public CliAbstractTableRow getRow(CliStreamMetadata stream) {
|
||||
@@ -808,25 +904,40 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
}
|
||||
|
||||
public DataType getDefinitionDataType() {
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH),
|
||||
CliCustomMod.class.getSimpleName(), 0);
|
||||
struct.add(BYTE, "CMOD", "CMOD_OPT or CMOD_REQD");
|
||||
struct.add(getDataTypeForBytes(this.sizeOfCount), "Type",
|
||||
"TypeDefOrRefOrSpec encoded type");
|
||||
StructureDataType struct =
|
||||
new StructureDataType(new CategoryPath(PATH), "CustomMod", 0);
|
||||
|
||||
String tableName = getTable().name();
|
||||
|
||||
struct.add(CliTypeCodeDataType.dataType, cmod.toString(), null);
|
||||
struct.add(getDataTypeForBytes(this.sizeOfCount), "TypeDefOrRefEncoded",
|
||||
tableName + ": Row 0x" + Integer.toHexString(getRowIndex()));
|
||||
return struct;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation(CliStreamMetadata stream) {
|
||||
return String.format("%s %s", cmod.toString(), getRow(stream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation() {
|
||||
return String.format("%s %x", cmod.toString(), typeEncoded);
|
||||
return String.format("%s %x", cmod.toString(), encodedType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortRepresentation() {
|
||||
return getRepresentation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortRepresentation(CliStreamMetadata stream) {
|
||||
return getRepresentation(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// The only possible constraint is ELEMENT_TYPE_PINNED (CliTypeCode.Pinned)
|
||||
public static class CliConstraint {
|
||||
public static class CliConstraint implements CliRepresentable {
|
||||
private CliElementType constraint;
|
||||
|
||||
public static boolean isConstraint(BinaryReader reader) throws IOException {
|
||||
@@ -841,6 +952,7 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
return constraint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation() {
|
||||
if (constraint == CliElementType.ELEMENT_TYPE_PINNED) {
|
||||
return constraint.toString();
|
||||
@@ -848,36 +960,96 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
return String.format("Invalid Constraint (%s - %x)", constraint.toString(),
|
||||
constraint.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortRepresentation() {
|
||||
return getRepresentation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation(CliStreamMetadata stream) {
|
||||
return getRepresentation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortRepresentation(CliStreamMetadata stream) {
|
||||
return getRepresentation();
|
||||
}
|
||||
}
|
||||
|
||||
// The only possible result is ELEMENT_TYPE_BYREF
|
||||
public static class CliByRef implements CliRepresentable {
|
||||
private CliElementType byRef;
|
||||
|
||||
public static boolean isByRef(BinaryReader reader) throws IOException {
|
||||
return (reader.peekNextByte() == CliElementType.ELEMENT_TYPE_BYREF.id());
|
||||
}
|
||||
|
||||
public CliByRef(BinaryReader reader) throws IOException {
|
||||
byRef = CliElementType.fromInt(reader.readNextByte());
|
||||
}
|
||||
|
||||
public CliElementType getByRef() {
|
||||
return byRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation() {
|
||||
if (byRef == CliElementType.ELEMENT_TYPE_BYREF) {
|
||||
return byRef.toString();
|
||||
}
|
||||
return String.format("Invalid ByRef (%s - %x)", byRef.toString(), byRef.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortRepresentation() {
|
||||
return getRepresentation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation(CliStreamMetadata stream) {
|
||||
return getRepresentation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortRepresentation(CliStreamMetadata stream) {
|
||||
return getRepresentation();
|
||||
}
|
||||
}
|
||||
|
||||
public class CliTypeBase implements CliRepresentable {
|
||||
private List<CliCustomMod> customMods = new ArrayList<>();
|
||||
private boolean constraint = false;
|
||||
private boolean byRef = false;
|
||||
private List<CliRepresentable> modifiers = new ArrayList<>();
|
||||
|
||||
private CliSigType type;
|
||||
|
||||
private long dataOffset = 0;
|
||||
private boolean isVoidAllowed = false;
|
||||
|
||||
public CliTypeBase(BinaryReader reader, boolean isRetType)
|
||||
throws IOException, InvalidInputException {
|
||||
dataOffset = reader.getPointerIndex();
|
||||
|
||||
this.isVoidAllowed = isRetType;
|
||||
|
||||
// Get any custom modifiers
|
||||
while (CliCustomMod.isCustomMod(reader)) {
|
||||
customMods.add(new CliCustomMod(reader));
|
||||
}
|
||||
// Check for any of the modifiers, which can repeat out of order
|
||||
// before encountering the base type
|
||||
while (CliCustomMod.isCustomMod(reader) || CliConstraint.isConstraint(reader) ||
|
||||
CliByRef.isByRef(reader)) {
|
||||
|
||||
// Check to see if it's a constrained variable
|
||||
if (CliConstraint.isConstraint(reader)) {
|
||||
constraint = true;
|
||||
reader.readNextByte();
|
||||
}
|
||||
// Get any custom modifiers
|
||||
while (CliCustomMod.isCustomMod(reader)) {
|
||||
modifiers.add(new CliCustomMod(reader));
|
||||
}
|
||||
|
||||
// Check to see if it's a ByRef
|
||||
byte byRefCheck = reader.peekNextByte();
|
||||
if (byRefCheck == CliElementType.ELEMENT_TYPE_BYREF.id()) {
|
||||
byRef = true;
|
||||
reader.readNextByte();
|
||||
// Check to see if it's a constrained variable
|
||||
if (CliConstraint.isConstraint(reader)) {
|
||||
modifiers.add(new CliConstraint(reader));
|
||||
}
|
||||
|
||||
// Check to see if it's a ByRef
|
||||
if (CliByRef.isByRef(reader)) {
|
||||
modifiers.add(new CliByRef(reader));
|
||||
}
|
||||
}
|
||||
|
||||
type = readCliType(reader);
|
||||
@@ -888,34 +1060,48 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
}
|
||||
|
||||
public List<CliCustomMod> getCustomMods() {
|
||||
List<CliCustomMod> customMods = new ArrayList<CliCustomMod>();
|
||||
for (CliRepresentable mod : modifiers) {
|
||||
if (mod instanceof CliCustomMod) {
|
||||
customMods.add((CliCustomMod) mod);
|
||||
}
|
||||
}
|
||||
|
||||
return customMods;
|
||||
}
|
||||
|
||||
public boolean isByRef() {
|
||||
return byRef;
|
||||
for (CliRepresentable mod : modifiers) {
|
||||
if (mod instanceof CliByRef) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isConstrained() {
|
||||
return constraint;
|
||||
for (CliRepresentable mod : modifiers) {
|
||||
if (mod instanceof CliConstraint) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getRepresentationCommon(CliStreamMetadata stream, boolean shortRep) {
|
||||
String rep = "";
|
||||
|
||||
for (CliCustomMod mod : customMods) {
|
||||
rep += mod.getRepresentation() + "; ";
|
||||
}
|
||||
|
||||
if (customMods.size() > 0) {
|
||||
rep = rep.substring(0, rep.length() - 2) + " ";
|
||||
}
|
||||
|
||||
if (constraint) {
|
||||
rep += "constrained ";
|
||||
}
|
||||
|
||||
if (byRef) {
|
||||
rep += "byref ";
|
||||
for (CliRepresentable mod : modifiers) {
|
||||
if (mod instanceof CliCustomMod) {
|
||||
CliCustomMod customMod = (CliCustomMod) mod;
|
||||
rep += customMod.getRepresentation() + "; ";
|
||||
}
|
||||
else if (mod instanceof CliConstraint) {
|
||||
rep += "constrained ";
|
||||
}
|
||||
else if (mod instanceof CliByRef) {
|
||||
rep += "byref ";
|
||||
}
|
||||
}
|
||||
|
||||
// The one special case value we have is the SENTINEL, which
|
||||
@@ -952,20 +1138,25 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
|
||||
}
|
||||
|
||||
public DataType getDefinitionDataType() {
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), "Type", 0);
|
||||
StructureDataType struct =
|
||||
new StructureDataType(new CategoryPath(PATH), "Type_" + dataOffset, 0);
|
||||
|
||||
for (CliCustomMod mod : customMods) {
|
||||
struct.add(mod.getDefinitionDataType(), "CustomMod", null);
|
||||
for (CliRepresentable mod : modifiers) {
|
||||
if (mod instanceof CliCustomMod) {
|
||||
CliCustomMod customMod = (CliCustomMod) mod;
|
||||
struct.add(customMod.getDefinitionDataType(), "CustomMod", null);
|
||||
}
|
||||
else if (mod instanceof CliConstraint) {
|
||||
struct.add(CliTypeCodeDataType.dataType,
|
||||
CliElementType.ELEMENT_TYPE_PINNED.toString(), "Constrained");
|
||||
}
|
||||
else if (mod instanceof CliByRef) {
|
||||
struct.add(CliTypeCodeDataType.dataType,
|
||||
CliElementType.ELEMENT_TYPE_BYREF.toString(), "By Reference");
|
||||
}
|
||||
}
|
||||
|
||||
if (constraint) {
|
||||
struct.add(BYTE, "CONSTRAINT", "Constrained");
|
||||
}
|
||||
|
||||
if (byRef) {
|
||||
struct.add(BYTE, "BYREF", "By reference");
|
||||
}
|
||||
struct.add(type.getDefinitionDataType(), "Type", null);
|
||||
struct.add(type.getDefinitionDataType(), type.baseTypeCode.toString(), null);
|
||||
return struct;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,14 @@ import ghidra.util.exception.InvalidInputException;
|
||||
public class CliSigField extends CliAbstractSig {
|
||||
private CliParam type;
|
||||
|
||||
private long dataOffset;
|
||||
private static final byte CLISIGFIELD_PROLOG = 0x06;
|
||||
|
||||
public CliSigField(CliBlob blob) throws IOException {
|
||||
super(blob);
|
||||
|
||||
BinaryReader reader = getContentsReader();
|
||||
dataOffset = reader.getPointerIndex();
|
||||
|
||||
byte prolog = reader.readNextByte();
|
||||
if (prolog != CLISIGFIELD_PROLOG) {
|
||||
@@ -67,7 +69,7 @@ public class CliSigField extends CliAbstractSig {
|
||||
public DataType getContentsDataType() {
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), getName(), 0);
|
||||
struct.add(BYTE, "FIELD", "Magic (0x06)");
|
||||
struct.add(type.getDefinitionDataType(), "Type", null);
|
||||
struct.add(type.getDefinitionDataType(), type.getType().baseTypeCode.toString(), null);
|
||||
return struct;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,17 +85,19 @@ public class CliSigMethodDef extends CliAbstractSig {
|
||||
@Override
|
||||
public DataType getContentsDataType() {
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), getName(), 0);
|
||||
struct.add(BYTE, "flags", "ORed calling convention and THIS presence"); // TODO: enum
|
||||
struct.add(BYTE, "Flags", "ORed VARARG/GENERIC/HASTHIS/EXPLICITTHIS"); // TODO: enum
|
||||
if (genericParamCount > 0) {
|
||||
struct.add(getDataTypeForBytes(sizeOfGenericCount), "GenParamCount",
|
||||
"Number of generic paramameters for the method");
|
||||
}
|
||||
struct.add(getDataTypeForBytes(sizeOfCount), "Count",
|
||||
"Number of param types to follow RetType");
|
||||
"Number of parameter types to follow RetType");
|
||||
struct.add(retType.getDefinitionDataType(), "RetType", null);
|
||||
for (CliParam param : params) {
|
||||
struct.add(param.getDefinitionDataType(), null, null);
|
||||
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
struct.add(params[i].getDefinitionDataType(), "Param" + i, null);
|
||||
}
|
||||
|
||||
return struct;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
public class CliSigMethodRef extends CliAbstractSig {
|
||||
|
||||
private long dataOffset;
|
||||
private CliRetType retType;
|
||||
private CliParam params[];
|
||||
private int sizeOfCount;
|
||||
@@ -45,6 +45,8 @@ public class CliSigMethodRef extends CliAbstractSig {
|
||||
|
||||
// Flags is similar to a MethodDef unless vararg is used.
|
||||
BinaryReader reader = getContentsReader();
|
||||
dataOffset = reader.getPointerIndex();
|
||||
|
||||
flags = reader.readNextByte();
|
||||
|
||||
if ((flags & METHODREFSIG_FLAGS_GENERIC) == METHODREFSIG_FLAGS_GENERIC) {
|
||||
@@ -90,16 +92,21 @@ public class CliSigMethodRef extends CliAbstractSig {
|
||||
@Override
|
||||
public DataType getContentsDataType() {
|
||||
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), getName(), 0);
|
||||
struct.add(BYTE, "FirstByte", "ORed VARARG and HASTHIS/EXPLICITTHIS");
|
||||
struct.add(BYTE, "Flags", "ORed VARARG/GENERIC/HASTHIS/EXPLICITTHIS");
|
||||
if (genericParamCount > 0) {
|
||||
struct.add(getDataTypeForBytes(sizeOfGenericCount), "GenParamCount",
|
||||
"Number of generic paramameters for the method");
|
||||
}
|
||||
struct.add(getDataTypeForBytes(sizeOfCount), "ParamCount",
|
||||
"Number of param types to follow RetType");
|
||||
"Number of parameter types to follow RetType");
|
||||
struct.add(retType.getDefinitionDataType(), "RetType", null);
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
struct.add(params[i].getDefinitionDataType(), "Type" + i, null);
|
||||
if (sentinelIndex == i) {
|
||||
struct.add(CliTypeCodeDataType.dataType,
|
||||
CliElementType.ELEMENT_TYPE_SENTINEL.toString(), "SENTINEL");
|
||||
}
|
||||
|
||||
struct.add(params[i].getDefinitionDataType(), "Param" + i, null);
|
||||
}
|
||||
return struct;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -24,69 +24,81 @@ import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class CliMethodDef implements StructConverter {
|
||||
|
||||
|
||||
public static final String PATH = "/PE/CLI/Methods/MethodDefs";
|
||||
|
||||
private Address addr;
|
||||
|
||||
private boolean isFatHeader;
|
||||
private boolean hasMoreSections;
|
||||
private boolean initLocals;
|
||||
public enum HeaderFormat {
|
||||
Fat, Tiny
|
||||
}
|
||||
|
||||
private int headerFlags;
|
||||
private HeaderFormat headerFormat;
|
||||
private int headerSize; // Size of this header
|
||||
private int maxStack; // Max number of items on operand stack
|
||||
private int methodSize; // Size of method body (code)
|
||||
private int localVarSigTok;
|
||||
|
||||
|
||||
private static final int CLIMETHODDEF_HEADER_FLAGS_SHIFT = 0x08;
|
||||
private static final int CLIMETHODDEF_HEADER_FLAGS_MASK = 0x0FFF;
|
||||
private static final int CLIMETHODDEF_HEADER_SIZE_SHIFT = 0x0C;
|
||||
private static final int CLIMETHODDEF_HEADER_SIZE_FAT_MULTIPLIER = 0x04;
|
||||
|
||||
private static final byte CorILMethod_TinyFormat = 0x2;
|
||||
private static final byte CorILMethod_FatFormat = 0x3;
|
||||
private static final byte CorILMethod_MoreSects = 0x8;
|
||||
private static final byte CorILMethod_InitLocals = 0x10;
|
||||
|
||||
|
||||
public CliMethodDef(Address addr, BinaryReader reader) throws IOException {
|
||||
this.addr = addr;
|
||||
|
||||
// Read first byte, see if tiny or fat.
|
||||
byte one = reader.readNextByte();
|
||||
if ((one & CorILMethod_FatFormat) == CorILMethod_FatFormat) {
|
||||
isFatHeader = true;
|
||||
if ((one & CorILMethod_MoreSects) == CorILMethod_MoreSects)
|
||||
hasMoreSections = true;
|
||||
if ((one & CorILMethod_InitLocals) == CorILMethod_InitLocals)
|
||||
initLocals = true;
|
||||
byte two = reader.readNextByte(); // TODO: need to read byte two? Seems to only have header length (in the wrong order?? >_<)
|
||||
int firstByte = reader.readNextUnsignedByte();
|
||||
if ((firstByte & CorILMethod_FatFormat) == CorILMethod_FatFormat) {
|
||||
headerFormat = HeaderFormat.Fat;
|
||||
|
||||
// The header flags are stored across 12 bits, the top 4 bits
|
||||
// indicate the size of the header
|
||||
headerFlags =
|
||||
(firstByte << CLIMETHODDEF_HEADER_FLAGS_SHIFT) + reader.readNextUnsignedByte();
|
||||
headerSize = headerFlags >> CLIMETHODDEF_HEADER_SIZE_SHIFT;
|
||||
headerFlags = (headerFlags & CLIMETHODDEF_HEADER_FLAGS_MASK);
|
||||
|
||||
// The raw header size bits indicate: "Size of this header
|
||||
// expressed as the count of 4-bytes integers occupied."
|
||||
headerSize = headerSize * CLIMETHODDEF_HEADER_SIZE_FAT_MULTIPLIER;
|
||||
|
||||
maxStack = reader.readNextShort();
|
||||
methodSize = reader.readNextInt();
|
||||
localVarSigTok = reader.readNextInt();
|
||||
}
|
||||
else if ((one & CorILMethod_TinyFormat) == CorILMethod_TinyFormat) {
|
||||
isFatHeader = false;
|
||||
hasMoreSections = false;
|
||||
initLocals = false;
|
||||
else if ((firstByte & CorILMethod_TinyFormat) == CorILMethod_TinyFormat) {
|
||||
headerFormat = HeaderFormat.Tiny;
|
||||
headerSize = 1;
|
||||
headerFlags = 0;
|
||||
maxStack = 8;
|
||||
methodSize = (((one & ~0x3) & 0xff) >> 2); // Mask off first 2 bits, right shift to get 6 length bits. 0xff mask to convert to right sign.
|
||||
methodSize = (((firstByte & ~0x3) & 0xff) >> 2); // Mask off first 2 bits, right shift to get 6 length bits. 0xff mask to convert to right sign.
|
||||
}
|
||||
}
|
||||
|
||||
private void fillTinyHeaderType(Structure struct) {
|
||||
struct.add(BYTE, "Size+Flags", "L.S. Bits 0:1 Flags, Bits 2:7 Size of method in Bytes");
|
||||
}
|
||||
|
||||
private void fillFatHeaderType(Structure struct) {
|
||||
struct.add( WORD, "Size+Flags", "L.S. Bits 0:3 Size of hdr in B, Bits 4:15 Flags");
|
||||
struct.add( WORD, "MaxStack", "Maximum number of items on the operand stack");
|
||||
struct.add(DWORD, "CodeSize", "Size of actual method body in B");
|
||||
struct.add(DWORD, "LocalVarSigTok", "Signature for the local variables of the method. 0 means no locals. References standalone signature in Metadata tables, which references #Blob heap.");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType struct =
|
||||
new StructureDataType(new CategoryPath(PATH), "MethodDefHdr_" + addr, 0);
|
||||
if (isFatHeader) {
|
||||
fillFatHeaderType(struct);
|
||||
StructureDataType struct;
|
||||
|
||||
if (headerFormat == HeaderFormat.Fat) {
|
||||
struct = new StructureDataType(new CategoryPath(PATH), "MethodDefHdr_Fat", 0);
|
||||
struct.add(WORD, "Size+Flags", "L.S. Bits 0:3 Size of hdr in bytes, Bits 4:15 Flags");
|
||||
struct.add(WORD, "MaxStack", "Maximum number of items on the operand stack");
|
||||
struct.add(DWORD, "CodeSize", "Size of actual method body in bytes");
|
||||
struct.add(DWORD, "LocalVarSigTok",
|
||||
"Signature for the local variables of the method. 0 means no locals. References standalone signature in Metadata tables, which references #Blob heap.");
|
||||
}
|
||||
else {
|
||||
fillTinyHeaderType(struct);
|
||||
struct = new StructureDataType(new CategoryPath(PATH), "MethodDefHdr_Tiny", 0);
|
||||
struct.add(BYTE, "Size+Flags", "L.S. Bits 0:1 Flags, Bits 2:7 Size of method in Bytes");
|
||||
}
|
||||
|
||||
return struct;
|
||||
}
|
||||
|
||||
@@ -95,7 +107,14 @@ public class CliMethodDef implements StructConverter {
|
||||
}
|
||||
|
||||
public boolean hasMoreSections() {
|
||||
return hasMoreSections;
|
||||
return (headerFlags & CorILMethod_MoreSects) == CorILMethod_MoreSects;
|
||||
}
|
||||
|
||||
public boolean hasLocals() {
|
||||
return (headerFlags & CorILMethod_InitLocals) == CorILMethod_InitLocals;
|
||||
}
|
||||
|
||||
public HeaderFormat getHeaderFormat() {
|
||||
return headerFormat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
|
||||
@@ -35,7 +35,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* The Metadata stream is giant and complicated. It is made up of {@link CliAbstractTable}s.
|
||||
*
|
||||
*
|
||||
* @see CliTypeTable
|
||||
*/
|
||||
public class CliStreamMetadata extends CliAbstractStream {
|
||||
@@ -55,7 +55,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the name of this stream.
|
||||
*
|
||||
*
|
||||
* @return The name of this stream.
|
||||
*/
|
||||
public static String getName() {
|
||||
@@ -64,13 +64,13 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Creates a new Metadata stream.
|
||||
*
|
||||
*
|
||||
* @param header The stream header associated with this stream.
|
||||
* @param guidStream The GUID stream.
|
||||
* @param userStringsStream The user strings stream.
|
||||
* @param stringsStream The strings stream.
|
||||
* @param blobStream The blob stream.
|
||||
* @param fileOffset The file offset where this stream starts.
|
||||
* @param fileOffset The file offset where this stream starts.
|
||||
* @param rva The relative virtual address where this stream starts.
|
||||
* @param reader A reader that is set to the start of the stream.
|
||||
* @throws IOException if there is a problem reading the stream.
|
||||
@@ -133,7 +133,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the GUID stream.
|
||||
*
|
||||
*
|
||||
* @return The GUID stream. Could be null if one doesn't exist.
|
||||
*/
|
||||
public CliStreamGuid getGuidStream() {
|
||||
@@ -142,7 +142,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the user strings stream.
|
||||
*
|
||||
*
|
||||
* @return The user strings stream. Could be null if one doesn't exist.
|
||||
*/
|
||||
public CliStreamUserStrings getUserStringsStream() {
|
||||
@@ -151,7 +151,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the strings stream.
|
||||
*
|
||||
*
|
||||
* @return The strings stream. Could be null if one doesn't exist.
|
||||
*/
|
||||
public CliStreamStrings getStringsStream() {
|
||||
@@ -160,7 +160,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the blob stream.
|
||||
*
|
||||
*
|
||||
* @return The blob stream. Could be null if one doesn't exist.
|
||||
*/
|
||||
public CliStreamBlob getBlobStream() {
|
||||
@@ -170,7 +170,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
/**
|
||||
* Creates a new {@link CliAbstractTable} from the table at the current reader index
|
||||
* with the given table type.
|
||||
*
|
||||
*
|
||||
* @param tableType The type of table to create.
|
||||
* @return A new table with the given type. Could be null if we don't support the table type.
|
||||
* @throws IOException if there was an issue reading the new table.
|
||||
@@ -300,7 +300,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the major version.
|
||||
*
|
||||
*
|
||||
* @return The major version.
|
||||
*/
|
||||
public short getMajorVersion() {
|
||||
@@ -309,7 +309,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the minor version.
|
||||
*
|
||||
*
|
||||
* @return The minor version.
|
||||
*/
|
||||
public short getMinorVersion() {
|
||||
@@ -318,7 +318,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the sorted field.
|
||||
*
|
||||
*
|
||||
* @return The sorted field.
|
||||
*/
|
||||
public long getSorted() {
|
||||
@@ -327,7 +327,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the valid field.
|
||||
*
|
||||
*
|
||||
* @return The valid field.
|
||||
*/
|
||||
public long getValid() {
|
||||
@@ -336,7 +336,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the table with the provided table type from the metadata stream.
|
||||
*
|
||||
*
|
||||
* @param tableType The type of table to get.
|
||||
* @return The table with the provided table type. Could be null if it doesn't exist.
|
||||
*/
|
||||
@@ -360,7 +360,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the table with the provided table type id from the metadata stream.
|
||||
*
|
||||
*
|
||||
* @param tableId The id of the table type to get.
|
||||
* @return The table with the provided table id. Could be null if it doesn't exist.
|
||||
*/
|
||||
@@ -370,9 +370,9 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
|
||||
/**
|
||||
* Gets the number of rows in the table with the given table type.
|
||||
*
|
||||
*
|
||||
* @param tableType The type of table to get the number of rows of.
|
||||
* @return The number of rows in the table with the given table type. Could be 0 if
|
||||
* @return The number of rows in the table with the given table type. Could be 0 if
|
||||
* the table of the given type was not found.
|
||||
*/
|
||||
public int getNumberRowsForTable(CliTypeTable tableType) {
|
||||
@@ -383,7 +383,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
/**
|
||||
* Gets the data type of the index into the string stream. Will be either
|
||||
* {@link DWordDataType} or {@link WordDataType}.
|
||||
*
|
||||
*
|
||||
* @return The data type of the index into the string stream.
|
||||
*/
|
||||
public DataType getStringIndexDataType() {
|
||||
@@ -393,7 +393,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
/**
|
||||
* Gets the data type of the index into the GUID stream. Will be either
|
||||
* {@link DWordDataType} or {@link WordDataType}.
|
||||
*
|
||||
*
|
||||
* @return The data type of the index into the string stream.
|
||||
*/
|
||||
public DataType getGuidIndexDataType() {
|
||||
@@ -403,7 +403,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
/**
|
||||
* Gets the data type of the index into the Blob stream. Will be either
|
||||
* {@link DWordDataType} or {@link WordDataType}.
|
||||
*
|
||||
*
|
||||
* @return The data type of the index into the string stream.
|
||||
*/
|
||||
public DataType getBlobIndexDataType() {
|
||||
@@ -413,7 +413,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
/**
|
||||
* Gets the data type of the index into a metadata table. Will be either
|
||||
* {@link DWordDataType} or {@link WordDataType}.
|
||||
*
|
||||
*
|
||||
* @return The data type of the index into the string stream.
|
||||
*/
|
||||
public DataType getTableIndexDataType(CliTypeTable table) {
|
||||
@@ -435,7 +435,7 @@ public class CliStreamMetadata extends CliAbstractStream {
|
||||
table.markup(program, isBinary, monitor, log, ntHeader);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "Failed to markup " + table + ": " + e.toString());
|
||||
Msg.error(this, "Failed to markup " + table + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import ghidra.program.model.data.CategoryPath;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -100,16 +101,24 @@ public class CliTableField extends CliAbstractTable {
|
||||
public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log,
|
||||
NTHeader ntHeader)
|
||||
throws DuplicateNameException, CodeUnitInsertionException, IOException {
|
||||
int fieldRowIndex = 0;
|
||||
for (CliAbstractTableRow row : rows) {
|
||||
CliFieldRow fieldRow = (CliFieldRow) row;
|
||||
fieldRowIndex++;
|
||||
|
||||
// Create FieldSig object and bookmark it
|
||||
// Create FieldSig object
|
||||
Address sigAddr = CliAbstractStream.getStreamMarkupAddress(program, isBinary, monitor,
|
||||
log, ntHeader, metadataStream.getBlobStream(), fieldRow.sigIndex);
|
||||
|
||||
CliSigField fieldSig =
|
||||
new CliSigField(metadataStream.getBlobStream().getBlob(fieldRow.sigIndex));
|
||||
metadataStream.getBlobStream().updateBlob(fieldSig, sigAddr, program);
|
||||
|
||||
if (!metadataStream.getBlobStream().updateBlob(fieldSig, sigAddr, program)) {
|
||||
Msg.warn(CliTableField.class,
|
||||
"Couldn't update FieldSig blob " +
|
||||
metadataStream.getStringsStream().getString(fieldRow.nameIndex) +
|
||||
" at Field table index " + fieldRowIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -16,14 +16,13 @@
|
||||
package ghidra.app.util.bin.format.pe.cli.tables;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.MemoryByteProvider;
|
||||
import ghidra.app.util.bin.format.pe.NTHeader;
|
||||
import ghidra.app.util.bin.format.pe.PeUtils;
|
||||
import ghidra.app.util.bin.format.pe.cli.blobs.CliAbstractSig.CliParam;
|
||||
import ghidra.app.util.bin.format.pe.cli.blobs.CliAbstractSig.*;
|
||||
import ghidra.app.util.bin.format.pe.cli.blobs.CliBlob;
|
||||
import ghidra.app.util.bin.format.pe.cli.blobs.CliSigMethodDef;
|
||||
import ghidra.app.util.bin.format.pe.cli.methods.CliMethodDef;
|
||||
@@ -31,6 +30,8 @@ import ghidra.app.util.bin.format.pe.cli.methods.CliMethodExtraSections;
|
||||
import ghidra.app.util.bin.format.pe.cli.streams.CliAbstractStream;
|
||||
import ghidra.app.util.bin.format.pe.cli.streams.CliStreamMetadata;
|
||||
import ghidra.app.util.bin.format.pe.cli.tables.CliTableParam.CliParamRow;
|
||||
import ghidra.app.util.bin.format.pe.cli.tables.CliTableTypeDef.CliTypeDefRow;
|
||||
import ghidra.app.util.bin.format.pe.cli.tables.CliTableTypeRef.CliTypeRefRow;
|
||||
import ghidra.app.util.bin.format.pe.cli.tables.flags.CliFlags.CliEnumMethodAttributes;
|
||||
import ghidra.app.util.bin.format.pe.cli.tables.flags.CliFlags.CliEnumMethodImplAttributes;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
@@ -40,6 +41,7 @@ import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
@@ -52,6 +54,8 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public class CliTableMethodDef extends CliAbstractTable {
|
||||
|
||||
private static final int CLITABLEMETHODDEF_PINVOKE_JUMP_LENGTH = 0x06;
|
||||
|
||||
public class CliMethodDefRow extends CliAbstractTableRow {
|
||||
public int RVA;
|
||||
public short ImplFlags; // MethodImplAttributes
|
||||
@@ -63,6 +67,42 @@ public class CliTableMethodDef extends CliAbstractTable {
|
||||
private static final int NEXT_ROW_PARAM_INIT_VALUE = -1;
|
||||
private int nextRowParamIndex = NEXT_ROW_PARAM_INIT_VALUE;
|
||||
|
||||
private static final int METHODIMPLATTRIBUTES_CODETYPE_IL = 0x00;
|
||||
private static final int METHODIMPLATTRIBUTES_CODETYPE_NATIVE = 0x01;
|
||||
private static final int METHODIMPLATTRIBUTES_CODETYPE_OPTIL = 0x02;
|
||||
private static final int METHODIMPLATTRIBUTES_CODETYPE_RUNTIME = 0x03;
|
||||
private static final int METHODIMPLATTRIBUTES_MANAGED_MANAGED = 0x00;
|
||||
private static final int METHODIMPLATTRIBUTES_MANAGED_UNMANAGED = 0x04;
|
||||
private static final int METHODIMPLATTRIBUTES_FORWARDREF = 0x10;
|
||||
private static final int METHODIMPLATTRIBUTES_PRESERVESIG = 0x80;
|
||||
private static final int METHODIMPLATTRIBUTES_INTERNALCALL = 0x1000;
|
||||
private static final int METHODIMPLATTRIBUTES_SYNCHRONIZED = 0x20;
|
||||
private static final int METHODIMPLATTRIBUTES_NOINLINING = 0x08;
|
||||
private static final int METHODIMPLATTRIBUTES_AGGRESSIVEINLINING = 0x1000;
|
||||
private static final int METHODIMPLATTRIBUTES_MAXMETHODIMPLVAL = 0xffff;
|
||||
|
||||
private static final int METHODATTRIBUTES_MEMBERACCESS_COMPILERCONTROLLED = 0x00;
|
||||
private static final int METHODATTRIBUTES_MEMBERACCESS_PRIVATE = 0x01;
|
||||
private static final int METHODATTRIBUTES_MEMBERACCESS_FAMANDASSEM = 0x02;
|
||||
private static final int METHODATTRIBUTES_MEMBERACCESS_ASSEM = 0x03;
|
||||
private static final int METHODATTRIBUTES_MEMBERACCESS_FAMILY = 0x04;
|
||||
private static final int METHODATTRIBUTES_MEMBERACCESS_FAMORASSEM = 0x05;
|
||||
private static final int METHODATTRIBUTES_MEMBERACCESS_PUBLIC = 0x06;
|
||||
private static final int METHODATTRIBUTES_STATIC = 0x10;
|
||||
private static final int METHODATTRIBUTES_FINAL = 0x20;
|
||||
private static final int METHODATTRIBUTES_VIRTUAL = 0x40;
|
||||
private static final int METHODATTRIBUTES_HIDEBYSIG = 0x80;
|
||||
private static final int METHODATTRIBUTES_VTABLELAYOUT_REUSESLOT = 0x0000;
|
||||
private static final int METHODATTRIBUTES_VTABLELAYOUT_NEWSLOT = 0x0100;
|
||||
private static final int METHODATTRIBUTES_STRICT = 0x0200;
|
||||
private static final int METHODATTRIBUTES_ABSTRACT = 0x0400;
|
||||
private static final int METHODATTRIBUTES_SPECIALNAME = 0x0800;
|
||||
private static final int METHODATTRIBUTES_PINVOKEIMPL = 0x2000;
|
||||
private static final int METHODATTRIBUTES_UNMANAGEDEXPORT = 0x08;
|
||||
private static final int METHODATTRIBUTES_RTSPECIALNAME = 0x1000;
|
||||
private static final int METHODATTRIBUTES_HASSECURITY = 0x4000;
|
||||
private static final int METHODATTRIBUTES_REQUIRESECOBJECT = 0x8000;
|
||||
|
||||
public CliMethodDefRow(int rva, short implFlags, short flags, int nameIndex, int sigIndex,
|
||||
int paramIndex) {
|
||||
this.RVA = rva;
|
||||
@@ -141,6 +181,28 @@ public class CliTableMethodDef extends CliAbstractTable {
|
||||
CliEnumMethodImplAttributes.dataType.getName(ImplFlags & 0xffff),
|
||||
CliEnumMethodAttributes.dataType.getName(Flags & 0xffff));
|
||||
}
|
||||
|
||||
// Static functions have four parameters but the first is an implied
|
||||
// pointer to the object they're associated with. It's not in the
|
||||
// ParameterTable and looking for the extra parameter will walk
|
||||
// you into the parameter of another function.
|
||||
boolean isStatic() {
|
||||
return (Flags & METHODATTRIBUTES_STATIC) == METHODATTRIBUTES_STATIC;
|
||||
}
|
||||
|
||||
boolean isPInvokeImpl() {
|
||||
return (Flags & METHODATTRIBUTES_PINVOKEIMPL) == METHODATTRIBUTES_PINVOKEIMPL;
|
||||
}
|
||||
|
||||
boolean isNative() {
|
||||
return (ImplFlags &
|
||||
METHODIMPLATTRIBUTES_CODETYPE_NATIVE) == METHODIMPLATTRIBUTES_CODETYPE_NATIVE;
|
||||
}
|
||||
|
||||
boolean isManaged() {
|
||||
return (ImplFlags &
|
||||
METHODIMPLATTRIBUTES_CODETYPE_IL) == METHODIMPLATTRIBUTES_CODETYPE_IL;
|
||||
}
|
||||
}
|
||||
|
||||
public CliTableMethodDef(BinaryReader reader, CliStreamMetadata stream, CliTypeTable tableId)
|
||||
@@ -159,7 +221,7 @@ public class CliTableMethodDef extends CliAbstractTable {
|
||||
}
|
||||
lastRow = row;
|
||||
}
|
||||
reader.setPointerIndex(this.readerOffset); // TODO: why do this, also elsewhere
|
||||
reader.setPointerIndex(this.readerOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -167,54 +229,64 @@ public class CliTableMethodDef extends CliAbstractTable {
|
||||
NTHeader ntHeader)
|
||||
throws DuplicateNameException, CodeUnitInsertionException, IOException {
|
||||
|
||||
int rvaZero = 0;
|
||||
|
||||
int methodRowIndex = 0;
|
||||
for (CliAbstractTableRow method : rows) {
|
||||
methodRowIndex++;
|
||||
|
||||
CliMethodDefRow methodRow = (CliMethodDefRow) method;
|
||||
|
||||
// This indicates the method is abstract, runtime, or PInvokeImpl
|
||||
if (methodRow.RVA == 0) {
|
||||
rvaZero++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Address addr = PeUtils.getMarkupAddress(program, isBinary, ntHeader, methodRow.RVA);
|
||||
Address startAddr = addr;
|
||||
Address endAddr = addr;
|
||||
|
||||
// Create MethodDef at this RVA
|
||||
BinaryReader reader =
|
||||
new BinaryReader(new MemoryByteProvider(program.getMemory(), addr),
|
||||
!program.getMemory().isBigEndian());
|
||||
CliMethodDef methodDef = new CliMethodDef(addr, reader);
|
||||
|
||||
PeUtils.createData(program, addr, methodDef.toDataType(), log);
|
||||
|
||||
// Get the function's address space, default to zero-length just in case
|
||||
Address startAddr = addr.add(methodDef.toDataType().getLength());
|
||||
Address endAddr = startAddr;
|
||||
if (methodDef.getMethodSize() > 0) {
|
||||
endAddr = startAddr.add(methodDef.getMethodSize() - 1);
|
||||
if (methodRow.isPInvokeImpl() && methodRow.isNative()) {
|
||||
endAddr = startAddr.add(CLITABLEMETHODDEF_PINVOKE_JUMP_LENGTH - 1);
|
||||
}
|
||||
else {
|
||||
// Create MethodDef at this RVA
|
||||
BinaryReader reader =
|
||||
new BinaryReader(new MemoryByteProvider(program.getMemory(), addr),
|
||||
!program.getMemory().isBigEndian());
|
||||
CliMethodDef methodDef = new CliMethodDef(addr, reader);
|
||||
|
||||
DataType methodDefDataType = methodDef.toDataType();
|
||||
PeUtils.createData(program, addr, methodDefDataType, log);
|
||||
|
||||
// Get the function's address space, default to zero-length just in case
|
||||
startAddr = addr.add(methodDefDataType.getLength());
|
||||
endAddr = startAddr;
|
||||
if (methodDef.getMethodSize() > 0) {
|
||||
endAddr = startAddr.add(methodDef.getMethodSize() - 1);
|
||||
}
|
||||
|
||||
// Do extra data sections in MethodDef
|
||||
if (methodDef.hasMoreSections()) {
|
||||
int extraSectionOffset =
|
||||
methodDefDataType.getLength() + methodDef.getMethodSize();
|
||||
|
||||
// Round up to the next offset divisible by 4
|
||||
extraSectionOffset = ((extraSectionOffset + 3) / 4) * 4;
|
||||
|
||||
reader.setPointerIndex(extraSectionOffset);
|
||||
CliMethodExtraSections extraSections = new CliMethodExtraSections(reader);
|
||||
Address extraSectionAddr = addr.add(extraSectionOffset);
|
||||
PeUtils.createData(program, extraSectionAddr, extraSections.toDataType(), log);
|
||||
}
|
||||
}
|
||||
|
||||
AddressSetView funcAddrSet = new AddressSet(startAddr, endAddr);
|
||||
|
||||
// Let Ghidra assign a default function name and then try to decode the
|
||||
// real one if it exists
|
||||
String funcName = null;
|
||||
if (methodRow.nameIndex > 0) {
|
||||
funcName = metadataStream.getStringsStream().getString(methodRow.nameIndex);
|
||||
}
|
||||
|
||||
// Do extra data sections in MethodDef
|
||||
if (methodDef.hasMoreSections()) {
|
||||
int extraSectionOffset =
|
||||
methodDef.toDataType().getLength() + methodDef.getMethodSize();
|
||||
|
||||
// Round up to the next offset divisible by 4
|
||||
extraSectionOffset = ((extraSectionOffset + 3) / 4) * 4;
|
||||
|
||||
reader.setPointerIndex(extraSectionOffset);
|
||||
CliMethodExtraSections extraSections = new CliMethodExtraSections(reader);
|
||||
Address extraSectionAddr = addr.add(extraSectionOffset);
|
||||
PeUtils.createData(program, extraSectionAddr, extraSections.toDataType(), log);
|
||||
funcName = SymbolUtilities.replaceInvalidChars(
|
||||
metadataStream.getStringsStream().getString(methodRow.nameIndex), true);
|
||||
}
|
||||
|
||||
// Get the function signature blob
|
||||
@@ -227,27 +299,136 @@ public class CliTableMethodDef extends CliAbstractTable {
|
||||
metadataStream.getBlobStream().updateBlob(methodSig, sigAddr, program);
|
||||
DataType returnType = methodSig.getReturnType().getExecutionDataType();
|
||||
|
||||
// Pull apart the function parameter names and types
|
||||
int maxSequence = 0;
|
||||
int stackOffset = 0;
|
||||
CliParam paramTypes[] = methodSig.getParamTypes();
|
||||
int paramCount = paramTypes.length;
|
||||
CliTableParam paramTable = (CliTableParam) metadataStream.getTable(CliTypeTable.Param);
|
||||
ParameterImpl parameters[] = new ParameterImpl[paramTypes.length];
|
||||
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
// Store the parameters in a Hashtable because by the time processing
|
||||
// finishes the number of actual parameters might change
|
||||
HashMap<Integer, ParameterImpl> parameterList = new HashMap<Integer, ParameterImpl>();
|
||||
|
||||
// Some Static function first parameters being pointers to a ValueType
|
||||
// have the same number of parameters specified, but one or more are implied
|
||||
// pointers to the object they're associated with. It's not in the Parameter
|
||||
// Table and looking for the extra parameter in the table will walk you
|
||||
// into the parameter list of another function.
|
||||
ParameterImpl staticParameter = null;
|
||||
if (methodRow.isStatic() && paramCount > 0) {
|
||||
CliParam staticParam = paramTypes[0];
|
||||
String paramName = "";
|
||||
|
||||
// Walk the path from the ELEMENT_TYPE_PTR to the ELEMENT_TYPE_VALUETYPE
|
||||
if (staticParam.getType() instanceof CliTypePtr) {
|
||||
CliTypePtr ptrToValueType = (CliTypePtr) staticParam.getType();
|
||||
if (ptrToValueType.getType() instanceof CliTypeValueType) {
|
||||
CliTypeValueType valueType = (CliTypeValueType) ptrToValueType.getType();
|
||||
|
||||
// Get the table and row specifying the type name
|
||||
CliTypeTable tableType = valueType.getTable();
|
||||
int rowIndex = valueType.getRowIndex();
|
||||
|
||||
int paramNameStringIndex = 0;
|
||||
CliAbstractTable table = metadataStream.getTable(tableType);
|
||||
CliAbstractTableRow row = table.getRow(rowIndex);
|
||||
if (tableType.id() == tableType.TypeDef.id()) {
|
||||
CliTypeDefRow typeDefRow = (CliTypeDefRow) row;
|
||||
paramNameStringIndex = typeDefRow.typeNameIndex;
|
||||
}
|
||||
else if (tableType.id() == tableType.TypeRef.id()) {
|
||||
CliTypeRefRow typeRefRow = (CliTypeRefRow) row;
|
||||
paramNameStringIndex = typeRefRow.typeNameIndex;
|
||||
}
|
||||
|
||||
if (paramNameStringIndex > 0) {
|
||||
paramName =
|
||||
metadataStream.getStringsStream().getString(paramNameStringIndex);
|
||||
paramName = SymbolUtilities.replaceInvalidChars(paramName, true);
|
||||
|
||||
DataType dataType = staticParam.getExecutionDataType();
|
||||
|
||||
try {
|
||||
staticParameter =
|
||||
new ParameterImpl(paramName, dataType, stackOffset, program);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.warn(this, "Error processing parameter \"" + paramName +
|
||||
"\" in function \"" + funcName + "\": " + e.getMessage());
|
||||
}
|
||||
|
||||
stackOffset += dataType.getLength();
|
||||
|
||||
paramCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pull apart the function's Param table entries
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
CliParamRow paramRow = (CliParamRow) paramTable.getRow(methodRow.paramIndex + i);
|
||||
|
||||
String paramName = metadataStream.getStringsStream().getString(paramRow.nameIndex);
|
||||
if (paramRow.sequence > maxSequence) {
|
||||
maxSequence = paramRow.sequence;
|
||||
}
|
||||
|
||||
String paramName = SymbolUtilities.replaceInvalidChars(
|
||||
metadataStream.getStringsStream().getString(paramRow.nameIndex), true);
|
||||
|
||||
DataType dataType = paramTypes[i].getExecutionDataType();
|
||||
|
||||
try {
|
||||
parameters[i] = new ParameterImpl(paramName, dataType, stackOffset, program);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.warn(this, "Error processing parameter \"" + paramName +
|
||||
"\" in function \"" + funcName + "\": " + e.getMessage());
|
||||
if (paramRow.sequence == 0) {
|
||||
// Parameters with a 0 sequence number are the return type,
|
||||
// reduce the size of the array and put any previously discovered
|
||||
// parameters into it
|
||||
returnType = dataType;
|
||||
}
|
||||
else {
|
||||
// Parameters are placed in the proper order based on the sequence
|
||||
// field (1-based) to compensate for some static methods having an implied
|
||||
// first parameter that won't be represented in the Parameter Table
|
||||
// and some return types that are represented as parameters.
|
||||
try {
|
||||
parameterList.put((int) paramRow.sequence,
|
||||
new ParameterImpl(paramName, dataType, stackOffset, program));
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.warn(this, "Error processing parameter \"" + paramName +
|
||||
"\" in function \"" + funcName + "\": " + e.getMessage());
|
||||
}
|
||||
|
||||
stackOffset += dataType.getLength();
|
||||
stackOffset += dataType.getLength();
|
||||
}
|
||||
}
|
||||
|
||||
ParameterImpl[] parameters = new ParameterImpl[maxSequence];
|
||||
parameterList.forEach((key, value) ->
|
||||
// Sequences are 1-based
|
||||
parameters[key - 1] = value);
|
||||
|
||||
// For static functions, fill in the pointer to ValueType
|
||||
// parameters that are implied before the actual parameters
|
||||
if (methodRow.isStatic()) {
|
||||
if (staticParameter != null) {
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
if (parameters[i] == null) {
|
||||
ParameterImpl param = null;
|
||||
try {
|
||||
param = new ParameterImpl(staticParameter.getName() + i,
|
||||
staticParameter.getDataType(), staticParameter.getStackOffset(),
|
||||
staticParameter.getProgram());
|
||||
}
|
||||
catch (InvalidInputException e1) {
|
||||
Msg.warn(this,
|
||||
"Couldn't clone " + staticParameter.getName() +
|
||||
" implied static function parameter in function : " +
|
||||
funcName + "in position " + i);
|
||||
}
|
||||
parameters[i] = param;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -257,15 +438,44 @@ public class CliTableMethodDef extends CliAbstractTable {
|
||||
newFunc.updateFunction(null, null, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS,
|
||||
true, SourceType.ANALYSIS, parameters);
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
Msg.warn(this, "Error processing function \"" + funcName + "\" (" + methodRowIndex +
|
||||
"): Bad parameters provided");
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.warn(this, "Error processing function \"" + funcName + "\"");
|
||||
Msg.warn(this, "Error processing function \" (\" + methodRowIndex + \")" +
|
||||
funcName + "\": Invalid function");
|
||||
}
|
||||
catch (OverlappingFunctionException e) {
|
||||
Msg.warn(this, "Error processing function \"" + funcName + "\"");
|
||||
String err = "Error processing function \" (\" + methodRowIndex + \")" + funcName +
|
||||
"\": Overlapping function (" + startAddr + ", " + endAddr + ": ";
|
||||
|
||||
Function existingFuncA = program.getFunctionManager().getFunctionAt(startAddr);
|
||||
Function existingFuncB = program.getFunctionManager().getFunctionAt(endAddr);
|
||||
|
||||
if (existingFuncA != null && existingFuncB == null) {
|
||||
err = err + existingFuncA.getName();
|
||||
}
|
||||
else if (existingFuncA == null && existingFuncB != null) {
|
||||
err = err + existingFuncB.getName();
|
||||
}
|
||||
else if (existingFuncA != null && existingFuncA == existingFuncB) {
|
||||
err = err + existingFuncA.getName();
|
||||
}
|
||||
|
||||
err = err + ")";
|
||||
|
||||
Msg.warn(this, err);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
String paramNames = "";
|
||||
for (int i = 0; i < parameters.length - 1; i++) {
|
||||
paramNames += parameters[i].getName() + ", ";
|
||||
}
|
||||
paramNames += parameters[parameters.length - 1].getName();
|
||||
Msg.warn(this, "Error processing function \"" + funcName + "\" (" + methodRowIndex +
|
||||
"): Duplicate parameter name (" + paramNames + ")");
|
||||
}
|
||||
}
|
||||
if (rvaZero > 0) {
|
||||
Msg.warn(this, rvaZero + " methods with RVA 0");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,14 @@ public class CliTableParam extends CliAbstractTable {
|
||||
public short flags;
|
||||
public short sequence;
|
||||
public int nameIndex;
|
||||
|
||||
|
||||
private static final int PARAMATTRIBUTES_IN = 0x1;
|
||||
private static final int PARAMATTRIBUTES_OUT = 0x2;
|
||||
private static final int PARAMATTRIBUTES_OPTIONAL = 0x10;
|
||||
private static final int PARAMATTRIBUTES_HASDEFAULT = 0x1000;
|
||||
private static final int PARAMATTRIBUTES_HASFIELDMARSHAL = 0x2000;
|
||||
private static final int PARAMATTRIBUTES_UNUSED = 0xCFE0;
|
||||
|
||||
public CliParamRow(short flags, short sequence, int nameIndex) {
|
||||
super();
|
||||
this.flags = flags;
|
||||
@@ -46,11 +53,13 @@ public class CliTableParam extends CliAbstractTable {
|
||||
CliEnumParamAttributes.dataType.getName(flags & 0xffff), sequence);
|
||||
}
|
||||
}
|
||||
|
||||
public CliTableParam(BinaryReader reader, CliStreamMetadata stream, CliTypeTable tableId) throws IOException {
|
||||
|
||||
public CliTableParam(BinaryReader reader, CliStreamMetadata stream, CliTypeTable tableId)
|
||||
throws IOException {
|
||||
super(reader, stream, tableId);
|
||||
for (int i = 0; i < this.numRows; i++) {
|
||||
CliParamRow row = new CliParamRow(reader.readNextShort(), reader.readNextShort(), readStringIndex(reader));
|
||||
CliParamRow row = new CliParamRow(reader.readNextShort(), reader.readNextShort(),
|
||||
readStringIndex(reader));
|
||||
rows.add(row);
|
||||
strings.add(row.nameIndex);
|
||||
}
|
||||
@@ -59,9 +68,9 @@ public class CliTableParam extends CliAbstractTable {
|
||||
|
||||
@Override
|
||||
public StructureDataType getRowDataType() {
|
||||
StructureDataType rowDt = new StructureDataType(new CategoryPath(PATH), "ParamRow",0);
|
||||
StructureDataType rowDt = new StructureDataType(new CategoryPath(PATH), "ParamRow", 0);
|
||||
rowDt.add(CliEnumParamAttributes.dataType, "Flags", "bitmask of type ParamAttributes");
|
||||
rowDt.add( WORD, "Sequence", "constant");
|
||||
rowDt.add(WORD, "Sequence", "constant");
|
||||
rowDt.add(metadataStream.getStringIndexDataType(), "Name", "index into String heap");
|
||||
return rowDt;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -90,6 +90,7 @@ public class CliTableStandAloneSig extends CliAbstractTable {
|
||||
throws DuplicateNameException, CodeUnitInsertionException, IOException {
|
||||
for (CliAbstractTableRow row : rows) {
|
||||
Integer sigIndex = ((CliStandAloneSigRow) row).signatureIndex;
|
||||
|
||||
CliBlob blob =
|
||||
metadataStream.getBlobStream().getBlob(((CliStandAloneSigRow) row).signatureIndex);
|
||||
Address sigAddr = CliAbstractStream.getStreamMarkupAddress(program, isBinary, monitor,
|
||||
|
||||
Reference in New Issue
Block a user