singrdk/base/Windows/mkmsil/msil/MetaDataFieldRVA.cs

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;
}
}