247 lines
9.1 KiB
C#
247 lines
9.1 KiB
C#
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
|
|
using System;
|
|
using System.IO;
|
|
|
|
namespace Bartok.MSIL
|
|
{
|
|
|
|
using System.Reflection;
|
|
|
|
public class MetaDataFieldRVA: MetaDataObject {
|
|
|
|
// Constructor Methods
|
|
|
|
internal MetaDataFieldRVA(int rva, MetaDataField field) {
|
|
this.rva = rva;
|
|
this.field = field;
|
|
}
|
|
|
|
internal void resolveReferences(MetaDataLoader loader,
|
|
PELoader peLoader,
|
|
Stream fileStream) {
|
|
this.field.resolveReferences(this);
|
|
int dataOffset = peLoader.VaToOffsetSafe(this.rva);
|
|
if (dataOffset != -1) {
|
|
fileStream.Seek(dataOffset, SeekOrigin.Begin);
|
|
BinaryReader reader = new BinaryReader(fileStream);
|
|
SignatureField fieldSignature = (SignatureField)
|
|
this.field.Signature;
|
|
Signature.Type fieldType = fieldSignature.FieldType;
|
|
int dataSize = this.getFieldSize(fieldType);
|
|
byte[] data = new byte[dataSize];
|
|
int count = reader.Read(data, 0, dataSize);
|
|
if (loader.HasVtableFixup() &&
|
|
loader.RVAHasRelocation(dataOffset) &&
|
|
dataSize == 4) {
|
|
// if this corresponds to a vtable label, we need to fix it
|
|
int location = data[0] | (data[1] << 8) |
|
|
(data[2] << 16) | (data[3] << 24);
|
|
int imageBase = peLoader.getImageBase();
|
|
location -= imageBase; // use RVA
|
|
fileStream.Seek(location, SeekOrigin.Begin);
|
|
BinaryReader binaryReader = new BinaryReader(fileStream);
|
|
short prefix = binaryReader.ReadInt16();
|
|
if (prefix == 0x25FF) { // this starts a vtable lable
|
|
count = binaryReader.Read(data, 0, 4);
|
|
}
|
|
}
|
|
this.dataBytes = data;
|
|
|
|
if (count != dataSize) {
|
|
throw new MetaDataLoader.IllegalMetaDataFormatException("Only got "+count+" out of "+dataSize+" data bytes for FieldRVA "+this.rva);
|
|
}
|
|
}
|
|
else {
|
|
Console.WriteLine("Found no data for "+this.field);
|
|
}
|
|
}
|
|
|
|
|
|
// Access Methods
|
|
|
|
public byte[] DataBytes {
|
|
get {
|
|
return this.dataBytes;
|
|
}
|
|
}
|
|
|
|
public MetaDataField Field {
|
|
get {
|
|
return this.field;
|
|
}
|
|
}
|
|
|
|
public int RVA {
|
|
get {
|
|
return this.rva;
|
|
}
|
|
}
|
|
|
|
// Helper Methods
|
|
|
|
private int getFieldSize(Signature.Type fieldType) {
|
|
switch (fieldType.ElementType) {
|
|
case ElementTypes.VOID:
|
|
return 0;
|
|
case ElementTypes.BOOLEAN:
|
|
case ElementTypes.I1:
|
|
case ElementTypes.U1:
|
|
return 1;
|
|
case ElementTypes.CHAR:
|
|
case ElementTypes.I2:
|
|
case ElementTypes.U2:
|
|
return 2;
|
|
case ElementTypes.I4:
|
|
case ElementTypes.U4:
|
|
case ElementTypes.R4:
|
|
return 4;
|
|
case ElementTypes.I8:
|
|
case ElementTypes.U8:
|
|
case ElementTypes.R8:
|
|
return 8;
|
|
case ElementTypes.OBJECT:
|
|
case ElementTypes.STRING:
|
|
case ElementTypes.FNPTR:
|
|
case ElementTypes.CLASS:
|
|
case ElementTypes.PTR:
|
|
case ElementTypes.BYREF:
|
|
case ElementTypes.U:
|
|
case ElementTypes.I:
|
|
return machineIntSize;
|
|
case ElementTypes.TYPEDBYREF:
|
|
return 2*machineIntSize;
|
|
case ElementTypes.VALUETYPE: {
|
|
MetaDataObject classObject = fieldType.ClassObject;
|
|
if (!(classObject is MetaDataTypeDefinition)) {
|
|
return -1;
|
|
}
|
|
MetaDataTypeDefinition typedef = (MetaDataTypeDefinition) classObject;
|
|
if ((typedef.Flags & TypeAttributes.Interface) != 0 ||
|
|
(typedef.Flags & TypeAttributes.Abstract) != 0) {
|
|
return -1;
|
|
}
|
|
int classSize = 0;
|
|
int packSize = 0;
|
|
if (typedef.ClassLayout != null) {
|
|
classSize = typedef.ClassLayout.ClassSize;
|
|
packSize = typedef.ClassLayout.PackingSize;
|
|
}
|
|
int instanceFieldSize = 0;
|
|
if ((typedef.Flags & TypeAttributes.ExplicitLayout) != 0) {
|
|
foreach (MetaDataField mdField in typedef.Fields) {
|
|
if ((mdField.Flags & (int) MetaDataField.FieldAttributes.Static) == 0) {
|
|
Signature.Type nestedFieldType =
|
|
((SignatureField) mdField.Signature).FieldType;
|
|
int fieldSize = this.getFieldSize(nestedFieldType);
|
|
int offset = mdField.Layout.Offset;
|
|
int fieldEnd = fieldSize + offset;
|
|
if (fieldEnd > instanceFieldSize) {
|
|
instanceFieldSize = fieldEnd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
foreach (MetaDataField mdField in typedef.Fields) {
|
|
if ((mdField.Flags & (int) MetaDataField.FieldAttributes.Static) == 0) {
|
|
Signature.Type nestedFieldType =
|
|
((SignatureField) mdField.Signature).FieldType;
|
|
int fieldSize = this.getFieldSize(nestedFieldType);
|
|
if (fieldSize == -1) {
|
|
return -1;
|
|
}
|
|
if (packSize > 1) {
|
|
int delta = instanceFieldSize % packSize;
|
|
if (delta > 0) {
|
|
instanceFieldSize += packSize - delta;
|
|
}
|
|
}
|
|
instanceFieldSize += fieldSize;
|
|
}
|
|
}
|
|
}
|
|
if (instanceFieldSize > classSize) {
|
|
return instanceFieldSize;
|
|
}
|
|
else if (classSize > 0) {
|
|
return classSize;
|
|
}
|
|
else {
|
|
return 1;
|
|
}
|
|
}
|
|
case ElementTypes.ARRAY: {
|
|
int elementCount = 1;
|
|
uint[] lowerBounds = fieldType.LowerBounds;
|
|
uint[] upperBounds = fieldType.UpperBounds;
|
|
int rank = upperBounds.Length;
|
|
for (int i = 0; i < rank; i++) {
|
|
int dimSize = (int) (upperBounds[i] - lowerBounds[i]);
|
|
if (dimSize == 0) {
|
|
// Must be an array of pointers to other arrays
|
|
return elementCount * machineIntSize;
|
|
}
|
|
else {
|
|
elementCount *= dimSize;
|
|
}
|
|
}
|
|
int elementSize = this.getFieldSize(fieldType.TypeObject);
|
|
return elementCount * elementSize;
|
|
}
|
|
case ElementTypes.CMOD_REQD:
|
|
case ElementTypes.CMOD_OPT:
|
|
return this.getFieldSize(fieldType.TypeObject);
|
|
case ElementTypes.PINNED:
|
|
return this.getFieldSize(fieldType.TypeObject);
|
|
case ElementTypes.SZARRAY:
|
|
// Should be machine dependent!
|
|
return 4;
|
|
case ElementTypes.SENTINEL:
|
|
case ElementTypes.END:
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Debug Methods
|
|
|
|
public override String ToString() {
|
|
System.Text.StringBuilder sb =
|
|
new System.Text.StringBuilder("MetaDataFieldRVA(");
|
|
sb.Append(this.field);
|
|
sb.Append(",");
|
|
if (this.dataBytes == null) {
|
|
sb.Append(this.rva);
|
|
}
|
|
else {
|
|
sb.Append("[");
|
|
int count = this.dataBytes.Length;
|
|
if (count > 0) {
|
|
sb.Append(this.dataBytes[0].ToString("x2"));
|
|
for (int i = 1; i < count; i++) {
|
|
sb.Append(",");
|
|
sb.Append(this.dataBytes[i].ToString("x2"));
|
|
}
|
|
}
|
|
sb.Append("]");
|
|
}
|
|
sb.Append(")");
|
|
return sb.ToString();
|
|
}
|
|
|
|
// State
|
|
|
|
private readonly int rva;
|
|
private byte[] dataBytes;
|
|
private readonly MetaDataField field;
|
|
|
|
// BUGBUG: Should be machine dependent!
|
|
private const int machineIntSize = 4;
|
|
|
|
}
|
|
|
|
}
|