Math.NET Numerics
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

4182 lines
198 KiB

// (c) Microsoft Corporation 2005-2009.
#light
//---------------------------------------------------------------------
// The big binary reader
//
//---------------------------------------------------------------------
module Microsoft.FSharp.Compiler.AbstractIL.BinaryReader
open System.IO
open System.Collections.Generic
open Internal.Utilities
open Internal.Utilities.Pervasives
open Microsoft.FSharp.Compiler.AbstractIL
open Microsoft.FSharp.Compiler.AbstractIL.Internal
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Support
open Microsoft.FSharp.Compiler.AbstractIL.Diagnostics
open Microsoft.FSharp.Compiler.AbstractIL.Internal.BinaryConstants
open Microsoft.FSharp.Compiler.AbstractIL.IL
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
open Microsoft.FSharp.Compiler.ErrorLogger
open Microsoft.FSharp.Compiler.Range
type readerOptions =
{ pdbPath: string option;
ilGlobals: ILGlobals;
optimizeForMemory: bool }
let report_ref = ref (fun oc -> ())
let add_report f = let old = !report_ref in report_ref := (fun oc -> old oc; f oc)
let report (oc:TextWriter) = !report_ref oc
let logging = false
let checking = false
let _ = if checking then dprintn "warning : Ilread.checking is on"
let empty_custom_attrs = mk_custom_attrs []
/// Read file from memory mapped files
module MMap =
open System
open System.IO
open System.Runtime.InteropServices
open Microsoft.FSharp.NativeInterop
type HANDLE = nativeint
type ADDR = nativeint
type SIZE_T = nativeint
[<DllImport("kernel32", SetLastError=true)>]
extern bool CloseHandle (HANDLE handler)
[<DllImport("kernel32", SetLastError=true, CharSet=CharSet.Unicode)>]
extern HANDLE CreateFile (string lpFileName,
int dwDesiredAccess,
int dwShareMode,
HANDLE lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
HANDLE hTemplateFile)
[<DllImport("kernel32", SetLastError=true, CharSet=CharSet.Unicode)>]
extern HANDLE CreateFileMapping (HANDLE hFile,
HANDLE lpAttributes,
int flProtect,
int dwMaximumSizeLow,
int dwMaximumSizeHigh,
string lpName)
[<DllImport("kernel32", SetLastError=true)>]
extern ADDR MapViewOfFile (HANDLE hFileMappingObject,
int dwDesiredAccess,
int dwFileOffsetHigh,
int dwFileOffsetLow,
SIZE_T dwNumBytesToMap)
[<DllImport("kernel32", SetLastError=true)>]
extern bool UnmapViewOfFile (ADDR lpBaseAddress)
let INVALID_HANDLE = new IntPtr(-1)
let MAP_READ = 0x0004
let GENERIC_READ = 0x80000000
let NULL_HANDLE = IntPtr.Zero
let FILE_SHARE_NONE = 0x0000
let FILE_SHARE_READ = 0x0001
let FILE_SHARE_WRITE = 0x0002
let FILE_SHARE_READ_WRITE = 0x0003
let CREATE_ALWAYS = 0x0002
let OPEN_EXISTING = 0x0003
let OPEN_ALWAYS = 0x0004
type mmap = { hMap: HANDLE; start:nativeint }
let create fileName =
//printf "fileName = %s\n" fileName;
let hFile = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero )
//printf "hFile = %Lx\n" (hFile.ToInt64());
if ( hFile.Equals(INVALID_HANDLE) ) then
failwithf "CreateFile(0x%08x)" ( Marshal.GetHRForLastWin32Error() );
let protection = 0x00000002 (* ReadOnly *)
//printf "OK! hFile = %Lx\n" (hFile.ToInt64());
let hMap = CreateFileMapping (hFile, IntPtr.Zero, protection, 0,0, null )
ignore(CloseHandle(hFile));
if hMap.Equals(NULL_HANDLE) then
failwithf "CreateFileMapping(0x%08x)" ( Marshal.GetHRForLastWin32Error() );
let start = MapViewOfFile (hMap, MAP_READ,0,0,0n)
if ( start.Equals(IntPtr.Zero) ) then
failwithf "MapViewOfFile(0x%08x)" ( Marshal.GetHRForLastWin32Error() );
{ hMap = hMap; start = start; }
let addr m (i:int) =
m.start + nativeint i
let deref_byte (p:nativeint) =
NativePtr.read (NativePtr.of_nativeint<byte> p) |> int32
let read_byte m i =
deref_byte (addr m i)
let read_bytes m i len =
let res = Bytes.zero_create len
Marshal.Copy(addr m i, res, 0,len);
res
let read_i32 m i =
NativePtr.read (NativePtr.of_nativeint<int32> (addr m i))
let read_u16_as_i32 m i =
NativePtr.read (NativePtr.of_nativeint<uint16> (addr m i)) |> int32
let close m =
ignore(UnmapViewOfFile ( m.start ));
ignore(CloseHandle ( m.hMap ))
let count_utf8_string m i =
let start = addr m i
let mutable p = start
while deref_byte p <> 0 do
p <- p+1n
int (p-start)
let read_utf8_string m i =
let n = count_utf8_string m i
new System.String(NativePtr.of_nativeint (addr m i), 0, n, System.Text.Encoding.UTF8)
module MMapChannel =
type t =
{ mutable mmPos: int;
mmMap: MMap.mmap }
let open_in f =
let mmap = MMap.create f
{ mmPos = 0; mmMap = mmap }
let input_byte mc =
let res = MMap.read_byte mc.mmMap mc.mmPos
mc.mmPos <- mc.mmPos + 1;
res
let input_i32 mc =
let res = MMap.read_i32 mc.mmMap mc.mmPos
mc.mmPos <- mc.mmPos + 4;
res
let input_u16_as_i32 mc =
let res = MMap.read_u16_as_i32 mc.mmMap mc.mmPos
mc.mmPos <- mc.mmPos + 2;
res
let input_bytes mc len =
let res = MMap.read_bytes mc.mmMap mc.mmPos len
mc.mmPos <- mc.mmPos + len;
res
let peek_utf8_string mc =
MMap.read_utf8_string mc.mmMap mc.mmPos
let seek mc addr = mc.mmPos <- addr
let close mc = MMap.close mc.mmMap
/// Read file into cached memory blocks to avoid taking any kind of a
/// lock on the file, and avoid needing any cleanup of files.
module MemChannel =
type mem_in_channel =
{ mutable mcPos: int;
mcBlocks: byte[] }
let open_in f =
let mcBlocks = System.IO.File.ReadAllBytes f
{ mcPos = 0; mcBlocks = mcBlocks }
let input_byte mc =
let p = mc.mcPos
let res = int mc.mcBlocks.[p]
mc.mcPos <- p + 1;
res
let input_bytes mc len =
let p = mc.mcPos
let res = Array.sub mc.mcBlocks p len
mc.mcPos <- p + len;
res
let seek mc addr =
mc.mcPos <- addr
(*---------------------------------------------------------------------
* Read file from cached memory blocks or via 'seek'
*---------------------------------------------------------------------*)
type input =
/// REVIEW: use a BinaryReader directly
| Chan of string * in_channel option ref
| Mem of MemChannel.mem_in_channel
| MMap of MMapChannel.t
let input_byte is =
match is with
| Chan (_,{contents=Some ic}) -> Pervasives.input_byte ic
| Chan (s,_) -> failwith ("input_byte: input channel "^s^" was closed" )
| Mem mc -> MemChannel.input_byte mc
| MMap mc -> MMapChannel.input_byte mc
let seek is addr =
match is with
| Chan (_,{contents=Some ic}) -> Pervasives.seek_in ic ( addr)
| Chan (s,_) -> failwith ("seek: input channel "^s^" was closed" )
| Mem mc -> MemChannel.seek mc ( addr)
| MMap mc -> MMapChannel.seek mc ( addr)
let read_bytes is len =
match is with
| Chan (_,{contents=Some ic}) -> Bytes.really_input ic ( len)
| Chan (s,_) -> failwith ("read_bytes: input channel "^s^" was closed" )
| Mem mc -> MemChannel.input_bytes mc ( len)
| MMap mc -> MMapChannel.input_bytes mc ( len)
let read_i64 is =
let b0 = input_byte is
let b1 = input_byte is
let b2 = input_byte is
let b3 = input_byte is
let b4 = input_byte is
let b5 = input_byte is
let b6 = input_byte is
let b7 = input_byte is
int64 b0 ||| (int64 b1 <<< 8) ||| (int64 b2 <<< 16) ||| (int64 b3 <<< 24) |||
(int64 b4 <<< 32) ||| (int64 b5 <<< 40) ||| (int64 b6 <<< 48) ||| (int64 b7 <<< 56)
let read_i32 is =
match is with
| Chan (_,{contents=Some ic}) -> Pervasives.input_binary_int ic
| Chan (s,_) -> failwith ("read_bytes: input channel "^s^" was closed" )
| MMap mm -> MMapChannel.input_i32 mm
| Mem _ ->
let b0 = input_byte is
let b1 = input_byte is
let b2 = input_byte is
let b3 = input_byte is
b0 ||| (b1 <<< 8) ||| (b2 <<< 16) ||| (b3 <<< 24)
(*---------------------------------------------------------------------
* Derived reading
*---------------------------------------------------------------------*)
let read_u16_as_i32 is =
match is with
| MMap mm -> MMapChannel.input_u16_as_i32 mm
| _ ->
let b0 = input_byte is
let b1 = input_byte is
b0 ||| (b1 <<< 8)
let read_u16 is = uint16 (read_u16_as_i32 is)
let read_u8_as_i32 is =
let b0 = input_byte is
b0
let read_u8_as_u16 is = uint16 (read_u8_as_i32 is)
let read_i8 is =
let b0 = input_byte is
sbyte (byte b0)
let read_i8_as_i32 is = int32 (read_i8 is)
let float32_of_bits (x:int32) = System.BitConverter.ToSingle(System.BitConverter.GetBytes(x),0)
let float_of_bits (x:int64) = System.BitConverter.Int64BitsToDouble(x)
let read_ieee32 is = float32_of_bits (read_i32 is)
let read_ieee64 is = float_of_bits (read_i64 is)
let read_z_unsigned_int32 is =
let b0 = read_u8_as_i32 is
if b0 <= 0x7F then b0
elif b0 <= 0xbf then
let b0 = b0 &&& 0x7f
let b1 = read_u8_as_i32 is
(b0 <<< 8) ||| b1
else
let b0 = b0 &&& 0x3f
let b1 = read_u8_as_i32 is
let b2 = read_u8_as_i32 is
let b3 = read_u8_as_i32 is
(b0 <<< 24) ||| (b1 <<< 16) ||| (b2 <<< 8) ||| b3
let SeekReadInt32 is addr = seek is addr; read_i32 is
let SeekReadInt64 is addr = seek is addr; read_i64 is
let SeekReadUInt16AsInt32 is addr = seek is addr; read_u16_as_i32 is
let SeekReadUInt16 is addr = seek is addr; read_u16 is
let SeekReadByteAsInt32 is addr = seek is addr; read_u8_as_i32 is
let SeekReadByteAsUInt16 is addr = seek is addr; read_u8_as_u16 is
let SeekReadSByte is addr = seek is addr; read_i8 is
let SeekReadSByteAsInt32 is addr = seek is addr; read_i8_as_i32 is
let SeekReadSingle is addr = seek is addr; read_ieee32 is
let SeekReadDouble is addr = seek is addr; read_ieee64 is
let SeekReadBytes is addr len = seek is addr; read_bytes is len
let rec count_utf8_string is n =
let c = input_byte is
if c = 0 then n
else count_utf8_string is (n+1)
let SeekReadUTF8String is addr =
seek is addr;
match is with
| MMap mc ->
// optimized implementation
MMapChannel.peek_utf8_string mc
| _ ->
let n = count_utf8_string is 0
let bytes = SeekReadBytes is addr (n)
Bytes.utf8_bytes_as_string bytes
let ReadBlob is =
let len = read_z_unsigned_int32 is
read_bytes is len
let SeekReadBlob is addr =
seek is addr;
ReadBlob is
let ReadUserString is =
let len = read_z_unsigned_int32 is
Bytes.unicode_bytes_as_string (read_bytes is (len - 1))
let SeekReadUserString is addr =
seek is addr;
ReadUserString is
let ReadGuid is =
read_bytes is 0x10
let SeakReadGuid is addr =
seek is addr;
ReadGuid is
(*---------------------------------------------------------------------
* Utilities.
*---------------------------------------------------------------------*)
let align alignment n = ((n + alignment - 0x1) / alignment) * alignment
let uncoded_token tab idx = (((tag_of_table tab) <<< 24) ||| idx)
let i32_to_uncoded_token tok =
let idx = tok &&& 0xffffff
let tab = tok lsr 24
(Table ( tab), idx)
let read_uncoded_token is = i32_to_uncoded_token (read_i32 is)
#nowarn "65"
type TaggedIndex<'a> =
struct
val tag: 'a
val index : int32
new(tag,index) = { tag=tag; index=index }
end
let uncoded_token_to_tdor (tab,tok) =
let tag =
if tab = tab_TypeDef then tdor_TypeDef
elif tab = tab_TypeRef then tdor_TypeRef
elif tab = tab_TypeSpec then tdor_TypeSpec
else failwith "bad table in uncoded_token_to_tdor"
TaggedIndex(tag,tok)
let uncoded_token_to_mdor (tab,tok) =
let tag =
if tab = tab_Method then mdor_MethodDef
elif tab = tab_MemberRef then mdor_MemberRef
else failwith "bad table in uncoded_token_to_mdor"
TaggedIndex(tag,tok)
let SeekReaduncoded_token is addr =
seek is addr;
read_uncoded_token is
let (|TaggedIndex|) (x:TaggedIndex<'a>) = x.tag, x.index
let read_z_tagged_idx f nbits big is =
let tok = if big then read_i32 is else read_u16_as_i32 is
let tagmask =
if nbits = 1 then 1
elif nbits = 2 then 3
elif nbits = 3 then 7
elif nbits = 4 then 15
elif nbits = 5 then 31
else failwith "too many nbits"
let tag = tok &&& tagmask
let idx = tok lsr nbits
TaggedIndex(f tag, idx)
(*---------------------------------------------------------------------
* Primitives to help read signatures. These do not use the file cursor, but
* pass ar
*---------------------------------------------------------------------*)
let sigptr_check (bytes:byte[]) sigptr =
if checking && sigptr >= bytes.Length then failwith "read past end of sig. "
let sigptr_get_byte (bytes:byte[]) sigptr =
sigptr_check bytes sigptr;
int(bytes.[sigptr]), sigptr + 1
let sigptr_get_bool bytes sigptr =
let b0,sigptr = sigptr_get_byte bytes sigptr
(b0 = 0x01) ,sigptr
let sigptr_get_u8 bytes sigptr =
let b0,sigptr = sigptr_get_byte bytes sigptr
byte b0,sigptr
let sigptr_get_i8 bytes sigptr =
let i,sigptr = sigptr_get_u8 bytes sigptr
sbyte i,sigptr
let sigptr_get_u16 bytes sigptr =
let b0,sigptr = sigptr_get_byte bytes sigptr
let b1,sigptr = sigptr_get_byte bytes sigptr
uint16 (b0 ||| (b1 <<< 8)),sigptr
let sigptr_get_i16 bytes sigptr =
let u,sigptr = sigptr_get_u16 bytes sigptr
int16 u,sigptr
let sigptr_get_i32 bytes sigptr =
sigptr_check bytes sigptr;
let b0 = int bytes.[sigptr]
let b1 = int bytes.[sigptr+1]
let b2 = int bytes.[sigptr+2]
let b3 = int bytes.[sigptr+3]
let res = b0 ||| (b1 <<< 8) ||| (b2 <<< 16) ||| (b3 <<< 24)
res, sigptr + 4
let sigptr_get_u32 bytes sigptr =
let u,sigptr = sigptr_get_i32 bytes sigptr
uint32 u,sigptr
let sigptr_get_u64 bytes sigptr =
let u0,sigptr = sigptr_get_u32 bytes sigptr
let u1,sigptr = sigptr_get_u32 bytes sigptr
(uint64 u0 ||| (uint64 u1 <<< 32)),sigptr
let sigptr_get_i64 bytes sigptr =
let u,sigptr = sigptr_get_u64 bytes sigptr
int64 u,sigptr
let sigptr_get_ieee32 bytes sigptr =
let u,sigptr = sigptr_get_i32 bytes sigptr
float32_of_bits u,sigptr
let sigptr_get_ieee64 bytes sigptr =
let u,sigptr = sigptr_get_i64 bytes sigptr
float_of_bits u,sigptr
let sigptr_get_z_i32 bytes sigptr =
let b0,sigptr = sigptr_get_byte bytes sigptr
if b0 <= 0x7F then b0, sigptr
elif b0 <= 0xbf then
let b0 = b0 &&& 0x7f
let b1,sigptr = sigptr_get_byte bytes sigptr
(b0 <<< 8) ||| b1, sigptr
else
let b0 = b0 &&& 0x3f
let b1,sigptr = sigptr_get_byte bytes sigptr
let b2,sigptr = sigptr_get_byte bytes sigptr
let b3,sigptr = sigptr_get_byte bytes sigptr
(b0 <<< 24) ||| (b1 <<< 16) ||| (b2 <<< 8) ||| b3, sigptr
let rec sigptr_foldi_acc f n (bytes:byte[]) (sigptr:int) i acc =
if i < n then
let x,sp = f bytes sigptr
sigptr_foldi_acc f n bytes sp (i+1) (x::acc)
else
List.rev acc, sigptr
let sigptr_foldi f n (bytes:byte[]) (sigptr:int) =
sigptr_foldi_acc f n bytes sigptr 0 []
let sigptr_get_bytes n bytes sigptr =
if checking && sigptr + n >= Bytes.length bytes then
dprintn "read past end of sig. in sigptr_get_string";
Bytes.zero_create 0, sigptr
else
let res = Bytes.zero_create n
for i = 0 to (n - 1) do
Bytes.set res i (Bytes.get bytes (sigptr + i))
res, sigptr + n
let sigptr_get_string n bytes sigptr =
let bytearray,sigptr = sigptr_get_bytes n bytes sigptr
Bytes.utf8_bytes_as_string bytearray,sigptr
(* --------------------------------------------------------------------
* Now the tables of instructions
* -------------------------------------------------------------------- *)
[<StructuralEquality(false); StructuralComparison(false)>]
type prefixes =
{ mutable al:Alignment;
mutable tl:Tailcall;
mutable vol:Volatility;
mutable ro:ReadonlySpec;
mutable constrained: ILType option}
let no_prefixes mk prefixes =
if prefixes.al <> Aligned then failwith "an unaligned prefix is not allowed here";
if prefixes.vol <> Nonvolatile then failwith "a volatile prefix is not allowed here";
if prefixes.tl <> Normalcall then failwith "a tailcall prefix is not allowed here";
if prefixes.ro <> NormalAddress then failwith "a readonly prefix is not allowed here";
if prefixes.constrained <> None then failwith "a constrained prefix is not allowed here";
mk
let volatile_unaligned_prefix mk prefixes =
if prefixes.tl <> Normalcall then failwith "a tailcall prefix is not allowed here";
if prefixes.constrained <> None then failwith "a constrained prefix is not allowed here";
if prefixes.ro <> NormalAddress then failwith "a readonly prefix is not allowed here";
mk (prefixes.al,prefixes.vol)
let volatile_prefix mk prefixes =
if prefixes.al <> Aligned then failwith "an unaligned prefix is not allowed here";
if prefixes.tl <> Normalcall then failwith "a tailcall prefix is not allowed here";
if prefixes.constrained <> None then failwith "a constrained prefix is not allowed here";
if prefixes.ro <> NormalAddress then failwith "a readonly prefix is not allowed here";
mk prefixes.vol
let tail_prefix mk prefixes =
if prefixes.al <> Aligned then failwith "an unaligned prefix is not allowed here";
if prefixes.vol <> Nonvolatile then failwith "a volatile prefix is not allowed here";
if prefixes.constrained <> None then failwith "a constrained prefix is not allowed here";
if prefixes.ro <> NormalAddress then failwith "a readonly prefix is not allowed here";
mk prefixes.tl
let constraint_tail_prefix mk prefixes =
if prefixes.al <> Aligned then failwith "an unaligned prefix is not allowed here";
if prefixes.vol <> Nonvolatile then failwith "a volatile prefix is not allowed here";
if prefixes.ro <> NormalAddress then failwith "a readonly prefix is not allowed here";
mk (prefixes.constrained,prefixes.tl )
let readonly_prefix mk prefixes =
if prefixes.al <> Aligned then failwith "an unaligned prefix is not allowed here";
if prefixes.vol <> Nonvolatile then failwith "a volatile prefix is not allowed here";
if prefixes.tl <> Normalcall then failwith "a tailcall prefix is not allowed here";
if prefixes.constrained <> None then failwith "a constrained prefix is not allowed here";
mk prefixes.ro
[<StructuralEquality(false); StructuralComparison(false)>]
type instr_decoder =
| I_u16_u8_instr of (prefixes -> uint16 -> ILInstr)
| I_u16_u16_instr of (prefixes -> uint16 -> ILInstr)
| I_none_instr of (prefixes -> ILInstr)
| I_i64_instr of (prefixes -> int64 -> ILInstr)
| I_i32_i32_instr of (prefixes -> int32 -> ILInstr)
| I_i32_i8_instr of (prefixes -> int32 -> ILInstr)
| I_r4_instr of (prefixes -> single -> ILInstr)
| I_r8_instr of (prefixes -> double -> ILInstr)
| I_field_instr of (prefixes -> ILFieldSpec -> ILInstr)
| I_method_instr of (prefixes -> ILMethodSpec * varargs -> ILInstr)
| I_unconditional_i32_instr of (prefixes -> ILCodeLabel -> ILInstr)
| I_unconditional_i8_instr of (prefixes -> ILCodeLabel -> ILInstr)
| I_conditional_i32_instr of (prefixes -> ILCodeLabel * ILCodeLabel -> ILInstr)
| I_conditional_i8_instr of (prefixes -> ILCodeLabel * ILCodeLabel -> ILInstr)
| I_string_instr of (prefixes -> string -> ILInstr)
| I_switch_instr of (prefixes -> ILCodeLabel list * ILCodeLabel -> ILInstr)
| I_tok_instr of (prefixes -> ILTokenSpec -> ILInstr)
| I_sig_instr of (prefixes -> ILCallingSignature * varargs -> ILInstr)
| I_type_instr of (prefixes -> ILType -> ILInstr)
| I_invalid_instr
let mk_stind dt = volatile_unaligned_prefix (fun (x,y) -> I_stind(x,y,dt))
let mk_ldind dt = volatile_unaligned_prefix (fun (x,y) -> I_ldind(x,y,dt))
let instrs () =
[ i_ldarg_s, I_u16_u8_instr (no_prefixes (fun x -> I_ldarg x));
i_starg_s, I_u16_u8_instr (no_prefixes (fun x -> I_starg x));
i_ldarga_s, I_u16_u8_instr (no_prefixes (fun x -> I_ldarga x));
i_stloc_s, I_u16_u8_instr (no_prefixes (fun x -> I_stloc x));
i_ldloc_s, I_u16_u8_instr (no_prefixes (fun x -> I_ldloc x));
i_ldloca_s, I_u16_u8_instr (no_prefixes (fun x -> I_ldloca x));
i_ldarg, I_u16_u16_instr (no_prefixes (fun x -> I_ldarg x));
i_starg, I_u16_u16_instr (no_prefixes (fun x -> I_starg x));
i_ldarga, I_u16_u16_instr (no_prefixes (fun x -> I_ldarga x));
i_stloc, I_u16_u16_instr (no_prefixes (fun x -> I_stloc x));
i_ldloc, I_u16_u16_instr (no_prefixes (fun x -> I_ldloc x));
i_ldloca, I_u16_u16_instr (no_prefixes (fun x -> I_ldloca x));
i_stind_i, I_none_instr (mk_stind DT_I);
i_stind_i1, I_none_instr (mk_stind DT_I1);
i_stind_i2, I_none_instr (mk_stind DT_I2);
i_stind_i4, I_none_instr (mk_stind DT_I4);
i_stind_i8, I_none_instr (mk_stind DT_I8);
i_stind_r4, I_none_instr (mk_stind DT_R4);
i_stind_r8, I_none_instr (mk_stind DT_R8);
i_stind_ref, I_none_instr (mk_stind DT_REF);
i_ldind_i, I_none_instr (mk_ldind DT_I);
i_ldind_i1, I_none_instr (mk_ldind DT_I1);
i_ldind_i2, I_none_instr (mk_ldind DT_I2);
i_ldind_i4, I_none_instr (mk_ldind DT_I4);
i_ldind_i8, I_none_instr (mk_ldind DT_I8);
i_ldind_u1, I_none_instr (mk_ldind DT_U1);
i_ldind_u2, I_none_instr (mk_ldind DT_U2);
i_ldind_u4, I_none_instr (mk_ldind DT_U4);
i_ldind_r4, I_none_instr (mk_ldind DT_R4);
i_ldind_r8, I_none_instr (mk_ldind DT_R8);
i_ldind_ref, I_none_instr (mk_ldind DT_REF);
i_cpblk, I_none_instr (volatile_unaligned_prefix (fun (x,y) -> I_cpblk(x,y)));
i_initblk, I_none_instr (volatile_unaligned_prefix (fun (x,y) -> I_initblk(x,y)));
i_ldc_i8, I_i64_instr (no_prefixes (fun x ->I_arith (AI_ldc (DT_I8, NUM_I8 x))));
i_ldc_i4, I_i32_i32_instr (no_prefixes (fun x -> ((mk_ldc_i32 x))));
i_ldc_i4_s, I_i32_i8_instr (no_prefixes (fun x -> ((mk_ldc_i32 x))));
i_ldc_r4, I_r4_instr (no_prefixes (fun x -> I_arith (AI_ldc (DT_R4, NUM_R4 x))));
i_ldc_r8, I_r8_instr (no_prefixes (fun x -> I_arith (AI_ldc (DT_R8, NUM_R8 x))));
i_ldfld, I_field_instr (volatile_unaligned_prefix(fun (x,y) fspec -> I_ldfld(x,y,fspec)));
i_stfld, I_field_instr (volatile_unaligned_prefix(fun (x,y) fspec -> I_stfld(x,y,fspec)));
i_ldsfld, I_field_instr (volatile_prefix (fun x fspec -> I_ldsfld (x, fspec)));
i_stsfld, I_field_instr (volatile_prefix (fun x fspec -> I_stsfld (x, fspec)));
i_ldflda, I_field_instr (no_prefixes (fun fspec -> I_ldflda fspec));
i_ldsflda, I_field_instr (no_prefixes (fun fspec -> I_ldsflda fspec));
i_call, I_method_instr (tail_prefix (fun tl (mspec,y) -> I_call (tl,mspec,y)));
i_ldftn, I_method_instr (no_prefixes (fun (mspec,y) -> I_ldftn mspec));
i_ldvirtftn, I_method_instr (no_prefixes (fun (mspec,y) -> I_ldvirtftn mspec));
i_newobj, I_method_instr (no_prefixes (fun (mspec,y) -> I_newobj (mspec,y)));
i_callvirt, I_method_instr (constraint_tail_prefix (fun (c,tl) (mspec,y) -> match c with Some ty -> I_callconstraint(tl,ty,mspec,y) | None -> I_callvirt (tl,mspec,y)));
i_leave_s, I_unconditional_i8_instr (no_prefixes (fun x -> I_leave x));
i_br_s, I_unconditional_i8_instr (no_prefixes (fun x -> I_br x));
i_leave, I_unconditional_i32_instr (no_prefixes (fun x -> I_leave x));
i_br, I_unconditional_i32_instr (no_prefixes (fun x -> I_br x));
i_brtrue_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_brtrue,x,y)));
i_brfalse_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_brfalse,x,y)));
i_beq_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_beq,x,y)));
i_blt_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_blt,x,y)));
i_blt_un_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_blt_un,x,y)));
i_ble_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_ble,x,y)));
i_ble_un_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_ble_un,x,y)));
i_bgt_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bgt,x,y)));
i_bgt_un_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bgt_un,x,y)));
i_bge_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bge,x,y)));
i_bge_un_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bge_un,x,y)));
i_bne_un_s, I_conditional_i8_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bne_un,x,y)));
i_brtrue, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_brtrue,x,y)));
i_brfalse, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_brfalse,x,y)));
i_beq, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_beq,x,y)));
i_blt, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_blt,x,y)));
i_blt_un, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_blt_un,x,y)));
i_ble, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_ble,x,y)));
i_ble_un, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_ble_un,x,y)));
i_bgt, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bgt,x,y)));
i_bgt_un, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bgt_un,x,y)));
i_bge, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bge,x,y)));
i_bge_un, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bge_un,x,y)));
i_bne_un, I_conditional_i32_instr (no_prefixes (fun (x,y) -> I_brcmp (BI_bne_un,x,y)));
i_ldstr, I_string_instr (no_prefixes (fun x -> I_ldstr x));
i_switch, I_switch_instr (no_prefixes (fun x -> I_switch x));
i_ldtoken, I_tok_instr (no_prefixes (fun x -> I_ldtoken x));
i_calli, I_sig_instr (tail_prefix (fun tl (x,y) -> I_calli (tl, x, y)));
i_mkrefany, I_type_instr (no_prefixes (fun x -> I_mkrefany x));
i_refanyval, I_type_instr (no_prefixes (fun x -> I_refanyval x));
i_ldelema, I_type_instr (readonly_prefix (fun ro x -> I_ldelema (ro,Rank1ArrayShape,x)));
i_ldelem_any, I_type_instr (no_prefixes (fun x -> I_ldelem_any (Rank1ArrayShape,x)));
i_stelem_any, I_type_instr (no_prefixes (fun x -> I_stelem_any (Rank1ArrayShape,x)));
i_newarr, I_type_instr (no_prefixes (fun x -> I_newarr (Rank1ArrayShape,x)));
i_castclass, I_type_instr (no_prefixes (fun x -> I_castclass x));
i_isinst, I_type_instr (no_prefixes (fun x -> I_isinst x));
i_unbox_any, I_type_instr (no_prefixes (fun x -> I_unbox_any x));
i_cpobj, I_type_instr (no_prefixes (fun x -> I_cpobj x));
i_initobj, I_type_instr (no_prefixes (fun x -> I_initobj x));
i_ldobj, I_type_instr (volatile_unaligned_prefix (fun (x,y) z -> I_ldobj (x,y,z)));
i_stobj, I_type_instr (volatile_unaligned_prefix (fun (x,y) z -> I_stobj (x,y,z)));
i_sizeof, I_type_instr (no_prefixes (fun x -> I_sizeof x));
i_box, I_type_instr (no_prefixes (fun x -> I_box x));
i_unbox, I_type_instr (no_prefixes (fun x -> I_unbox x)); ]
(* The tables are delayed to avoid building them unnecessarily at startup *)
(* Many applications of AbsIL (e.g. a compiler) don't need to read instructions. *)
let one_byte_instrs = ref None
let two_byte_instrs = ref None
let fill_instrs () =
let one_byte_tab = Array.create 256 I_invalid_instr
let two_byte_tab = Array.create 256 I_invalid_instr
let add_instr (i,f) =
if i > 0xff then
assert (i lsr 8 = 0xfe);
let i = (i &&& 0xff)
if (two_byte_tab.[i] <> I_invalid_instr) then
dprintn ("warning: duplicate decode entries for "^string i);
two_byte_tab.[i] <- f
else
if (one_byte_tab.[i] <> I_invalid_instr) then
dprintn ("warning: duplicate decode entries for "^string i);
one_byte_tab.[i] <- f
List.iter add_instr (instrs());
List.iter (fun (x,mk) -> add_instr (x,I_none_instr (no_prefixes mk))) (noarg_instrs.Force());
one_byte_instrs := Some one_byte_tab;
two_byte_instrs := Some two_byte_tab
let rec get_one_byte_instr i =
match !one_byte_instrs with
| None -> fill_instrs(); get_one_byte_instr i
| Some t -> t.[i]
let rec get_two_byte_instr i =
match !two_byte_instrs with
| None -> fill_instrs(); get_two_byte_instr i
| Some t -> t.[i]
(*---------------------------------------------------------------------
*
*---------------------------------------------------------------------*)
type chunk = { size: int32; addr: int32 }
let chunk sz next = ({addr=next; size=sz},next + sz)
let nochunk next = ({addr= 0x0;size= 0x0; } ,next)
type row_element_kind =
| UShort
| ULong
| Byte
| Data
| GGuid
| Blob
| SString
| SimpleIndex of table
| TypeDefOrRefOrSpec
| TypeOrMethodDef
| HasConstant
| HasCustomAttribute
| HasFieldMarshal
| HasDeclSecurity
| MemberRefParent
| HasSemantics
| MethodDefOrRef
| MemberForwarded
| Implementation
| CustomAttributeType
| ResolutionScope
type row_kind = RowKind of row_element_kind list
let kind_AssemblyRef = RowKind [ UShort; UShort; UShort; UShort; ULong; Blob; SString; SString; Blob; ]
let kind_ModuleRef = RowKind [ SString ]
let kind_FileRef = RowKind [ ULong; SString; Blob ]
let kind_TypeRef = RowKind [ ResolutionScope; SString; SString ]
let kind_TypeSpec = RowKind [ Blob ]
let kind_TypeDef = RowKind [ ULong; SString; SString; TypeDefOrRefOrSpec; SimpleIndex tab_Field; SimpleIndex tab_Method ]
let kind_PropertyMap = RowKind [ SimpleIndex tab_TypeDef; SimpleIndex tab_Property ]
let kind_EventMap = RowKind [ SimpleIndex tab_TypeDef; SimpleIndex tab_Event ]
let kind_InterfaceImpl = RowKind [ SimpleIndex tab_TypeDef; TypeDefOrRefOrSpec ]
let kind_Nested = RowKind [ SimpleIndex tab_TypeDef; SimpleIndex tab_TypeDef ]
let kind_CustomAttribute = RowKind [HasCustomAttribute; CustomAttributeType; Blob ]
let kind_DeclSecurity = RowKind [ UShort; HasDeclSecurity; Blob ]
let kind_MemberRef = RowKind [MemberRefParent; SString; Blob ]
let kind_StandAloneSig = RowKind [Blob ]
let kind_FieldDef = RowKind [UShort; SString; Blob ]
let kind_FieldRVA = RowKind [Data; SimpleIndex tab_Field ]
let kind_FieldMarshal = RowKind [HasFieldMarshal; Blob ]
let kind_Constant = RowKind [ UShort;HasConstant; Blob ]
let kind_FieldLayout = RowKind [ULong; SimpleIndex tab_Field ]
let kind_Param = RowKind [ UShort; UShort; SString ]
let kind_MethodDef = RowKind [ULong; UShort; UShort; SString; Blob; SimpleIndex tab_Param ]
let kind_MethodImpl = RowKind [SimpleIndex tab_TypeDef; MethodDefOrRef; MethodDefOrRef ]
let kind_ImplMap = RowKind [UShort; MemberForwarded; SString; SimpleIndex tab_ModuleRef ]
let kind_MethodSemantics = RowKind [UShort; SimpleIndex tab_Method; HasSemantics ]
let kind_Property =RowKind [ UShort; SString; Blob ]
let kind_Event =RowKind [ UShort; SString; TypeDefOrRefOrSpec ]
let kind_ManifestResource =RowKind [ ULong; ULong; SString; Implementation ]
let kind_ClassLayout = RowKind [ UShort; ULong; SimpleIndex tab_TypeDef ]
let kind_ExportedType = RowKind [ ULong; ULong; SString; SString; Implementation ]
let kind_Assembly = RowKind [ ULong; UShort; UShort; UShort; UShort; ULong; Blob; SString; SString ]
let kind_GenericParam_v1_1 = RowKind [ UShort; UShort; TypeOrMethodDef; SString; TypeDefOrRefOrSpec ]
let kind_GenericParam_v2_0 = RowKind [ UShort; UShort; TypeOrMethodDef; SString ]
let kind_MethodSpec = RowKind [ MethodDefOrRef; Blob ]
let kind_GenericParamConstraint = RowKind [ SimpleIndex tab_GenericParam; TypeDefOrRefOrSpec ]
let kind_Module = RowKind [ UShort; SString; GGuid; GGuid; GGuid ]
let kind_Illegal = RowKind []
(*---------------------------------------------------------------------
* Used for binary searches of sorted tables. Each function that reads
* a table row returns a tuple that contains the elements of the row.
* One of these elements may be a key for a sorted table. These
* keys can be compared using the functions below depending on the
* kind of element in that column.
*---------------------------------------------------------------------*)
let hc_compare (TaggedIndex(HasConstantTag t1, (idx1:int))) (TaggedIndex(HasConstantTag t2, idx2)) =
if idx1 < idx2 then -1 elif idx1 > idx2 then 1 else compare t1 t2
let hs_compare (TaggedIndex(HasSemanticsTag t1, (idx1:int))) (TaggedIndex(HasSemanticsTag t2, idx2)) =
if idx1 < idx2 then -1 elif idx1 > idx2 then 1 else compare t1 t2
let hca_compare (TaggedIndex(HasCustomAttributeTag t1, (idx1:int))) (TaggedIndex(HasCustomAttributeTag t2, idx2)) =
if idx1 < idx2 then -1 elif idx1 > idx2 then 1 else compare t1 t2
let mf_compare (TaggedIndex(MemberForwardedTag t1, (idx1:int))) (TaggedIndex(MemberForwardedTag t2, idx2)) =
if idx1 < idx2 then -1 elif idx1 > idx2 then 1 else compare t1 t2
let hds_compare (TaggedIndex(HasDeclSecurityTag t1, (idx1:int))) (TaggedIndex(HasDeclSecurityTag t2, idx2)) =
if idx1 < idx2 then -1 elif idx1 > idx2 then 1 else compare t1 t2
let hfm_compare (TaggedIndex(HasFieldMarshalTag t1, idx1)) (TaggedIndex(HasFieldMarshalTag t2, idx2)) =
if idx1 < idx2 then -1 elif idx1 > idx2 then 1 else compare t1 t2
let tomd_compare (TaggedIndex(TypeOrMethodDefTag t1, idx1)) (TaggedIndex(TypeOrMethodDefTag t2, idx2)) =
if idx1 < idx2 then -1 elif idx1 > idx2 then 1 else compare t1 t2
let simpleindex_compare (idx1:int) (idx2:int) =
compare idx1 idx2
(*---------------------------------------------------------------------
* The various keys for the various caches. We avoid using polymorphic
* types within keys becuase F# is not crash hot at hashing and compare
* them. In other words, the types in the indexes below should not
* use (real) tuples, lists, options etc. We also add a couple of
* hashtables indexed by integers since these are also much faster
* for F#.
*---------------------------------------------------------------------*)
type typeDefAsTypIdx = TypeDefAsTypIdx of ILBoxity * ILGenericArgs * int
type typeRefAsTypIdx = TypeRefAsTypIdx of ILBoxity * ILGenericArgs * int
type blobAsMethodSigIdx = BlobAsMethodSigIdx of int * int32
type blobAsFieldSigIdx = BlobAsFieldSigIdx of int * int32
type blobAsPropSigIdx = BlobAsPropSigIdx of int * int32
type blobAsLocalSigIdx = BlobAsLocalSigIdx of int * int32
type memberRefAsMspecIdx = MemberRefAsMspecIdx of int * int
type methodSpecAsMspecIdx = MethodSpecAsMspecIdx of int * int
type memberRefAsFspecIdx = MemberRefAsFspecIdx of int * int
type customAttrIdx = CustomAttrIdx of customAttributeType_tag * int * int32
type securityDeclIdx = SecurityDeclIdx of uint16 * int32
type genericParsIdx = GenericParamsIdx of int * typeOrMethodDef_tag * int
(*---------------------------------------------------------------------
* Polymorphic caches for row and heap readers
*---------------------------------------------------------------------*)
module I32hashtbl =
type 'a t = System.Collections.Generic.Dictionary<int32,'a>
let create (n:int) : 'a t = new System.Collections.Generic.Dictionary<_,_>(n)
let add (t: 'a t) x y = t.Add(x,y)
let find (t: 'a t) x = t.Item(x)
let mem (t: 'a t) x = t.ContainsKey(x)
let mk_cache_int32 lowMem inbase nm sz =
if lowMem then (fun f x -> f x) else
let cache = ref null in // I32hashtbl.create 11 (* sz *)
let count = ref 0
add_report (fun oc -> if !count <> 0 then output_string oc (inbase^string !count ^ " "^nm^" cache hits"^"\n"));
fun f (idx:int32) ->
let cache =
match !cache with
| null -> cache := I32hashtbl.create 11 (* sz *)
| _ -> ()
!cache
if I32hashtbl.mem cache idx then (incr count; I32hashtbl.find cache idx)
else let res = f idx in I32hashtbl.add cache idx res; res
let mk_cache_gen lowMem inbase nm sz =
if lowMem then (fun f x -> f x) else
let cache = ref null in // I32hashtbl.create 11 (* sz *)
//let cache = new Dictionary<_,_>(sz:int)
let count = ref 0
add_report (fun oc -> if !count <> 0 then output_string oc (inbase^string !count ^ " "^nm^" cache hits"^"\n"));
fun f (idx :'a) ->
let cache =
match !cache with
| null -> cache := new Dictionary<_,_>(11 (* sz:int *) )
| _ -> ()
!cache
if cache.ContainsKey idx then (incr count; cache.[idx])
else let res = f idx in cache.[idx] <- res; res
(*-----------------------------------------------------------------------
* Polymorphic general helpers for searching for particular rows.
* ----------------------------------------------------------------------*)
let SeekFindRow nrows rowChooser =
let mutable i = 1
while (i <= nrows && not (rowChooser i)) do
i <- i + 1;
if i > nrows then dprintn "warning: SeekFindRow: row not found";
i
// search for rows satisfying predicate
let SeekReadIndexedRows (nrows,rowReader,keyfunc,keycomparef,binchop, rowConverter) =
if binchop then
let mutable low = 0
let mutable high = nrows + 1
begin
let mutable fin = false
while not fin do
(* if logging then dprintn (infile ^ ": binary search of table "^string (tag_of_table tab)^", low = "^string !low^", high = "^string !high);*)
if high - low <= 1 then
fin <- true
else
let mid = (low + high) / 2
let midrow = rowReader mid
let c = keycomparef (keyfunc midrow)
if c > 0 then
low <- mid
elif c < 0 then
high <- mid
else
fin <- true
end;
(* if logging then dprintn (infile ^ ": finished binary search of table "^string (tag_of_table tab));*)
let mutable res = []
if high - low > 1 then
// now read off rows, forward and backwards
let mid = (low + high) / 2
// read forward
begin
let mutable fin = false
let mutable curr = mid
while not fin do
if curr > nrows then
fin <- true;
else
let currrow = rowReader curr
if keycomparef (keyfunc currrow) = 0 then
res <- rowConverter currrow :: res;
else
fin <- true;
curr <- curr + 1;
done;
end;
res <- List.rev res;
// read backwards
begin
let mutable fin = false
let mutable curr = mid - 1
while not fin do
if curr = 0 then
fin <- true
else
let currrow = rowReader curr
if keycomparef (keyfunc currrow) = 0 then
res <- rowConverter currrow :: res;
else
fin <- true;
curr <- curr - 1;
end;
// sanity check
if checking then
let res2 =
[ for i = 1 to nrows do
let rowinfo = rowReader i
if keycomparef (keyfunc rowinfo) = 0 then
yield rowConverter rowinfo ]
if (res2 <> res) then
failwith ("results of binary search did not match results of linear search: linear search produced "^string res2.Length^", binary search produced "^string res.Length)
res
else
let res = ref []
for i = 1 to nrows do
let rowinfo = rowReader i
if keycomparef (keyfunc rowinfo) = 0 then
res := rowConverter rowinfo :: !res;
List.rev !res
let SeekReadOptionalIndexedRow ((nrows,rowReader,keyfunc,keycomparer,binchop,rowConverter) as info) =
match SeekReadIndexedRows info with
| [k] -> Some k
| [] -> None
| h::t ->
dprintn ("multiple rows found when indexing table");
Some h
let SeekReadIndexedRow ((nrows,rowReader,keyfunc,keycomparer,binchop,rowConverter) as info) =
match SeekReadOptionalIndexedRow info with
| Some row -> row
| None -> failwith ("no row found for key when indexing table")
(*---------------------------------------------------------------------
* The big fat reader.
*---------------------------------------------------------------------*)
type ILModuleReader =
{ modul: ILModuleDef;
ilAssemblyRefs: Lazy<ILAssemblyRef list>
dispose: unit -> unit }
member x.ILModuleDef = x.modul
member x.ILAssemblyRefs = x.ilAssemblyRefs.Force()
type method_data = ILType * ILCallingConv * string * ILType list * ILType * ILType list
type vararg_method_data = ILType * ILCallingConv * string * ILType list * ILType list option * ILType * ILType list
[<StructuralEquality(false); StructuralComparison(false)>]
type ctxt =
{ ilg: ILGlobals;
data_end_points: int32 list Lazy.t;
sorted: int64;
pdb: (pdb_reader * (string -> ILSourceDocument)) option;
eptoken: table * int;
nrows: table -> int;
text_phys_loc : int32;
text_phys_size : int32;
data_phys_loc : int32;
data_phys_size : int32;
anyV2P : (string * int32) -> int32;
metadata_addr: int32;
section_headers : (int32 * int32 * int32) list;
native_resources_addr:int32;
native_resources_size:int32;
resources_addr:int32;
strongname_addr:int32;
vtable_fixups_addr:int32;
is:input;
infile:string;
user_strings_stream_phys_loc: int32;
strings_stream_phys_loc: int32;
blobs_stream_phys_loc: int32;
ReadUserStringHeap: (int32 -> string);
MemoizeString: string -> string;
ReadStringHeap: (int32 -> string);
ReadBlobHeap: (int32 -> byte[]);
guids_stream_phys_loc : int32;
row_addr : (table -> int -> int32);
table_bignesses : bool array;
rs_bigness : bool;
tdor_bigness : bool;
tomd_bigness : bool;
hc_bigness : bool;
hca_bigness : bool;
hfm_bigness : bool;
hds_bigness : bool;
mrp_bigness : bool;
hs_bigness : bool;
mdor_bigness : bool;
mf_bigness : bool;
i_bigness : bool;
cat_bigness : bool;
strings_big: bool;
guids_big: bool;
blobs_big: bool;
count_TypeRef : int ref;
count_TypeDef : int ref;
count_Field : int ref;
count_Method : int ref;
count_Param : int ref;
count_InterfaceImpl : int ref;
count_MemberRef : int ref;
count_Constant : int ref;
count_CustomAttribute : int ref;
count_FieldMarshal: int ref;
count_Permission : int ref;
count_ClassLayout : int ref;
count_FieldLayout : int ref;
count_StandAloneSig : int ref;
count_EventMap : int ref;
count_Event : int ref;
count_PropertyMap : int ref;
count_Property : int ref;
count_MethodSemantics : int ref;
count_MethodImpl : int ref;
count_ModuleRef : int ref;
count_TypeSpec : int ref;
count_ImplMap : int ref;
count_FieldRVA : int ref;
count_Assembly : int ref;
count_AssemblyRef : int ref;
count_File : int ref;
count_ExportedType : int ref;
count_ManifestResource : int ref;
count_Nested : int ref;
count_GenericParam : int ref;
count_GenericParamConstraint : int ref;
count_MethodSpec : int ref;
SeekReadNestedRow : int -> int * int;
SeekReadConstantRow : int -> int32 * TaggedIndex<hasConstant_tag> * int32;
SeekReadMethodSemanticsRow : int -> int32 * int * TaggedIndex<hasSemantics_tag>;
SeekReadTypeDefRow : int -> int32 * int32 * int32 * TaggedIndex<typeDefOrRef_tag> * int * int;
SeekReadInterfaceImplRow : int -> int * TaggedIndex<typeDefOrRef_tag>;
SeekReadFieldMarshalRow : int -> TaggedIndex<hasFieldMarshal_tag> * int32;
SeekReadPropertyMapRow : int -> int * int;
SeekReadAssemblyRef : int -> ILAssemblyRef;
SeekReadMethodSpec_as_mdata : methodSpecAsMspecIdx -> vararg_method_data;
SeekReadMemberRef_as_mdata : memberRefAsMspecIdx -> vararg_method_data;
SeekReadMemberRef_as_fspec : memberRefAsFspecIdx -> ILFieldSpec;
SeekReadCustomAttr : customAttrIdx -> ILAttribute;
SeekReadSecurityDecl : securityDeclIdx -> ILPermission;
SeekReadTypeRef : int ->ILTypeRef;
SeekReadTypeRef_as_typ : typeRefAsTypIdx -> ILType;
ReadBlobHeap_as_property_sig : blobAsPropSigIdx -> ILThisConvention * ILType * ILType list;
ReadBlobHeap_as_field_sig : blobAsFieldSigIdx -> ILType;
ReadBlobHeap_as_method_sig : blobAsMethodSigIdx -> bool * int32 * ILCallingConv * ILType * ILType list * ILType list option;
ReadBlobHeap_as_locals_sig : blobAsLocalSigIdx -> Local list;
SeekReadTypeDefAsType : typeDefAsTypIdx -> ILType;
SeekReadMethodDef_as_mdata : int -> method_data;
SeekReadGenericParams : genericParsIdx -> ILGenericParameterDef list;
SeekReadFieldDef_as_fspec : int -> ILFieldSpec; }
let read_z_untagged_idx tab ctxt =
if ctxt.table_bignesses.[tag_of_table tab]
then read_i32 ctxt.is
else read_u16_as_i32 ctxt.is
let read_rs_idx ctxt = read_z_tagged_idx mkResolutionScopeTag 2 ctxt.rs_bigness ctxt.is
let read_tdor_idx ctxt = read_z_tagged_idx mkTypeDefOrRefOrSpecTag 2 ctxt.tdor_bigness ctxt.is
let read_tomd_idx ctxt = read_z_tagged_idx mkTypeOrMethodDefTag 1 ctxt.tomd_bigness ctxt.is
let read_hc_idx ctxt = read_z_tagged_idx mkHasConstantTag 2 ctxt.hc_bigness ctxt.is
let read_hca_idx ctxt = read_z_tagged_idx mkHasCustomAttributeTag 5 ctxt.hca_bigness ctxt.is
let read_hfm_idx ctxt = read_z_tagged_idx mkHasFieldMarshalTag 1 ctxt.hfm_bigness ctxt.is
let read_hds_idx ctxt = read_z_tagged_idx mkHasDeclSecurityTag 2 ctxt.hds_bigness ctxt.is
let read_mrp_idx ctxt = read_z_tagged_idx mkMemberRefParentTag 3 ctxt.mrp_bigness ctxt.is
let read_hs_idx ctxt = read_z_tagged_idx mkHasSemanticsTag 1 ctxt.hs_bigness ctxt.is
let read_mdor_idx ctxt = read_z_tagged_idx mkMethodDefOrRefTag 1 ctxt.mdor_bigness ctxt.is
let read_mf_idx ctxt = read_z_tagged_idx mkMemberForwardedTag 1 ctxt.mf_bigness ctxt.is
let read_i_idx ctxt = read_z_tagged_idx mkImplementationTag 2 ctxt.i_bigness ctxt.is
let read_cat_idx ctxt = read_z_tagged_idx mkCustomAttributeTypeTag 3 ctxt.cat_bigness ctxt.is
let read_string_idx ctxt = if ctxt.strings_big then read_i32 ctxt.is else read_u16_as_i32 ctxt.is
let read_guid_idx ctxt = if ctxt.guids_big then read_i32 ctxt.is else read_u16_as_i32 ctxt.is
let read_blob_idx ctxt = if ctxt.blobs_big then read_i32 ctxt.is else read_u16_as_i32 ctxt.is
let SeekReadModuleRow ctxt idx =
if idx = 0 then failwith "cannot read Module table row 0";
let addr = ctxt.row_addr tab_Module idx
if logging then dprintn (ctxt.infile ^ ": module row addr = " ^ string addr);
seek ctxt.is addr;
let generation = read_u16 ctxt.is
let name_idx = read_string_idx ctxt
let mvid_idx = read_guid_idx ctxt
let encid_idx = read_guid_idx ctxt
let encbaseid_idx = read_guid_idx ctxt
(generation, name_idx, mvid_idx, encid_idx, encbaseid_idx)
/// Read Table ILTypeRef
let SeekReadTypeRefRow ctxt idx =
incr ctxt.count_TypeRef;
let addr = ctxt.row_addr tab_TypeRef idx
seek ctxt.is addr;
let scope_idx = read_rs_idx ctxt
let name_idx = read_string_idx ctxt
let namespace_idx = read_string_idx ctxt
(scope_idx,name_idx,namespace_idx)
/// Read Table ILTypeDef
let SeekReadTypeDefRow ctxt idx = ctxt.SeekReadTypeDefRow idx
let SeekReadTypeDefRowUncached ctxtH idx =
let ctxt = getHole ctxtH
incr ctxt.count_TypeDef;
let addr = ctxt.row_addr tab_TypeDef idx
seek ctxt.is addr;
let flags = read_i32 ctxt.is
let name_idx = read_string_idx ctxt
let namespace_idx = read_string_idx ctxt
let extends_idx = read_tdor_idx ctxt
let fields_idx = read_z_untagged_idx tab_Field ctxt
let methods_idx = read_z_untagged_idx tab_Method ctxt
(flags, name_idx, namespace_idx, extends_idx, fields_idx, methods_idx)
/// Read Table Field
let SeekReadFieldRow ctxt idx =
incr ctxt.count_Field;
let addr = ctxt.row_addr tab_Field idx
seek ctxt.is addr;
let flags = read_u16_as_i32 ctxt.is
let name_idx = read_string_idx ctxt
let type_idx = read_blob_idx ctxt
(flags,name_idx,type_idx)
/// Read Table Method
let SeekReadMethodRow ctxt idx =
incr ctxt.count_Method;
let addr = ctxt.row_addr tab_Method idx
seek ctxt.is addr;
let code_rva = read_i32 ctxt.is
let implflags = read_u16_as_i32 ctxt.is
let flags = read_u16_as_i32 ctxt.is
let name_idx = read_string_idx ctxt
let type_idx = read_blob_idx ctxt
let param_idx = read_z_untagged_idx tab_Param ctxt
(code_rva, implflags, flags, name_idx, type_idx, param_idx)
/// Read Table Param
let SeekReadParamRow ctxt idx =
incr ctxt.count_Param;
let addr = ctxt.row_addr tab_Param idx
seek ctxt.is addr;
let flags = read_u16_as_i32 ctxt.is
let seq = (read_u16_as_i32 ctxt.is)
let name_idx = read_string_idx ctxt
(flags,seq,name_idx)
/// Read Table InterfaceImpl
let SeekReadInterfaceImplRow ctxt idx = ctxt.SeekReadInterfaceImplRow idx
let SeekReadInterfaceImplRowUncached ctxtH idx =
let ctxt = getHole ctxtH
incr ctxt.count_InterfaceImpl;
let addr = ctxt.row_addr tab_InterfaceImpl idx
seek ctxt.is addr;
let tidx = read_z_untagged_idx tab_TypeDef ctxt
let intf_idx = read_tdor_idx ctxt
(tidx,intf_idx)
/// Read Table MemberRef
let SeekReadMemberRefRow ctxt idx =
incr ctxt.count_MemberRef;
let addr = ctxt.row_addr tab_MemberRef idx
seek ctxt.is addr;
let mrp_idx = read_mrp_idx ctxt
let name_idx = read_string_idx ctxt
let type_idx = read_blob_idx ctxt
(mrp_idx,name_idx,type_idx)
/// Read Table Constant
let SeekReadConstantRow ctxt idx = ctxt.SeekReadConstantRow idx
let SeekReadConstantRowUncached ctxtH idx =
let ctxt = getHole ctxtH
incr ctxt.count_Constant;
let addr = ctxt.row_addr tab_Constant idx
seek ctxt.is addr;
let kind = read_u16_as_i32 ctxt.is
let parent_idx = read_hc_idx ctxt
let val_idx = read_blob_idx ctxt
(kind, parent_idx, val_idx)
/// Read Table CustomAttribute
let SeekReadCustomAttributeRow ctxt idx =
incr ctxt.count_CustomAttribute;
let addr = ctxt.row_addr tab_CustomAttribute idx
seek ctxt.is addr;
let parent_idx = read_hca_idx ctxt
let type_idx = read_cat_idx ctxt
let val_idx = read_blob_idx ctxt
(parent_idx, type_idx, val_idx)
/// Read Table FieldMarshal
let SeekReadFieldMarshalRow ctxt idx = ctxt.SeekReadFieldMarshalRow idx
let SeekReadFieldMarshalRowUncached ctxtH idx =
let ctxt = getHole ctxtH
incr ctxt.count_FieldMarshal;
let addr = ctxt.row_addr tab_FieldMarshal idx
seek ctxt.is addr;
let parent_idx = read_hfm_idx ctxt
let type_idx = read_blob_idx ctxt
(parent_idx, type_idx)
/// Read Table Permission
let SeekReadPermissionRow ctxt idx =
incr ctxt.count_Permission;
(* if logging then dprintn (ctxt.infile ^ ": reading Permission row "^string idx); *)
let addr = ctxt.row_addr tab_Permission idx
seek ctxt.is addr;
let action = read_u16 ctxt.is
let parent_idx = read_hds_idx ctxt
let type_idx = read_blob_idx ctxt
(* if logging then dprintn "finished read of Permission row";*)
(action,parent_idx, type_idx)
/// Read Table ClassLayout
let SeekReadClassLayoutRow ctxt idx =
incr ctxt.count_ClassLayout;
let addr = ctxt.row_addr tab_ClassLayout idx
seek ctxt.is addr;
let pack = read_u16 ctxt.is
let size = read_i32 ctxt.is
let tidx = read_z_untagged_idx tab_TypeDef ctxt
(pack,size,tidx)
/// Read Table FieldLayout
let SeekReadFieldLayoutRow ctxt idx =
incr ctxt.count_FieldLayout;
let addr = ctxt.row_addr tab_FieldLayout idx
seek ctxt.is addr;
let offset = read_i32 ctxt.is
let fidx = read_z_untagged_idx tab_Field ctxt
(offset,fidx)
//// Read Table StandAloneSig
let SeekReadStandAloneSigRow ctxt idx =
incr ctxt.count_StandAloneSig;
let addr = ctxt.row_addr tab_StandAloneSig idx
seek ctxt.is addr;
let sig_idx = read_blob_idx ctxt
(sig_idx)
/// Read Table EventMap
let SeekReadEventMapRow ctxt idx =
incr ctxt.count_EventMap;
let addr = ctxt.row_addr tab_EventMap idx
seek ctxt.is addr;
let tidx = read_z_untagged_idx tab_TypeDef ctxt
let events_idx = read_z_untagged_idx tab_Event ctxt
(tidx,events_idx)
/// Read Table Event
let SeekReadEventRow ctxt idx =
incr ctxt.count_Event;
let addr = ctxt.row_addr tab_Event idx
seek ctxt.is addr;
let flags = read_u16_as_i32 ctxt.is
let name_idx = read_string_idx ctxt
let typ_idx = read_tdor_idx ctxt
(flags,name_idx,typ_idx)
/// Read Table PropertyMap
let SeekReadPropertyMapRow ctxt idx = ctxt.SeekReadPropertyMapRow idx
let SeekReadPropertyMapRowUncached ctxtH idx =
let ctxt = getHole ctxtH
incr ctxt.count_PropertyMap;
let addr = ctxt.row_addr tab_PropertyMap idx
seek ctxt.is addr;
let tidx = read_z_untagged_idx tab_TypeDef ctxt
let props_idx = read_z_untagged_idx tab_Property ctxt
(tidx,props_idx)
/// Read Table Property
let SeekReadPropertyRow ctxt idx =
incr ctxt.count_Property;
let addr = ctxt.row_addr tab_Property idx
seek ctxt.is addr;
let flags = read_u16_as_i32 ctxt.is
let name_idx = read_string_idx ctxt
let typ_idx = read_blob_idx ctxt
(flags,name_idx,typ_idx)
/// Read Table MethodSemantics
let SeekReadMethodSemanticsRow ctxt idx = ctxt.SeekReadMethodSemanticsRow idx
let SeekReadMethodSemanticsRowUncached ctxtH idx =
let ctxt = getHole ctxtH
incr ctxt.count_MethodSemantics;
let addr = ctxt.row_addr tab_MethodSemantics idx
seek ctxt.is addr;
let flags = read_u16_as_i32 ctxt.is
let midx = read_z_untagged_idx tab_Method ctxt
let assoc_idx = read_hs_idx ctxt
(flags,midx,assoc_idx)
/// Read Table MethodImpl
let SeekReadMethodImplRow ctxt idx =
incr ctxt.count_MethodImpl;
let addr = ctxt.row_addr tab_MethodImpl idx
seek ctxt.is addr;
let tidx = read_z_untagged_idx tab_TypeDef ctxt
let mbody_idx = read_mdor_idx ctxt
let mdecl_idx = read_mdor_idx ctxt
(tidx,mbody_idx,mdecl_idx)
/// Read Table ILModuleRef
let SeekReadModuleRefRow ctxt idx =
incr ctxt.count_ModuleRef;
let addr = ctxt.row_addr tab_ModuleRef idx
seek ctxt.is addr;
let name_idx = read_string_idx ctxt
name_idx
/// Read Table ILTypeSpec
let SeekReadTypeSpecRow ctxt idx =
incr ctxt.count_TypeSpec;
let addr = ctxt.row_addr tab_TypeSpec idx
seek ctxt.is addr;
let blob_idx = read_blob_idx ctxt
blob_idx
/// Read Table ImplMap
let SeekReadImplMapRow ctxt idx =
incr ctxt.count_ImplMap;
let addr = ctxt.row_addr tab_ImplMap idx
seek ctxt.is addr;
let flags = read_u16_as_i32 ctxt.is
let forwrded_idx = read_mf_idx ctxt
let name_idx = read_string_idx ctxt
let scope_idx = read_z_untagged_idx tab_ModuleRef ctxt
(flags, forwrded_idx, name_idx, scope_idx)
/// Read Table FieldRVA
let SeekReadFieldRVARow ctxt idx =
incr ctxt.count_FieldRVA;
let addr = ctxt.row_addr tab_FieldRVA idx
seek ctxt.is addr;
let rva = read_i32 ctxt.is
let fidx = read_z_untagged_idx tab_Field ctxt
(rva,fidx)
/// Read Table Assembly
let SeekReadAssemblyRow ctxt idx =
incr ctxt.count_Assembly;
let addr = ctxt.row_addr tab_Assembly idx
seek ctxt.is addr;
let hash = read_i32 ctxt.is
let v1 = read_u16 ctxt.is
let v2 = read_u16 ctxt.is
let v3 = read_u16 ctxt.is
let v4 = read_u16 ctxt.is
let flags = read_i32 ctxt.is
let public_key_idx = read_blob_idx ctxt
let name_idx = read_string_idx ctxt
let locale_idx = read_string_idx ctxt
(hash,v1,v2,v3,v4,flags,public_key_idx, name_idx, locale_idx)
/// Read Table ILAssemblyRef
let SeekReadAssemblyRefRow ctxt idx =
incr ctxt.count_AssemblyRef;
let addr = ctxt.row_addr tab_AssemblyRef idx
seek ctxt.is addr;
let v1 = read_u16 ctxt.is
let v2 = read_u16 ctxt.is
let v3 = read_u16 ctxt.is
let v4 = read_u16 ctxt.is
let flags = read_i32 ctxt.is
let public_key_or_token_idx = read_blob_idx ctxt
let name_idx = read_string_idx ctxt
let locale_idx = read_string_idx ctxt
let hash_value_idx = read_blob_idx ctxt
(v1,v2,v3,v4,flags,public_key_or_token_idx, name_idx, locale_idx,hash_value_idx)
/// Read Table File
let SeekReadFileRow ctxt idx =
incr ctxt.count_File;
let addr = ctxt.row_addr tab_File idx
seek ctxt.is addr;
let flags = read_i32 ctxt.is
let name_idx = read_string_idx ctxt
let hash_value_idx = read_blob_idx ctxt
(flags, name_idx, hash_value_idx)
/// Read Table ILExportedType
let SeekReadExportedTypeRow ctxt idx =
incr ctxt.count_ExportedType;
let addr = ctxt.row_addr tab_ExportedType idx
seek ctxt.is addr;
let flags = read_i32 ctxt.is
let tok = read_i32 ctxt.is
let name_idx = read_string_idx ctxt
let namespace_idx = read_string_idx ctxt
let impl_idx = read_i_idx ctxt
(flags,tok,name_idx,namespace_idx,impl_idx)
/// Read Table ManifestResource
let SeekReadManifestResourceRow ctxt idx =
incr ctxt.count_ManifestResource;
let addr = ctxt.row_addr tab_ManifestResource idx
seek ctxt.is addr;
let offset = read_i32 ctxt.is
let flags = read_i32 ctxt.is
let name_idx = read_string_idx ctxt
let impl_idx = read_i_idx ctxt
(offset,flags,name_idx,impl_idx)
/// Read Table Nested
let SeekReadNestedRow ctxt idx = ctxt.SeekReadNestedRow idx
let SeekReadNestedRowUncached ctxtH idx =
let ctxt = getHole ctxtH
incr ctxt.count_Nested;
let addr = ctxt.row_addr tab_Nested idx
seek ctxt.is addr;
let nested_idx = read_z_untagged_idx tab_TypeDef ctxt
let encl_idx = read_z_untagged_idx tab_TypeDef ctxt
(nested_idx,encl_idx)
/// Read Table GenericParam
let SeekReadGenericParamRow ctxt idx =
incr ctxt.count_GenericParam;
let addr = ctxt.row_addr tab_GenericParam idx
seek ctxt.is addr;
let seq = read_u16 ctxt.is
let flags = read_u16 ctxt.is
let owner_idx = read_tomd_idx ctxt
let name_idx = read_string_idx ctxt
(idx,seq,flags,owner_idx,name_idx)
// Read Table GenericParamConstraint
let SeekReadGenericParamConstraintRow ctxt idx =
incr ctxt.count_GenericParamConstraint;
let addr = ctxt.row_addr tab_GenericParamConstraint idx
seek ctxt.is addr;
let pidx = read_z_untagged_idx tab_GenericParam ctxt
let constraint_idx = read_tdor_idx ctxt
(pidx,constraint_idx)
/// Read Table ILMethodSpec
let SeekReadMethodSpecRow ctxt idx =
incr ctxt.count_MethodSpec;
let addr = ctxt.row_addr tab_MethodSpec idx
seek ctxt.is addr;
let mdor_idx = read_mdor_idx ctxt
let inst_idx = read_blob_idx ctxt
(mdor_idx,inst_idx)
let ReadUserStringHeapUncached ctxtH idx =
let ctxt = getHole ctxtH
if logging then dprintn (ctxt.infile ^ ": reading user string heap "^string idx);
let res = SeekReadUserString ctxt.is (ctxt.user_strings_stream_phys_loc + idx)
(* if logging then dprintn (ctxt.infile ^ ": read string '"^res^"'"); *)
res
let ReadUserStringHeap ctxt idx = ctxt.ReadUserStringHeap idx
let ReadStringHeapUncached ctxtH idx =
let ctxt = getHole ctxtH
SeekReadUTF8String ctxt.is (ctxt.strings_stream_phys_loc + idx)
let ReadStringHeap ctxt idx = ctxt.ReadStringHeap idx
let ReadStringHeapOption ctxt idx = if idx = 0 then None else Some (ReadStringHeap ctxt idx)
let ReadBlobHeapUncached ctxtH idx =
let ctxt = getHole ctxtH
if logging then dprintn (ctxt.infile ^ ": reading blob heap "^string idx);
SeekReadBlob ctxt.is (ctxt.blobs_stream_phys_loc + idx)
let ReadBlobHeap ctxt idx = ctxt.ReadBlobHeap idx
let ReadBlobHeapOption ctxt idx = if idx = 0 then None else Some (ReadBlobHeap ctxt idx)
let ReadGuidHeap ctxt idx = SeakReadGuid ctxt.is (ctxt.guids_stream_phys_loc + idx)
(* read a single value out of a blob heap using the given function *)
let ReadBlobHeap_as_bool ctxt vidx = fst (sigptr_get_bool (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_i8 ctxt vidx = fst (sigptr_get_i8 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_i16 ctxt vidx = fst (sigptr_get_i16 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_i32 ctxt vidx = fst (sigptr_get_i32 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_i64 ctxt vidx = fst (sigptr_get_i64 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_u8 ctxt vidx = fst (sigptr_get_u8 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_u16 ctxt vidx = fst (sigptr_get_u16 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_u32 ctxt vidx = fst (sigptr_get_u32 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_u64 ctxt vidx = fst (sigptr_get_u64 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_ieee32 ctxt vidx = fst (sigptr_get_ieee32 (ReadBlobHeap ctxt vidx) 0)
let ReadBlobHeap_as_ieee64 ctxt vidx = fst (sigptr_get_ieee64 (ReadBlobHeap ctxt vidx) 0)
//-----------------------------------------------------------------------
// This is gross. Some binaries have raw data embedded
// their text sections, e.g. mscorlib, for field inits. And there is no
// information that definitively tells us the extent of
// the text section that may be interesting data.
// But we certainly don't want to duplicate the entire
// text section as data!
//
// So, we assume:
// 1. no part of the metadata is double-used for raw data
// 2. the data bits are all the bits of the text section
// that stretch from a Field or Resource RVA to one of
// (a) the next Field or resource RVA
// (b) a MethodRVA
// (c) the start of the metadata
// (d) the end of a section
// (e) the start of the native resources attached to the binary if any
// ----------------------------------------------------------------------*)
let read_native_resources ctxt =
let native_resources =
if logging then dprintn (ctxt.infile ^ ": native_resources_size = "^string ctxt.native_resources_size);
if logging then dprintn (ctxt.infile ^ ": native_resources_addr = "^string ctxt.native_resources_addr);
if ctxt.native_resources_size = 0x0 or ctxt.native_resources_addr = 0x0 then
[]
else
[ (lazy (if logging then dprintn (ctxt.infile ^ ": reading linked resource...");
let linkedResource = SeekReadBytes ctxt.is (ctxt.anyV2P (ctxt.infile ^ ": native resources",ctxt.native_resources_addr)) ctxt.native_resources_size
if logging then dprintn (ctxt.infile ^ ": size = "^string (Bytes.length linkedResource));
if logging then dprintn (ctxt.infile ^ ": unlinking resource...");
unlinkResource ctxt.native_resources_addr linkedResource)) ]
native_resources
let data_end_points ctxtH =
lazy
begin
let ctxt = getHole ctxtH
let dataStartPoints =
let res = ref []
for i = 1 to ctxt.nrows (tab_FieldRVA) do
let rva,fidx = SeekReadFieldRVARow ctxt i
res := ("field",rva) :: !res;
for i = 1 to ctxt.nrows (tab_ManifestResource) do
let (offset,_,_,TaggedIndex(tag,idx)) = SeekReadManifestResourceRow ctxt i
if idx = 0 then
let rva = ctxt.resources_addr + offset
res := ("manifest resource", rva) :: !res;
!res
if isNil dataStartPoints then []
else
let methodRVAs =
let res = ref []
for i = 1 to ctxt.nrows (tab_Method) do
let (rva, _, _, name_idx, _, _) = SeekReadMethodRow ctxt i
if rva <> 0 then
let nm = ReadStringHeap ctxt name_idx
res := (nm,rva) :: !res;
!res
([ ctxt.text_phys_loc + ctxt.text_phys_size;
ctxt.data_phys_loc + ctxt.data_phys_size; ]
@
(List.map ctxt.anyV2P
(dataStartPoints
@ [for (virt_addr,virt_size,phys_loc) in ctxt.section_headers do yield ("section start",virt_addr) done]
@ [("md",ctxt.metadata_addr)]
@ (if ctxt.native_resources_addr = 0x0 then [] else [("native resources",ctxt.native_resources_addr); ])
@ (if ctxt.resources_addr = 0x0 then [] else [("managed resources",ctxt.resources_addr); ])
@ (if ctxt.strongname_addr = 0x0 then [] else [("managed strongname",ctxt.strongname_addr); ])
@ (if ctxt.vtable_fixups_addr = 0x0 then [] else [("managed vtable_fixups",ctxt.vtable_fixups_addr); ])
@ methodRVAs)))
// Make distinct
|> Set.of_list
|> Set.to_list
|> List.sort
end
let rec rva_to_data ctxt nm rva =
if rva = 0x0 then failwith "rva is zero";
let start = ctxt.anyV2P (nm, rva)
let endPoints = (Lazy.force ctxt.data_end_points)
let rec look l =
match l with
| [] ->
failwithf "find_text_data_extent: none found for infile=%s, name=%s, rva=0x%08x, start=0x%08x" ctxt.infile nm rva start
| e::t ->
if start < e then
(SeekReadBytes ctxt.is start (e - start))
else look t
look endPoints
//-----------------------------------------------------------------------
// Read the AbsIL structure (lazily) by reading off the relevant rows.
// ----------------------------------------------------------------------
let is_sorted ctxt tab = ((ctxt.sorted &&& (int64 1 <<< tag_of_table tab)) <> int64 0x0)
let rec SeekReadModule ctxt (subsys,ilonly,only32,only64,platform,is_dll, align_virt,align_phys,image_base_real) idx =
let (generation, name_idx, mvid_idx, encid_idx, encbaseid_idx) = SeekReadModuleRow ctxt idx
let mname = ReadStringHeap ctxt name_idx
let native_resources = read_native_resources ctxt
{ modulManifest =
if ctxt.nrows (tab_Assembly) > 0 then Some (SeekReadAssemblyManifest ctxt 1)
else None;
modulCustomAttrs = SeekReadCustomAttrs ctxt (TaggedIndex(hca_Module,idx));
modulName = mname;
modulNativeResources=native_resources;
modulTypeDefs = mk_lazy_tdefs (lazy (SeekReadTopTypeDefs ctxt ()));
modulSubSystem = int32 subsys;
modulILonly = ilonly;
modulPlatform = platform;
modul32bit = only32;
modul64bit = only64;
modulDLL=is_dll;
modulVirtAlignment = align_virt;
modulPhysAlignment = align_phys;
modulImageBase = image_base_real;
modulResources = SeekReadManifestResources ctxt ();
(* modulFixups = [] (* REVIEW:VIP *) *) }
and SeekReadAssemblyManifest ctxt idx =
let (hash,v1,v2,v3,v4,flags,public_key_idx, name_idx, locale_idx) = SeekReadAssemblyRow ctxt idx
let name = ReadStringHeap ctxt name_idx
let pubkey = ReadBlobHeapOption ctxt public_key_idx
{ manifestName= name;
manifestAuxModuleHashAlgorithm=hash;
manifestSecurityDecls= SeekReadSecurityDecls ctxt (TaggedIndex(hds_Assembly,idx));
manifestPublicKey= pubkey;
manifestVersion= Some (v1,v2,v3,v4);
manifestLocale= ReadStringHeapOption ctxt locale_idx;
manifestCustomAttrs = SeekReadCustomAttrs ctxt (TaggedIndex(hca_Assembly,idx));
manifestLongevity=
begin let masked = flags &&& 0x000e
if masked = 0x0000 then LongevityUnspecified
elif masked = 0x0002 then LongevityLibrary
elif masked = 0x0004 then LongevityPlatformAppDomain
elif masked = 0x0006 then LongevityPlatformProcess
elif masked = 0x0008 then LongevityPlatformSystem
else LongevityUnspecified
end;
manifestExportedTypes= SeekReadTopExportedTypes ctxt ();
manifestEntrypointElsewhere=(if fst ctxt.eptoken = tab_File then Some (SeekReadFile ctxt (snd ctxt.eptoken)) else None);
manifestRetargetable = 0 <> (flags &&& 0xff);
manifestDisableJitOptimizations = 0 <> (flags &&& 0x4000);
manifestJitTracking = 0 <> (flags &&& 0x8000); }
and SeekReadAssemblyRef ctxt idx = ctxt.SeekReadAssemblyRef idx
and SeekReadAssemblyRefUncached ctxtH idx =
let ctxt = getHole ctxtH
let (v1,v2,v3,v4,flags,public_key_or_token_idx, name_idx, locale_idx,hash_value_idx) = SeekReadAssemblyRefRow ctxt idx
let nm = ReadStringHeap ctxt name_idx
let publicKey =
match ReadBlobHeapOption ctxt public_key_or_token_idx with
| None -> None
| Some blob -> Some (if (flags &&& 0x0001) <> 0x0 then PublicKey blob else PublicKeyToken blob)
ILAssemblyRef.Create
(name=nm,
hash=ReadBlobHeapOption ctxt hash_value_idx,
publicKey=publicKey,
retargetable=((flags &&& 0x0100) <> 0x0),
version=Some(v1,v2,v3,v4),
locale=ReadStringHeapOption ctxt locale_idx;)
and SeekReadModuleRef ctxt idx =
let (name_idx) = SeekReadModuleRefRow ctxt idx
ILModuleRef.Create(name = ReadStringHeap ctxt name_idx,
hasMetadata=true,
hash=None)
and SeekReadFile ctxt idx =
let (flags, name_idx, hash_value_idx) = SeekReadFileRow ctxt idx
ILModuleRef.Create(name = ReadStringHeap ctxt name_idx,
hasMetadata= ((flags &&& 0x0001) = 0x0),
hash= ReadBlobHeapOption ctxt hash_value_idx)
and SeekReadClassLayout ctxt idx =
match SeekReadOptionalIndexedRow (ctxt.nrows tab_ClassLayout,SeekReadClassLayoutRow ctxt,(fun (_,_,tidx) -> tidx),simpleindex_compare idx,is_sorted ctxt tab_ClassLayout,(fun (pack,size,_) -> pack,size)) with
| None -> { typeSize = None; typePack = None }
| Some (pack,size) -> { typeSize = Some size;
typePack = Some pack; }
and member_access_of_flags flags =
let f = (flags &&& 0x00000007)
if f = 0x00000001 then MemAccess_private
elif f = 0x00000006 then MemAccess_public
elif f = 0x00000004 then MemAccess_family
elif f = 0x00000002 then MemAccess_famandassem
elif f = 0x00000005 then MemAccess_famorassem
elif f = 0x00000003 then MemAccess_assembly
else MemAccess_compilercontrolled
and type_access_of_flags flags =
let f = (flags &&& 0x00000007)
if f = 0x00000001 then TypeAccess_public
elif f = 0x00000002 then TypeAccess_nested MemAccess_public
elif f = 0x00000003 then TypeAccess_nested MemAccess_private
elif f = 0x00000004 then TypeAccess_nested MemAccess_family
elif f = 0x00000006 then TypeAccess_nested MemAccess_famandassem
elif f = 0x00000007 then TypeAccess_nested MemAccess_famorassem
elif f = 0x00000005 then TypeAccess_nested MemAccess_assembly
else TypeAccess_private
and type_layout_of_flags ctxt flags tidx =
let f = (flags &&& 0x00000018)
if f = 0x00000008 then TypeLayout_sequential (SeekReadClassLayout ctxt tidx)
elif f = 0x00000010 then TypeLayout_explicit (SeekReadClassLayout ctxt tidx)
else TypeLayout_auto
and type_kind_of_flags nm mdefs fdefs super flags =
if (flags &&& 0x00000020) <> 0x0 then TypeDef_interface
else
let is_enum = (match super with None -> false | Some ty -> (tspec_of_typ ty).Name = "System.Enum")
let is_delegate = (match super with None -> false | Some ty -> (tspec_of_typ ty).Name = "System.Delegate")
let is_multicast_delegate = (match super with None -> false | Some ty -> (tspec_of_typ ty).Name = "System.MulticastDelegate")
let self_is_multicast_delegate = nm = "System.MulticastDelegate"
let is_valuetype = (match super with None -> false | Some ty -> (tspec_of_typ ty).Name = "System.ValueType" && nm <> "System.Enum")
if is_enum then TypeDef_enum
elif (is_delegate && not self_is_multicast_delegate) or is_multicast_delegate then TypeDef_delegate
elif is_valuetype then TypeDef_valuetype
else TypeDef_class
and type_encoding_of_flags flags =
let f = (flags &&& 0x00030000)
if f = 0x00020000 then TypeEncoding_autochar
elif f = 0x00010000 then TypeEncoding_unicode
else TypeEncoding_ansi
and seek_is_wanted_TypeDef flags = true
and seek_is_top_TypeDef flags =
(type_access_of_flags flags = TypeAccess_private) ||
type_access_of_flags flags = TypeAccess_public
and seek_is_top_TypeDef_idx ctxt idx =
let (flags,_,_, _, _,_) = SeekReadTypeDefRow ctxt idx
seek_is_top_TypeDef flags
and ReadBlobHeap_as_split_type_name ctxt (name_idx,namespace_idx) =
let name = ReadStringHeap ctxt name_idx
let nspace = ReadStringHeapOption ctxt namespace_idx
match nspace with
| Some nspace -> split_namespace nspace,name
| None -> [],name
and ReadBlobHeapAsTypeName ctxt (name_idx,namespace_idx) =
let name = ReadStringHeap ctxt name_idx
let nspace = ReadStringHeapOption ctxt namespace_idx
match nspace with
| None -> name
| Some ns -> ctxt.MemoizeString (ns^"."^name)
and SeekReadTypeDefRow_extents ctxt ((_,_, _, _, fields_idx, methods_idx) as info ) (idx:int) =
if idx >= ctxt.nrows (tab_TypeDef) then
ctxt.nrows (tab_Field) + 1,
ctxt.nrows (tab_Method) + 1
else
let (_, _, _, _, fields_idx, methods_idx) = SeekReadTypeDefRow ctxt (idx + 1)
fields_idx, methods_idx
and SeekReadTypeDefRow_with_extents ctxt (idx:int) =
let info= SeekReadTypeDefRow ctxt idx
info,SeekReadTypeDefRow_extents ctxt info idx
and SeekReadTypeDef ctxt toponly acc (idx:int) =
let (flags,name_idx,namespace_idx, _, _, _) = SeekReadTypeDefRow ctxt idx
if toponly && not (seek_is_top_TypeDef flags) then acc
elif not (seek_is_wanted_TypeDef flags) then acc
else
let ns,n = ReadBlobHeap_as_split_type_name ctxt (name_idx,namespace_idx)
let cas = SeekReadCustomAttrs ctxt (TaggedIndex(hca_TypeDef,idx))
let rest =
lazy
begin
(* Re-read so as not to save all these in the lazy closure - this suspension ctxt.is the largest *)
(* heavily allocated one in all of AbsIL*)
let ((flags,name_idx,namespace_idx, extends_idx, fields_idx, methods_idx) as info) = SeekReadTypeDefRow ctxt idx
let nm = ReadBlobHeapAsTypeName ctxt (name_idx,namespace_idx)
let cas = SeekReadCustomAttrs ctxt (TaggedIndex(hca_TypeDef,idx))
if logging then dprintn ("reading remainder of type "^nm);
let (end_fields_idx, end_methods_idx) = SeekReadTypeDefRow_extents ctxt info idx
let typars = SeekReadGenericParams ctxt 0 (tomd_TypeDef,idx)
let numtypars = List.length typars
if logging then dprintn ("reading supertype of type "^nm);
let super = SeekReadOptionalTypeDefOrRef ctxt numtypars AsObject extends_idx
let layout = type_layout_of_flags ctxt flags idx
let has_layout = (match layout with TypeLayout_explicit _ -> true | _ -> false)
if logging then dprintn ("setting up reading of methods and fields for type "^nm);
let mdefs = SeekReadMethods ctxt numtypars methods_idx end_methods_idx
let fdefs = SeekReadFields ctxt (numtypars,has_layout) fields_idx end_fields_idx
if logging then dprintn ("determining kind of type "^nm);
let kind = type_kind_of_flags nm mdefs fdefs super flags
if logging then dprintn ("setting up read of nested types for type "^nm);
let nested = SeekReadNestedTypeDefs ctxt idx nm
if logging then dprintn ("setting up read of interface impls for type "^nm);
let impls = SeekReadInterfaceImpls ctxt numtypars idx
if logging then dprintn ("setting up read of security decls for type "^nm);
let sdecls = SeekReadSecurityDecls ctxt (TaggedIndex(hds_TypeDef,idx))
if logging then dprintn ("setting up read of mimpls for type "^nm);
let mimpls = SeekReadMethodImpls ctxt numtypars idx
if logging then dprintn ("setting up read of properties for type "^nm);
let props = SeekReadProperties ctxt numtypars idx
if logging then dprintn ("setting up read of custom attributes for type "^nm);
let events = SeekReadEvents ctxt numtypars idx
if logging then dprintn ("preparing results for type "^nm);
let res =
{ tdKind= kind;
tdName=nm;
tdGenericParams=typars;
tdAccess= type_access_of_flags flags;
tdAbstract= (flags &&& 0x00000080) <> 0x0;
tdSealed= (flags &&& 0x00000100) <> 0x0;
tdSerializable= (flags &&& 0x00002000) <> 0x0;
tdComInterop= (flags &&& 0x00001000) <> 0x0;
tdLayout = layout;
tdSpecialName= (flags &&& 0x00000400) <> 0x0;
tdEncoding=type_encoding_of_flags flags;
tdNested= nested;
tdImplements = impls;
tdExtends = super;
tdMethodDefs = mdefs;
tdSecurityDecls = sdecls;
tdHasSecurity=(flags &&& 0x00040000) <> 0x0;
tdFieldDefs=fdefs;
tdMethodImpls=mimpls;
tdInitSemantics=
if kind = TypeDef_interface then TypeInit_beforeany
elif (flags &&& 0x00100000) <> 0x0 then TypeInit_beforefield
else TypeInit_beforeany;
tdEvents= events;
tdProperties=props;
tdCustomAttrs=cas; }
if logging then dprintn ("done reading remainder of type "^nm);
res
end
(ns,n,cas,rest) :: acc
and SeekReadTopTypeDefs ctxt () =
let res = ref []
for i = 1 to ctxt.nrows (tab_TypeDef) do
res := SeekReadTypeDef ctxt true !res i;
List.rev !res
and SeekReadNestedTypeDefs ctxt tidx nm =
mk_lazy_tdefs
(lazy
begin
if logging then dprintn ("reading nested ILTypeDefs for type "^nm);
let nested_idxs = SeekReadIndexedRows (ctxt.nrows tab_Nested,SeekReadNestedRow ctxt,snd,simpleindex_compare tidx,false,fst)
List.rev (List.fold (SeekReadTypeDef ctxt false) [] nested_idxs)
end)
and SeekReadInterfaceImpls ctxt numtypars tidx =
SeekReadIndexedRows (ctxt.nrows tab_InterfaceImpl,
SeekReadInterfaceImplRow ctxt,
fst,
simpleindex_compare tidx,
is_sorted ctxt tab_InterfaceImpl,
(snd >> SeekReadTypeDefOrRef ctxt numtypars AsObject (*ok*) []))
and SeekReadGenericParams ctxt numtypars (a,b) = ctxt.SeekReadGenericParams (GenericParamsIdx(numtypars,a,b))
and SeekReadGenericParamsUncached ctxtH (GenericParamsIdx(numtypars,a,b)) =
let ctxt = getHole ctxtH
let pars =
SeekReadIndexedRows
(ctxt.nrows tab_GenericParam,SeekReadGenericParamRow ctxt,
(fun (_,_,_,tomd,_) -> tomd),
tomd_compare (TaggedIndex(a,b)),
is_sorted ctxt tab_GenericParam,
(fun (gpidx,seq,flags,_,name_idx) ->
let flags = int32 flags
let variance_flags = flags &&& 0x0003
let variance =
if variance_flags = 0x0000 then NonVariant
elif variance_flags = 0x0001 then CoVariant
elif variance_flags = 0x0002 then ContraVariant
else NonVariant
let constraints = SeekReadGenericParamConstraintsUncached ctxt numtypars gpidx
seq, {gpName=ReadStringHeap ctxt name_idx;
gpConstraints=constraints;
gpVariance=variance;
gpReferenceTypeConstraint= (flags &&& 0x0004) <> 0;
gpNotNullableValueTypeConstraint= (flags &&& 0x0008) <> 0;
gpDefaultConstructorConstraint=(flags &&& 0x0010) <> 0; }))
pars |> List.sortBy fst |> List.map snd
and SeekReadGenericParamConstraintsUncached ctxt numtypars gpidx =
SeekReadIndexedRows
(ctxt.nrows tab_GenericParamConstraint,
SeekReadGenericParamConstraintRow ctxt,
fst,
simpleindex_compare gpidx,
is_sorted ctxt tab_GenericParamConstraint,
(snd >> SeekReadTypeDefOrRef ctxt numtypars AsObject (*ok*) []))
and SeekReadTypeDefAsType ctxt boxity ginst idx =
ctxt.SeekReadTypeDefAsType (TypeDefAsTypIdx (boxity,ginst,idx))
and SeekReadTypeDefAsTypeUncached ctxtH (TypeDefAsTypIdx (boxity,ginst,idx)) =
let ctxt = getHole ctxtH
mk_typ boxity (ILTypeSpec.Create(SeekReadTypeDefAsTypeRef ctxt idx, ginst))
and SeekReadTypeDefAsTypeRef ctxt idx =
if logging then dprintn ("reading ILTypeDef "^string idx^" as type ref");
let enc =
if seek_is_top_TypeDef_idx ctxt idx then []
else
let encl_idx = SeekReadIndexedRow (ctxt.nrows tab_Nested,SeekReadNestedRow ctxt,fst,simpleindex_compare idx,is_sorted ctxt tab_Nested,snd)
let tref = SeekReadTypeDefAsTypeRef ctxt encl_idx
tref.Enclosing@[tref.Name]
let (_, name_idx, namespace_idx, _, _, _) = SeekReadTypeDefRow ctxt idx
let nm = ReadBlobHeapAsTypeName ctxt (name_idx,namespace_idx)
ILTypeRef.Create(scope=ScopeRef_local, enclosing=enc, name = nm )
and SeekReadTypeRef ctxt idx = ctxt.SeekReadTypeRef idx
and SeekReadTypeRefUncached ctxtH idx =
let ctxt = getHole ctxtH
if logging then dprintn ("reading ILTypeRef "^string idx);
let scope_idx,name_idx,namespace_idx = SeekReadTypeRefRow ctxt idx
let scope,enc = SeekReadTypeRefScope ctxt scope_idx
let nm = ReadBlobHeapAsTypeName ctxt (name_idx,namespace_idx)
ILTypeRef.Create(scope=scope, enclosing=enc, name = nm)
and SeekReadTypeRef_as_typ ctxt boxity ginst idx = ctxt.SeekReadTypeRef_as_typ (TypeRefAsTypIdx (boxity,ginst,idx))
and SeekReadTypeRef_as_typUncached ctxtH (TypeRefAsTypIdx (boxity,ginst,idx)) =
let ctxt = getHole ctxtH
mk_typ boxity (ILTypeSpec.Create(SeekReadTypeRef ctxt idx, ginst))
and SeekReadTypeDefOrRef ctxt numtypars boxity ginst (TaggedIndex(tag,idx) ) =
match tag with
| tag when tag = tdor_TypeDef -> SeekReadTypeDefAsType ctxt boxity ginst idx
| tag when tag = tdor_TypeRef -> SeekReadTypeRef_as_typ ctxt boxity ginst idx
| tag when tag = tdor_TypeSpec ->
if ginst <> [] then dprintn ("type spec used as type constructor for a generic instantiation: ignoring instantiation");
ReadBlobHeap_as_typ ctxt numtypars (SeekReadTypeSpecRow ctxt idx)
| _ -> failwith "SeekReadTypeDefOrRef ctxt"
and SeekReadTypeDefOrRefAsTypeRef ctxt (TaggedIndex(tag,idx) ) =
match tag with
| tag when tag = tdor_TypeDef -> SeekReadTypeDefAsTypeRef ctxt idx
| tag when tag = tdor_TypeRef -> SeekReadTypeRef ctxt idx
| tag when tag = tdor_TypeSpec ->
dprintn ("type spec used where a type ref or def ctxt.is required");
ctxt.ilg.tref_Object
| _ -> failwith "SeekReadTypeDefOrRefAsTypeRef_read_tdor"
and SeekReadMethodRefParent ctxt numtypars (TaggedIndex(tag,idx)) =
match tag with
| tag when tag = mrp_TypeRef -> SeekReadTypeRef_as_typ ctxt AsObject (* not ok - no way to tell if a member ref parent ctxt.is a value type or not *) [] idx
| tag when tag = mrp_ModuleRef -> typ_for_toplevel (ScopeRef_module (SeekReadModuleRef ctxt idx))
| tag when tag = mrp_MethodDef ->
let mspec = mk_mspec_in_typ(SeekReadMethodDef_as_mdata ctxt idx)
mspec.EnclosingType
| tag when tag = mrp_TypeSpec -> ReadBlobHeap_as_typ ctxt numtypars (SeekReadTypeSpecRow ctxt idx)
| _ -> failwith "SeekReadMethodRefParent ctxt"
and SeekReadMethodDefOrRef ctxt numtypars (TaggedIndex(tag,idx)) =
match tag with
| tag when tag = mdor_MethodDef ->
let (encl_typ, cc, nm, argtys, retty,minst) = SeekReadMethodDef_as_mdata ctxt idx
(encl_typ, cc, nm, argtys, None,retty,minst)
| tag when tag = mdor_MemberRef -> SeekReadMemberRef_as_mdata ctxt numtypars idx
| _ -> failwith "SeekReadMethodDefOrRef ctxt"
and SeekReadMethodDefOrRefNoVarargs ctxt numtypars x =
let (encl_typ, cc, nm, argtys, varargs,retty,minst)= SeekReadMethodDefOrRef ctxt numtypars x
if varargs <> None then dprintf "ignoring sentinel and varargs in ILMethodDef token signature";
(encl_typ, cc, nm, argtys, retty,minst)
and SeekReadCustomAttrType ctxt (TaggedIndex(tag,idx) ) =
match tag with
| tag when tag = cat_MethodDef -> (mk_mspec_in_typ (SeekReadMethodDef_as_mdata ctxt idx))
| tag when tag = cat_MemberRef -> (mk_mspec_in_typ (SeekReadMemberRef_as_mdata_no_varargs ctxt 0 idx))
| _ -> failwith "SeekReadCustomAttrType ctxt"
and SeekReadImplAsScopeRef ctxt (TaggedIndex(tag,idx) ) =
if idx = 0 then ScopeRef_local
else
match tag with
| tag when tag = i_File -> ScopeRef_module (SeekReadFile ctxt idx)
| tag when tag = i_AssemblyRef -> ScopeRef_assembly (SeekReadAssemblyRef ctxt idx)
| tag when tag = i_ExportedType -> failwith "SeekReadImplAsScopeRef ctxt"
| _ -> failwith "SeekReadImplAsScopeRef ctxt"
and SeekReadTypeRefScope ctxt (TaggedIndex(tag,idx) ) =
match tag with
| tag when tag = rs_Module -> ScopeRef_local,[]
| tag when tag = rs_ModuleRef -> ScopeRef_module (SeekReadModuleRef ctxt idx),[]
| tag when tag = rs_AssemblyRef -> ScopeRef_assembly (SeekReadAssemblyRef ctxt idx),[]
| tag when tag = rs_TypeRef ->
let tref = SeekReadTypeRef ctxt idx
tref.Scope,(tref.Enclosing@[tref.Name])
| _ -> failwith "SeekReadTypeRefScope ctxt"
and SeekReadOptionalTypeDefOrRef ctxt numtypars boxity idx =
if idx = TaggedIndex(tdor_TypeDef, 0) then None
else Some (SeekReadTypeDefOrRef ctxt numtypars boxity [] idx)
and SeekReadField ctxt (numtypars, has_layout) (idx:int) =
let (flags,name_idx,type_idx) = SeekReadFieldRow ctxt idx
let nm = ReadStringHeap ctxt name_idx
if logging then dprintn ("reading field "^nm);
let isStatic = (flags &&& 0x0010) <> 0
let fd =
{ fdName = nm;
fdType= ReadBlobHeap_as_field_sig ctxt numtypars type_idx;
fdAccess = member_access_of_flags flags;
fdStatic = isStatic;
fdInitOnly = (flags &&& 0x0020) <> 0;
fdLiteral = (flags &&& 0x0040) <> 0;
fdNotSerialized = (flags &&& 0x0080) <> 0;
fdSpecialName = (flags &&& 0x0200) <> 0 or (flags &&& 0x0400) <> 0; (* REVIEW: RTSpecialName *)
fdInit = if (flags &&& 0x8000) = 0 then None else Some (SeekReadConstant ctxt (TaggedIndex(hc_FieldDef,idx)));
fdMarshal =
if (flags &&& 0x1000) = 0 then None else
Some (SeekReadIndexedRow (ctxt.nrows tab_FieldMarshal,
SeekReadFieldMarshalRow ctxt,
fst,
hfm_compare (TaggedIndex(hfm_FieldDef,idx)),
is_sorted ctxt tab_FieldMarshal,
(snd >> ReadBlobHeapAsNativeType ctxt)));
fdData =
begin
if (flags &&& 0x0100) = 0 then None
else
let rva = SeekReadIndexedRow (ctxt.nrows tab_FieldRVA,
SeekReadFieldRVARow ctxt,
snd,
simpleindex_compare idx,
is_sorted ctxt tab_FieldRVA,
fst)
Some (rva_to_data ctxt "field" rva)
end;
fdOffset =
if has_layout && not isStatic then Some (SeekReadIndexedRow (ctxt.nrows tab_FieldLayout,
SeekReadFieldLayoutRow ctxt,
snd,
simpleindex_compare idx,
is_sorted ctxt tab_FieldLayout,
fst)) else None;
fdCustomAttrs=SeekReadCustomAttrs ctxt (TaggedIndex(hca_FieldDef,idx)); }
if logging then dprintn ("done reading field "^nm);
fd
and SeekReadFields ctxt (numtypars, has_layout) fidx1 fidx2 =
mk_lazy_fdefs
(lazy
[ for i = fidx1 to fidx2 - 1 do
yield SeekReadField ctxt (numtypars, has_layout) i ])
and SeekReadMethods ctxt numtypars midx1 midx2 =
mk_lazy_mdefs
(lazy
[ for i = midx1 to midx2 - 1 do
if seek_is_wanted_MethodDef i then
yield SeekReadMethod ctxt numtypars i ])
and sigptr_get_tdor_idx bytes sigptr =
let n, sigptr = sigptr_get_z_i32 bytes sigptr
if (n &&& 0x01) = 0x0 then (* Type Def *)
TaggedIndex(tdor_TypeDef, (n lsr 2)), sigptr
else (* Type Ref *)
TaggedIndex(tdor_TypeRef, (n lsr 2)), sigptr
and sigptr_get_typ ctxt numtypars bytes sigptr =
let b0,sigptr = sigptr_get_byte bytes sigptr
if logging then dprintn ("reading type from sig at "^string sigptr^", et = "^string b0);
if b0 = et_OBJECT then ctxt.ilg.typ_Object , sigptr
elif b0 = et_STRING then ctxt.ilg.typ_String, sigptr
elif b0 = et_I1 then ctxt.ilg.typ_int8, sigptr
elif b0 = et_I2 then ctxt.ilg.typ_int16, sigptr
elif b0 = et_I4 then ctxt.ilg.typ_int32, sigptr
elif b0 = et_I8 then ctxt.ilg.typ_int64, sigptr
elif b0 = et_I then ctxt.ilg.typ_IntPtr, sigptr
elif b0 = et_U1 then ctxt.ilg.typ_uint8, sigptr
elif b0 = et_U2 then ctxt.ilg.typ_uint16, sigptr
elif b0 = et_U4 then ctxt.ilg.typ_uint32, sigptr
elif b0 = et_U8 then ctxt.ilg.typ_uint64, sigptr
elif b0 = et_U then ctxt.ilg.typ_UIntPtr, sigptr
elif b0 = et_R4 then ctxt.ilg.typ_float32, sigptr
elif b0 = et_R8 then ctxt.ilg.typ_float64, sigptr
elif b0 = et_CHAR then ctxt.ilg.typ_char, sigptr
elif b0 = et_BOOLEAN then ctxt.ilg.typ_bool, sigptr
elif b0 = et_WITH then
let b0,sigptr = sigptr_get_byte bytes sigptr
let tdor_idx, sigptr = sigptr_get_tdor_idx bytes sigptr
let n, sigptr = sigptr_get_z_i32 bytes sigptr
let argtys,sigptr = sigptr_foldi (sigptr_get_typ ctxt numtypars) ( n) bytes sigptr
SeekReadTypeDefOrRef ctxt numtypars (if b0 = et_CLASS then AsObject else AsValue) argtys tdor_idx,
sigptr
elif b0 = et_CLASS then
let tdor_idx, sigptr = sigptr_get_tdor_idx bytes sigptr
SeekReadTypeDefOrRef ctxt numtypars AsObject [] tdor_idx, sigptr
elif b0 = et_VALUETYPE then
let tdor_idx, sigptr = sigptr_get_tdor_idx bytes sigptr
SeekReadTypeDefOrRef ctxt numtypars AsValue [] tdor_idx, sigptr
elif b0 = et_VAR then
let n, sigptr = sigptr_get_z_i32 bytes sigptr
Type_tyvar (uint16 n),sigptr
elif b0 = et_MVAR then
let n, sigptr = sigptr_get_z_i32 bytes sigptr
Type_tyvar (uint16 (n + numtypars)), sigptr
elif b0 = et_BYREF then
let typ, sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
Type_byref typ, sigptr
elif b0 = et_PTR then
let typ, sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
Type_ptr typ, sigptr
elif b0 = et_SZARRAY then
let typ, sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
mk_sdarray_ty typ, sigptr
elif b0 = et_ARRAY then
let typ, sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
let rank, sigptr = sigptr_get_z_i32 bytes sigptr
let num_sized, sigptr = sigptr_get_z_i32 bytes sigptr
let sizes, sigptr = sigptr_foldi sigptr_get_z_i32 ( num_sized) bytes sigptr
let num_lobounded, sigptr = sigptr_get_z_i32 bytes sigptr
let lobounds, sigptr = sigptr_foldi sigptr_get_z_i32 ( num_lobounded) bytes sigptr
let shape =
let dim i =
(if i < num_lobounded then Some (List.nth lobounds i) else None),
(if i < num_sized then Some (List.nth sizes i) else None)
ILArrayShape (Array.to_list (Array.init ( rank) dim))
mk_array_ty (typ, shape), sigptr
elif b0 = et_VOID then Type_void, sigptr
elif b0 = et_TYPEDBYREF then ctxt.ilg.typ_TypedReference, sigptr
elif b0 = et_CMOD_REQD or b0 = et_CMOD_OPT then
let tdor_idx, sigptr = sigptr_get_tdor_idx bytes sigptr
let typ, sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
Type_modified((b0 = et_CMOD_REQD), SeekReadTypeDefOrRefAsTypeRef ctxt tdor_idx, typ), sigptr
elif b0 = et_FNPTR then
begin
if logging then dprintn ("reading fptr sig ");
let cc_byte,sigptr = sigptr_get_byte bytes sigptr
let generic,cc = byte_as_callconv cc_byte
if generic then failwith "fptr sig may not be generic";
let numparams,sigptr = sigptr_get_z_i32 bytes sigptr
let retty,sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
let argtys,sigptr = sigptr_foldi (sigptr_get_typ ctxt numtypars) ( numparams) bytes sigptr
Type_fptr
{ callsigCallconv=cc;
callsigArgs=argtys;
callsigReturn=retty }
,sigptr
end
elif b0 = et_SENTINEL then failwith "varargs NYI"
else Type_void , sigptr
and sigptr_get_vararg_typs ctxt n numtypars bytes sigptr =
sigptr_foldi (sigptr_get_typ ctxt numtypars) n bytes sigptr
and sigptr_get_arg_typs ctxt n numtypars bytes sigptr acc =
if n <= 0 then (List.rev acc,None),sigptr
else
let b0,sigptr2 = sigptr_get_byte bytes sigptr
if b0 = et_SENTINEL then
let varargs,sigptr = sigptr_get_vararg_typs ctxt n numtypars bytes sigptr2
(List.rev acc,Some(varargs)),sigptr
else
let x,sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
sigptr_get_arg_typs ctxt (n-1) numtypars bytes sigptr (x::acc)
and sigptr_get_local ctxt numtypars bytes sigptr =
let pinned,sigptr =
let b0, sigptr' = sigptr_get_byte bytes sigptr
if b0 = et_PINNED then
true, sigptr'
else
false, sigptr
let typ, sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
{ localPinned = pinned;
localType = typ }, sigptr
and ReadBlobHeap_as_method_sig ctxt numtypars blob_idx =
ctxt.ReadBlobHeap_as_method_sig (BlobAsMethodSigIdx (numtypars,blob_idx))
and ReadBlobHeap_as_method_sigUncached ctxtH (BlobAsMethodSigIdx (numtypars,blob_idx)) =
let ctxt = getHole ctxtH
if logging then dprintn ("reading method sig at "^string blob_idx);
let bytes = ReadBlobHeap ctxt blob_idx
let sigptr = 0
let cc_byte,sigptr = sigptr_get_byte bytes sigptr
let generic,cc = byte_as_callconv cc_byte
let genarity,sigptr = if generic then sigptr_get_z_i32 bytes sigptr else 0x0,sigptr
let numparams,sigptr = sigptr_get_z_i32 bytes sigptr
let retty,sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
let (argtys,varargs),sigptr = sigptr_get_arg_typs ctxt ( numparams) numtypars bytes sigptr []
generic,genarity,cc,retty,argtys,varargs
and ReadBlobHeap_as_typ ctxt numtypars blob_idx =
let bytes = ReadBlobHeap ctxt blob_idx
let ty,sigptr = sigptr_get_typ ctxt numtypars bytes 0
ty
and ReadBlobHeap_as_field_sig ctxt numtypars blob_idx =
ctxt.ReadBlobHeap_as_field_sig (BlobAsFieldSigIdx (numtypars,blob_idx))
and ReadBlobHeap_as_field_sigUncached ctxtH (BlobAsFieldSigIdx (numtypars,blob_idx)) =
let ctxt = getHole ctxtH
if logging then dprintn ("reading field sig at "^string blob_idx);
let bytes = ReadBlobHeap ctxt blob_idx
let sigptr = 0
let cc_byte,sigptr = sigptr_get_byte bytes sigptr
if cc_byte <> e_IMAGE_CEE_CS_CALLCONV_FIELD then dprintn "warning: field sig was not CC_FIELD";
let retty,sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
retty
and ReadBlobHeap_as_property_sig ctxt numtypars blob_idx =
ctxt.ReadBlobHeap_as_property_sig (BlobAsPropSigIdx (numtypars,blob_idx))
and ReadBlobHeap_as_property_sigUncached ctxtH (BlobAsPropSigIdx (numtypars,blob_idx)) =
let ctxt = getHole ctxtH
let bytes = ReadBlobHeap ctxt blob_idx
let sigptr = 0
let cc_byte,sigptr = sigptr_get_byte bytes sigptr
let hasthis = byte_as_hasthis cc_byte
let cc_masked = (cc_byte &&& 0x0f)
if cc_masked <> e_IMAGE_CEE_CS_CALLCONV_PROPERTY then dprintn ("warning: property sig was "^string cc_masked^" instead of CC_PROPERTY");
let numparams,sigptr = sigptr_get_z_i32 bytes sigptr
let retty,sigptr = sigptr_get_typ ctxt numtypars bytes sigptr
let argtys,sigptr = sigptr_foldi (sigptr_get_typ ctxt numtypars) ( numparams) bytes sigptr
hasthis,retty,argtys
and ReadBlobHeap_as_locals_sig ctxt numtypars blob_idx =
ctxt.ReadBlobHeap_as_locals_sig (BlobAsLocalSigIdx (numtypars,blob_idx))
and ReadBlobHeap_as_locals_sigUncached ctxtH (BlobAsLocalSigIdx (numtypars,blob_idx)) =
let ctxt = getHole ctxtH
let bytes = ReadBlobHeap ctxt blob_idx
let sigptr = 0
let cc_byte,sigptr = sigptr_get_byte bytes sigptr
if cc_byte <> e_IMAGE_CEE_CS_CALLCONV_LOCAL_SIG then dprintn "warning: local sig was not CC_LOCAL";
let numlocals,sigptr = sigptr_get_z_i32 bytes sigptr
let localtys,sigptr = sigptr_foldi (sigptr_get_local ctxt numtypars) ( numlocals) bytes sigptr
localtys
and byte_as_hasthis b =
let hasthis_masked = (b &&& 0x60)
if hasthis_masked = e_IMAGE_CEE_CS_CALLCONV_INSTANCE then CC_instance
elif hasthis_masked = e_IMAGE_CEE_CS_CALLCONV_INSTANCE_EXPLICIT then CC_instance_explicit
else CC_static
and byte_as_callconv b =
let cc =
let cc_masked = (b &&& 0x0f)
if cc_masked = e_IMAGE_CEE_CS_CALLCONV_FASTCALL then CC_fastcall
elif cc_masked = e_IMAGE_CEE_CS_CALLCONV_STDCALL then CC_stdcall
elif cc_masked = e_IMAGE_CEE_CS_CALLCONV_THISCALL then CC_thiscall
elif cc_masked = e_IMAGE_CEE_CS_CALLCONV_CDECL then CC_cdecl
elif cc_masked = e_IMAGE_CEE_CS_CALLCONV_VARARG then CC_vararg
else CC_default
let generic = (b &&& e_IMAGE_CEE_CS_CALLCONV_GENERIC) <> 0x0
generic, Callconv (byte_as_hasthis b,cc)
and SeekReadMemberRef_as_mdata ctxt numtypars idx =
ctxt.SeekReadMemberRef_as_mdata (MemberRefAsMspecIdx (numtypars,idx))
and SeekReadMemberRef_as_mdataUncached ctxtH (MemberRefAsMspecIdx (numtypars,idx)) =
let ctxt = getHole ctxtH
let (mrp_idx,name_idx,type_idx) = SeekReadMemberRefRow ctxt idx
let nm = ReadStringHeap ctxt name_idx
let encl_typ = SeekReadMethodRefParent ctxt numtypars mrp_idx
let generic,genarity,cc,retty,argtys,varargs = ReadBlobHeap_as_method_sig ctxt (List.length (inst_of_typ encl_typ)) type_idx
let minst = List.init genarity (fun n -> mk_tyvar_ty (uint16 (numtypars+n)))
(encl_typ, cc, nm, argtys, varargs,retty,minst)
and SeekReadMemberRef_as_mdata_no_varargs ctxt numtypars idx =
let (encl_typ, cc, nm, argtys,varargs, retty,minst) = SeekReadMemberRef_as_mdata ctxt numtypars idx
if isSome varargs then dprintf "ignoring sentinel and varargs in ILMethodDef token signature";
(encl_typ, cc, nm, argtys, retty,minst)
and SeekReadMethodSpec_as_mdata ctxt numtypars idx =
ctxt.SeekReadMethodSpec_as_mdata (MethodSpecAsMspecIdx (numtypars,idx))
and SeekReadMethodSpec_as_mdataUncached ctxtH (MethodSpecAsMspecIdx (numtypars,idx)) =
let ctxt = getHole ctxtH
let (mdor_idx,inst_idx) = SeekReadMethodSpecRow ctxt idx
let (encl_typ, cc, nm, argtys, varargs,retty,_) = SeekReadMethodDefOrRef ctxt numtypars mdor_idx
let minst =
let bytes = ReadBlobHeap ctxt inst_idx
let sigptr = 0
let cc_byte,sigptr = sigptr_get_byte bytes sigptr
if cc_byte <> e_IMAGE_CEE_CS_CALLCONV_GENERICINST then dprintn ("warning: method inst ILCallingConv was "^string cc_byte^" instead of CC_GENERICINST");
let numgpars,sigptr = sigptr_get_z_i32 bytes sigptr
let argtys,sigptr = sigptr_foldi (sigptr_get_typ ctxt numtypars) ( numgpars) bytes sigptr
argtys
(encl_typ, cc, nm, argtys, varargs,retty, minst)
and SeekReadMemberRef_as_fspec ctxt numtypars idx =
ctxt.SeekReadMemberRef_as_fspec (MemberRefAsFspecIdx (numtypars,idx))
and SeekReadMemberRef_as_fspecUncached ctxtH (MemberRefAsFspecIdx (numtypars,idx)) =
let ctxt = getHole ctxtH
let (mrp_idx,name_idx,type_idx) = SeekReadMemberRefRow ctxt idx
let nm = ReadStringHeap ctxt name_idx
let encl_typ = SeekReadMethodRefParent ctxt numtypars mrp_idx
let retty = ReadBlobHeap_as_field_sig ctxt numtypars type_idx
mk_fspec_in_typ(encl_typ, nm, retty)
// One extremely annoying aspect of the MD format is that given a
// ILMethodDef token it is non-trivial to find which ILTypeDef it belongs
// to. So we do a binary chop through the ILTypeDef table
// looking for which ILTypeDef has the ILMethodDef within its range.
// Although the ILTypeDef table is not "sorted", it is effectively sorted by
// method-range and field-range start/finish indexes
and SeekReadMethodDef_as_mdata ctxt idx =
ctxt.SeekReadMethodDef_as_mdata idx
and SeekReadMethodDef_as_mdataUncached ctxtH idx =
let ctxt = getHole ctxtH
let (code_rva, implflags, flags, name_idx, type_idx, param_idx) = SeekReadMethodRow ctxt idx
let nm = ReadStringHeap ctxt name_idx
// Look for the method def parent.
let tidx =
SeekReadIndexedRow (ctxt.nrows tab_TypeDef,
(fun i -> i, SeekReadTypeDefRow_with_extents ctxt i),
(fun r -> r),
(fun (_,((_, _, _, _, _, methods_idx),
(_, end_methods_idx))) ->
if end_methods_idx <= idx then 1
elif methods_idx <= idx && idx < end_methods_idx then 0
else -1),
true,fst)
// Read the method def signature.
let generic,genarity,cc,retty,argtys,varargs = ReadBlobHeap_as_method_sig ctxt 0 type_idx
if varargs <> None then dprintf "ignoring sentinel and varargs in ILMethodDef token signature";
// Create a formal instantiation if needed
let finst = generalize_gparams (SeekReadGenericParams ctxt 0 (tomd_TypeDef,tidx))
let minst = generalize_gparams (SeekReadGenericParams ctxt (List.length finst) (tomd_MethodDef,idx))
// Read the method def parent.
let encl_typ = SeekReadTypeDefAsType ctxt AsObject (* not ok: see note *) finst tidx
// Return the constituent parts: put it together at the place where this is called.
(encl_typ, cc, nm, argtys, retty,minst)
(* Similarly for fields. *)
and SeekReadFieldDef_as_fspec ctxt idx =
ctxt.SeekReadFieldDef_as_fspec idx
and SeekReadFieldDef_as_fspecUncached ctxtH idx =
let ctxt = getHole ctxtH
let (flags, name_idx, type_idx) = SeekReadFieldRow ctxt idx
let nm = ReadStringHeap ctxt name_idx
(* Look for the field def parent. *)
let tidx =
SeekReadIndexedRow (ctxt.nrows tab_TypeDef,
(fun i -> i, SeekReadTypeDefRow_with_extents ctxt i),
(fun r -> r),
(fun (_,((_, _, _, _, fields_idx, _),(end_fields_idx, _))) ->
if end_fields_idx <= idx then 1
elif fields_idx <= idx && idx < end_fields_idx then 0
else -1),
true,fst)
// Read the field signature.
let retty = ReadBlobHeap_as_field_sig ctxt 0 type_idx
// Create a formal instantiation if needed
let finst = generalize_gparams (SeekReadGenericParams ctxt 0 (tomd_TypeDef,tidx))
// Read the field def parent.
let encl_typ = SeekReadTypeDefAsType ctxt AsObject (* not ok: see note *) finst tidx
// Put it together.
mk_fspec_in_typ(encl_typ, nm, retty)
and seek_is_wanted_MethodDef idx = true
and SeekReadMethod ctxt numtypars (idx:int) =
if logging then dprintn ("reading method "^string idx);
let (code_rva, implflags, flags, name_idx, type_idx, param_idx) = SeekReadMethodRow ctxt idx
let nm = ReadStringHeap ctxt name_idx
if logging then dprintn (" method name = " ^ nm);
let isStatic = (flags &&& 0x0010) <> 0x0
let final = (flags &&& 0x0020) <> 0x0
let virt = (flags &&& 0x0040) <> 0x0
let strict = (flags &&& 0x0200) <> 0x0
let hidebysig = (flags &&& 0x0080) <> 0x0
let newslot = (flags &&& 0x0100) <> 0x0
let abstr = (flags &&& 0x0400) <> 0x0
let specialname = (flags &&& 0x0800) <> 0x0
let pinvoke = (flags &&& 0x2000) <> 0x0
let export = (flags &&& 0x0008) <> 0x0
let rtspecialname = (flags &&& 0x1000) <> 0x0
let reqsecobj = (flags &&& 0x8000) <> 0x0
let hassec = (flags &&& 0x4000) <> 0x0
let codetype = implflags &&& 0x0003
let unmanaged = (implflags &&& 0x0004) <> 0x0
let forwardref = (implflags &&& 0x0010) <> 0x0
let preservesig = (implflags &&& 0x0080) <> 0x0
let internalcall = (implflags &&& 0x1000) <> 0x0
let synchronized = (implflags &&& 0x0020) <> 0x0
let noinline = (implflags &&& 0x0008) <> 0x0
let mustrun = (implflags &&& 0x0040) <> 0x0
let cctor = (nm = ".cctor")
let ctor = (nm = ".ctor")
let generic,genarity,cc,retty,argtys,varargs = ReadBlobHeap_as_method_sig ctxt numtypars type_idx
if varargs <> None then dprintf "ignoring sentinel and varargs in ILMethodDef signature";
if logging then dprintn ("finding end param idx");
let end_param_idx =
if idx >= ctxt.nrows (tab_Method) then
ctxt.nrows (tab_Param) + 1
else
let (_,_,_,_,_, param_idx) = SeekReadMethodRow ctxt (idx + 1)
param_idx
if logging then dprintn ("found param range: "^string param_idx^" - "^string end_param_idx);
let ret,ilParams = SeekReadParams ctxt (retty,argtys) param_idx end_param_idx
if logging then dprintn ("read param range: "^string param_idx^" - "^string end_param_idx);
let res =
{ mdName=nm;
mdKind =
(if cctor then MethodKind_cctor
elif ctor then MethodKind_ctor
elif isStatic then MethodKind_static
elif virt then
MethodKind_virtual
{ virtFinal=final;
virtNewslot=newslot;
virtStrict=strict;
virtAbstract=abstr; }
else MethodKind_nonvirtual);
mdAccess = member_access_of_flags flags;
mdSecurityDecls=SeekReadSecurityDecls ctxt (TaggedIndex(hds_MethodDef,idx));
mdHasSecurity=hassec;
mdEntrypoint= (fst ctxt.eptoken = tab_Method && snd ctxt.eptoken = idx);
mdReqSecObj=reqsecobj;
mdHideBySig=hidebysig;
mdSpecialName=specialname;
mdUnmanagedExport=export;
mdSynchronized=synchronized;
mdMustRun=mustrun;
mdPreserveSig=preservesig;
mdManaged = not unmanaged;
mdInternalCall = internalcall;
mdForwardRef = forwardref;
mdCodeKind = (if (codetype = 0x00) then MethodCodeKind_il elif (codetype = 0x01) then MethodCodeKind_native elif (codetype = 0x03) then MethodCodeKind_runtime else (dprintn "unsupported code type"; MethodCodeKind_native));
mdExport=None; (* REVIEW:VIP *)
mdVtableEntry=None; (* REVIEW:VIP *)
mdGenericParams=SeekReadGenericParams ctxt numtypars (tomd_MethodDef,idx);
mdCustomAttrs=SeekReadCustomAttrs ctxt (TaggedIndex(hca_MethodDef,idx));
mdParams= ilParams;
mdCallconv=cc;
mdReturn=ret;
mdBody=
if (codetype = 0x01) && pinvoke then
mk_lazy_mbody (notlazy MethodBody_native)
elif pinvoke then
SeekReadImplMap ctxt nm idx
elif internalcall or abstr or unmanaged or (codetype <> 0x00) then
if code_rva <> 0x0 then dprintn "non-IL or abstract method with non-zero RVA";
mk_lazy_mbody (notlazy MethodBody_abstract)
else
SeekReadMethodRVA ctxt (idx,nm,internalcall,noinline,numtypars) code_rva;
}
if logging then dprintn (" done method = " ^ nm);
res
and SeekReadParams ctxt (retty,argtys) pidx1 pidx2 =
let ret_res = ref { returnMarshal=None;
returnType=retty;
returnCustomAttrs=empty_custom_attrs }
let params_res =
argtys
|> Array.of_list
|> Array.map (fun ty -> { paramName=None;
paramDefault=None;
paramMarshal=None;
paramIn=false;
paramOut=false;
paramOptional=false;
paramType=ty;
paramCustomAttrs=empty_custom_attrs })
for i = pidx1 to pidx2 - 1 do
SeekReadParam_extras ctxt (ret_res,params_res) i
!ret_res, Array.to_list params_res
and SeekReadParam_extras ctxt (ret_res,params_res) (idx:int) =
let (flags,seq,name_idx) = SeekReadParamRow ctxt idx
if logging then dprintn ("reading param "^string idx^", seq = "^string seq);
let inout_masked = (flags &&& 0x00FF)
let has_marshal = (flags &&& 0x2000) <> 0x0
let has_default = (flags &&& 0x1000) <> 0x0
let fm_reader idx = SeekReadIndexedRow (ctxt.nrows tab_FieldMarshal,SeekReadFieldMarshalRow ctxt,fst,hfm_compare idx,is_sorted ctxt tab_FieldMarshal,(snd >> ReadBlobHeapAsNativeType ctxt))
let cas = SeekReadCustomAttrs ctxt (TaggedIndex(hca_ParamDef,idx))
if seq = 0 then
ret_res := { !ret_res with
returnMarshal=(if has_marshal then Some (fm_reader (TaggedIndex(hfm_ParamDef,idx))) else None);
returnCustomAttrs = cas }
elif seq > Array.length params_res then dprintn "bad seq num. for param"
else
params_res.[seq - 1] <-
{ params_res.[seq - 1] with
paramMarshal=(if has_marshal then Some (fm_reader (TaggedIndex(hfm_ParamDef,idx))) else None);
paramDefault = (if has_default then Some (SeekReadConstant ctxt (TaggedIndex(hc_ParamDef,idx))) else None);
paramName = ReadStringHeapOption ctxt name_idx;
paramIn = ((inout_masked &&& 0x0001) <> 0x0);
paramOut = ((inout_masked &&& 0x0002) <> 0x0);
paramOptional = ((inout_masked &&& 0x0010) <> 0x0);
paramCustomAttrs =cas }
and SeekReadMethodImpls ctxt numtypars tidx =
mk_lazy_mimpls
(lazy
begin
let mimpls = SeekReadIndexedRows (ctxt.nrows tab_MethodImpl,SeekReadMethodImplRow ctxt,(fun (a,_,_) -> a),simpleindex_compare tidx,is_sorted ctxt tab_MethodImpl,(fun (_,b,c) -> b,c))
mimpls |> List.map (fun (b,c) ->
{ mimplOverrideBy=(mk_mspec_in_typ (SeekReadMethodDefOrRefNoVarargs ctxt numtypars b));
mimplOverrides=
(let mspec = (mk_mspec_in_typ (SeekReadMethodDefOrRefNoVarargs ctxt numtypars c))
OverridesSpec(mspec.MethodRef, mspec.EnclosingType)) })
end)
and SeekReadMultipleMethodSemantics ctxt (flags,id) =
SeekReadIndexedRows
(ctxt.nrows tab_MethodSemantics ,
SeekReadMethodSemanticsRow ctxt,
(fun (flags,_,c) -> c),
hs_compare id,
is_sorted ctxt tab_MethodSemantics,
(fun (a,b,c) -> a, (mk_mspec_in_typ (SeekReadMethodDef_as_mdata ctxt b)).MethodRef))
|> List.filter (fun (flags2,_) -> flags = flags2)
|> List.map snd
and SeekReadoptional_MethodSemantics ctxt id =
match SeekReadMultipleMethodSemantics ctxt id with
[] -> None
| [h] -> Some h
| h::t -> dprintn "multiple method semantics found"; Some h
and SeekReadMethodSemantics ctxt id =
match SeekReadoptional_MethodSemantics ctxt id with
| None -> failwith "SeekReadMethodSemantics ctxt: no method found"
| Some x -> x
and SeekReadEvent ctxt numtypars idx =
let (flags,name_idx,typ_idx) = SeekReadEventRow ctxt idx
{ eventName = ReadStringHeap ctxt name_idx;
eventType = SeekReadOptionalTypeDefOrRef ctxt numtypars AsObject typ_idx;
eventSpecialName = (flags &&& 0x0200) <> 0x0;
eventRTSpecialName = (flags &&& 0x0400) <> 0x0;
eventAddOn= SeekReadMethodSemantics ctxt (0x0008,TaggedIndex(hs_Event, idx));
eventRemoveOn=SeekReadMethodSemantics ctxt (0x0010,TaggedIndex(hs_Event,idx));
eventFire=SeekReadoptional_MethodSemantics ctxt (0x0020,TaggedIndex(hs_Event,idx));
eventOther = SeekReadMultipleMethodSemantics ctxt (0x0004, TaggedIndex(hs_Event, idx));
eventCustomAttrs=SeekReadCustomAttrs ctxt (TaggedIndex(hca_Event,idx)) }
(* REVIEW: can substantially reduce numbers of EventMap and PropertyMap reads by first checking if the whole table is sorted according to ILTypeDef tokens and then doing a binary chop *)
and SeekReadEvents ctxt numtypars tidx =
mk_lazy_events
(lazy
begin
match SeekReadOptionalIndexedRow (ctxt.nrows tab_EventMap,(fun i -> i, SeekReadEventMapRow ctxt i),(fun (_,row) -> fst row),compare tidx,false,(fun (i,row) -> (i,snd row))) with
| None -> []
| Some (row_num,begin_event_idx) ->
let end_event_idx =
if row_num >= ctxt.nrows (tab_EventMap) then
ctxt.nrows (tab_Event) + 1
else
let (_, end_event_idx) = SeekReadEventMapRow ctxt (row_num + 1)
end_event_idx
[ for i in begin_event_idx .. end_event_idx - 1 do
yield SeekReadEvent ctxt numtypars i ]
end)
and SeekReadProperty ctxt numtypars idx =
let (flags,name_idx,typ_idx) = SeekReadPropertyRow ctxt idx
let cc,retty,argtys = ReadBlobHeap_as_property_sig ctxt numtypars typ_idx
let setter= SeekReadoptional_MethodSemantics ctxt (0x0001,TaggedIndex(hs_Property,idx))
let getter = SeekReadoptional_MethodSemantics ctxt (0x0002,TaggedIndex(hs_Property,idx))
(* NOTE: the "hasthis" value on the property is not reliable: better to look on the getter/setter *)
(* NOTE: e.g. tlbimp on Office msword.olb seems to set this incorrectly *)
let hasthis_of_callconv (Callconv (a,b)) = a
let cc2 =
match getter with
| Some mref -> hasthis_of_callconv mref.CallingConv
| None ->
match setter with
| Some mref -> hasthis_of_callconv mref.CallingConv
| None -> cc
{ propName=ReadStringHeap ctxt name_idx;
propCallconv = cc2;
propRTSpecialName=(flags &&& 0x0400) <> 0x0;
propSpecialName= (flags &&& 0x0200) <> 0x0;
propSet=setter;
propGet=getter;
propType=retty;
propInit= if (flags &&& 0x1000) = 0 then None else Some (SeekReadConstant ctxt (TaggedIndex(hc_Property,idx)));
propArgs=argtys;
propCustomAttrs=SeekReadCustomAttrs ctxt (TaggedIndex(hca_Property,idx)) }
and SeekReadProperties ctxt numtypars tidx =
mk_lazy_properties
(lazy
begin
match SeekReadOptionalIndexedRow (ctxt.nrows tab_PropertyMap,(fun i -> i, SeekReadPropertyMapRow ctxt i),(fun (_,row) -> fst row),compare tidx,false,(fun (i,row) -> (i,snd row))) with
| None -> []
| Some (row_num,begin_prop_idx) ->
let end_prop_idx =
if row_num >= ctxt.nrows (tab_PropertyMap) then
ctxt.nrows (tab_Property) + 1
else
let (_, end_prop_idx) = SeekReadPropertyMapRow ctxt (row_num + 1)
end_prop_idx
[ for i in begin_prop_idx .. end_prop_idx - 1 do
yield SeekReadProperty ctxt numtypars i ]
end)
and SeekReadCustomAttrs ctxt idx =
mk_computed_custom_attrs
(fun () ->
SeekReadIndexedRows (ctxt.nrows tab_CustomAttribute,
SeekReadCustomAttributeRow ctxt,(fun (a,_,_) -> a),
hca_compare idx,
is_sorted ctxt tab_CustomAttribute,
(fun (_,b,c) -> SeekReadCustomAttr ctxt (b,c))))
and SeekReadCustomAttr ctxt (TaggedIndex(cat,idx),b) =
ctxt.SeekReadCustomAttr (CustomAttrIdx (cat,idx,b))
and SeekReadCustomAttrUncached ctxtH (CustomAttrIdx (cat,idx,val_idx)) =
let ctxt = getHole ctxtH
{ customMethod=SeekReadCustomAttrType ctxt (TaggedIndex(cat,idx));
customData=
match ReadBlobHeapOption ctxt val_idx with
| Some bytes -> bytes
| None -> Bytes.of_intarray [| |] }
and SeekReadSecurityDecls ctxt idx =
mk_lazy_security_decls
(lazy
begin
SeekReadIndexedRows (ctxt.nrows tab_Permission,
SeekReadPermissionRow ctxt,
(fun (_,par,_) -> par),
hds_compare idx,
is_sorted ctxt tab_Permission,
(fun (act,_,ty) -> SeekReadSecurityDecl ctxt (act,ty)))
end)
and SeekReadSecurityDecl ctxt (a,b) =
ctxt.SeekReadSecurityDecl (SecurityDeclIdx (a,b))
and SeekReadSecurityDeclUncached ctxtH (SecurityDeclIdx (act,ty)) =
let ctxt = getHole ctxtH
if logging then dprintn "reading SecurityDecl";
PermissionSet ((if List.mem_assoc (int act) (Lazy.force secaction_rmap) then List.assoc (int act) (Lazy.force secaction_rmap) else failwith "unknown security action"),
ReadBlobHeap ctxt ty)
and SeekReadConstant ctxt idx =
let kind,vidx = SeekReadIndexedRow (ctxt.nrows tab_Constant,
SeekReadConstantRow ctxt,
(fun (_,key,_) -> key),
hc_compare idx,is_sorted ctxt tab_Constant,(fun (kind,_,v) -> kind,v))
match kind with
| x when x = et_STRING -> FieldInit_string (Bytes.unicode_bytes_as_string (ReadBlobHeap ctxt vidx)) | x when x = et_BOOLEAN -> FieldInit_bool (ReadBlobHeap_as_bool ctxt vidx)
| x when x = et_CHAR -> FieldInit_char (ReadBlobHeap_as_u16 ctxt vidx)
| x when x = et_I1 -> FieldInit_int8 (ReadBlobHeap_as_i8 ctxt vidx)
| x when x = et_I2 -> FieldInit_int16 (ReadBlobHeap_as_i16 ctxt vidx)
| x when x = et_I4 -> FieldInit_int32 (ReadBlobHeap_as_i32 ctxt vidx)
| x when x = et_I8 -> FieldInit_int64 (ReadBlobHeap_as_i64 ctxt vidx)
| x when x = et_U1 -> FieldInit_uint8 (ReadBlobHeap_as_u8 ctxt vidx)
| x when x = et_U2 -> FieldInit_uint16 (ReadBlobHeap_as_u16 ctxt vidx)
| x when x = et_U4 -> FieldInit_uint32 (ReadBlobHeap_as_u32 ctxt vidx)
| x when x = et_U8 -> FieldInit_uint64 (ReadBlobHeap_as_u64 ctxt vidx)
| x when x = et_R4 -> FieldInit_single (ReadBlobHeap_as_ieee32 ctxt vidx)
| x when x = et_R8 -> FieldInit_double (ReadBlobHeap_as_ieee64 ctxt vidx)
| x when x = et_CLASS or x = et_OBJECT -> FieldInit_ref
| _ -> FieldInit_ref
and SeekReadImplMap ctxt nm midx =
mk_lazy_mbody
(lazy
begin
if logging then dprintn ("reading pinvoke map for method "^string midx);
let (flags,name_idx, scope_idx) = SeekReadIndexedRow (ctxt.nrows tab_ImplMap,
SeekReadImplMapRow ctxt,
(fun (_,m,_,_) -> m),
mf_compare (TaggedIndex(mf_MethodDef,midx)),
is_sorted ctxt tab_ImplMap,
(fun (a,_,c,d) -> a,c,d))
let cc =
let masked = flags &&& 0x0700
if masked = 0x0000 then PInvokeCallConvNone
elif masked = 0x0200 then PInvokeCallConvCdecl
elif masked = 0x0300 then PInvokeCallConvStdcall
elif masked = 0x0400 then PInvokeCallConvThiscall
elif masked = 0x0500 then PInvokeCallConvFastcall
elif masked = 0x0100 then PInvokeCallConvWinapi
else (dprintn "strange pinvokeCallconv"; PInvokeCallConvNone)
let enc =
let masked = flags &&& 0x0006
if masked = 0x0000 then PInvokeEncodingNone
elif masked = 0x0002 then PInvokeEncodingAnsi
elif masked = 0x0004 then PInvokeEncodingUnicode
elif masked = 0x0006 then PInvokeEncodingAuto
else (dprintn "strange PInvokeCharEncoding"; PInvokeEncodingNone)
let bestfit =
let masked = flags &&& 0x0030
if masked = 0x0000 then PInvokeBestFitUseAssem
elif masked = 0x0010 then PInvokeBestFitEnabled
elif masked = 0x0020 then PInvokeBestFitDisabled
else (dprintn "strange PInvokeCharBestFit"; PInvokeBestFitUseAssem)
let unmap =
let masked = flags &&& 0x3000
if masked = 0x0000 then PInvokeThrowOnUnmappableCharUseAssem
elif masked = 0x1000 then PInvokeThrowOnUnmappableCharEnabled
elif masked = 0x2000 then PInvokeThrowOnUnmappableCharDisabled
else (dprintn "strange PInvokeThrowOnUnmappableChar"; PInvokeThrowOnUnmappableCharUseAssem)
MethodBody_pinvoke { pinvokeCallconv = cc;
PInvokeCharEncoding = enc;
PInvokeCharBestFit=bestfit;
PInvokeThrowOnUnmappableChar=unmap;
pinvokeNoMangle = (flags &&& 0x0001) <> 0x0;
pinvokeLastErr = (flags &&& 0x0040) <> 0x0;
pinvokeName =
(match ReadStringHeapOption ctxt name_idx with
| None -> nm
| Some nm2 -> nm2);
pinvokeWhere = SeekReadModuleRef ctxt scope_idx }
end)
and SeekReadTopCode ctxt nm numtypars (sz:int) start seqpoints =
let labels_of_raw_offsets = new Dictionary<_,_>(sz/2)
let ilOffsetsOfLabels = new Dictionary<_,_>(sz/2)
let try_raw2lab raw_offset =
if labels_of_raw_offsets.ContainsKey raw_offset then
Some(labels_of_raw_offsets.[raw_offset])
else
None
let raw2lab raw_offset =
match try_raw2lab raw_offset with
| Some l -> l
| None ->
let lab = generate_code_label()
labels_of_raw_offsets.[raw_offset] <- lab;
lab
let mark_as_instruction_start raw_offset il_offset =
let lab = raw2lab raw_offset
ilOffsetsOfLabels.[lab] <- il_offset
let ibuf = new ResizeArray<_>(sz/2)
let curr = ref 0
let prefixes = { al=Aligned; tl= Normalcall; vol= Nonvolatile;ro=NormalAddress;constrained=None }
let lastb = ref 0x0
let lastb2 = ref 0x0
let b = ref 0x0
let get () =
lastb := SeekReadByteAsInt32 ctxt.is (start + (!curr));
incr curr;
b :=
if !lastb = 0xfe && !curr < sz then
lastb2 := SeekReadByteAsInt32 ctxt.is (start + (!curr));
incr curr;
!lastb2
else
!lastb
let seqpoints_remaining = ref seqpoints
while !curr < sz do
if logging then dprintn (ctxt.infile ^ ", "^nm^": registering "^string !curr^" as start of an instruction");
mark_as_instruction_start !curr ibuf.Count;
(* Insert any sequence points into the instruction sequence *)
if logging then dprintn ("** #remaining sequence points @ "^string !curr ^ " = "^string (List.length !seqpoints_remaining));
while
(match !seqpoints_remaining with
| (i,tag) :: rest when i <= !curr -> true
| _ -> false)
do
if logging then dprintn ("** Emitting one sequence point ** ");
let (_,tag) = List.hd !seqpoints_remaining
seqpoints_remaining := List.tl !seqpoints_remaining;
ibuf.Add (I_seqpoint tag)
if logging then dprintn (ctxt.infile ^ ", "^nm^ ": instruction begins at "^string !curr);
(* Read the prefixes. Leave lastb and lastb2 holding the instruction byte(s) *)
begin
prefixes.al <- Aligned;
prefixes.tl <- Normalcall;
prefixes.vol <- Nonvolatile;
prefixes.ro<-NormalAddress;
prefixes.constrained<-None;
get ();
while !curr < sz &&
!lastb = 0xfe &&
(!b = (i_constrained &&& 0xff) or
!b = (i_readonly &&& 0xff) or
!b = (i_unaligned &&& 0xff) or
!b = (i_volatile &&& 0xff) or
!b = (i_tail &&& 0xff)) do
begin
if !b = (i_unaligned &&& 0xff) then
let unal = SeekReadByteAsInt32 ctxt.is (start + (!curr))
incr curr;
prefixes.al <-
if unal = 0x1 then Unaligned_1
elif unal = 0x2 then Unaligned_2
elif unal = 0x4 then Unaligned_4
else (dprintn "bad alignment for unaligned"; Aligned)
elif !b = (i_volatile &&& 0xff) then prefixes.vol <- Volatile
elif !b = (i_readonly &&& 0xff) then prefixes.ro <- ReadonlyAddress
elif !b = (i_constrained &&& 0xff) then
let uncoded = SeekReaduncoded_token ctxt.is (start + (!curr))
curr := !curr + 4;
let typ = SeekReadTypeDefOrRef ctxt numtypars AsObject [] (uncoded_token_to_tdor uncoded)
prefixes.constrained <- Some typ
else prefixes.tl <- Tailcall;
end;
get ();
done;
end;
if logging then dprintn (ctxt.infile ^ ": data for instruction begins at "^string !curr);
(* Read and decode the instruction *)
if (!curr <= sz) then
let idecoder =
if !lastb = 0xfe then get_two_byte_instr ( !lastb2)
else get_one_byte_instr ( !lastb)
let instr =
match idecoder with
| I_u16_u8_instr f ->
let x = SeekReadByteAsUInt16 ctxt.is (start + (!curr))
curr := !curr + 1;
f prefixes x
| I_u16_u16_instr f ->
let x = SeekReadUInt16 ctxt.is (start + (!curr))
curr := !curr + 2;
f prefixes x
| I_none_instr f ->
f prefixes
| I_i64_instr f ->
let x = SeekReadInt64 ctxt.is (start + (!curr))
curr := !curr + 8;
f prefixes x
| I_i32_i8_instr f ->
let x = SeekReadSByteAsInt32 ctxt.is (start + (!curr))
curr := !curr + 1;
f prefixes x
| I_i32_i32_instr f ->
let x = SeekReadInt32 ctxt.is (start + (!curr))
curr := !curr + 4;
f prefixes x
| I_r4_instr f ->
let x = SeekReadSingle ctxt.is (start + (!curr))
curr := !curr + 4;
f prefixes x
| I_r8_instr f ->
let x = SeekReadDouble ctxt.is (start + (!curr))
curr := !curr + 8;
f prefixes x
| I_field_instr f ->
let (tab,tok) = SeekReaduncoded_token ctxt.is (start + (!curr))
curr := !curr + 4;
let fspec =
if tab = tab_Field then
SeekReadFieldDef_as_fspec ctxt tok
elif tab = tab_MemberRef then
SeekReadMemberRef_as_fspec ctxt numtypars tok
else failwith "bad table in FieldDefOrRef"
f prefixes fspec
| I_method_instr f ->
if logging then dprintn (ctxt.infile ^ ": method instruction, curr = "^string !curr);
let (tab,idx) = SeekReaduncoded_token ctxt.is (start + (!curr))
curr := !curr + 4;
let (encl_typ, cc, nm, argtys,varargs, retty, minst) =
if tab = tab_Method then
SeekReadMethodDefOrRef ctxt numtypars (TaggedIndex(mdor_MethodDef, idx))
elif tab = tab_MemberRef then
SeekReadMethodDefOrRef ctxt numtypars (TaggedIndex(mdor_MemberRef, idx))
elif tab = tab_MethodSpec then
SeekReadMethodSpec_as_mdata ctxt numtypars idx
else failwith "bad table in MethodDefOrRefOrSpec"
if is_array_ty encl_typ then
let (shape,ty) = dest_array_ty encl_typ
match nm with
| "Get" -> I_ldelem_any(shape,ty)
| "Set" -> I_stelem_any(shape,ty)
| "Address" -> I_ldelema(prefixes.ro, shape,ty)
| ".ctor" -> I_newarr(shape,ty)
| _ -> failwith "bad method on array type"
else
let mspec = (mk_mspec_in_typ (encl_typ, cc, nm, argtys, retty, minst))
f prefixes (mspec,varargs)
| I_type_instr f ->
let uncoded = SeekReaduncoded_token ctxt.is (start + (!curr))
curr := !curr + 4;
let typ = SeekReadTypeDefOrRef ctxt numtypars AsObject [] (uncoded_token_to_tdor uncoded)
f prefixes typ
| I_string_instr f ->
let (tab,idx) = SeekReaduncoded_token ctxt.is (start + (!curr))
curr := !curr + 4;
if tab <> tab_UserStrings then dprintn "warning: bad table in user string for ldstr";
f prefixes (ReadUserStringHeap ctxt (idx))
| I_conditional_i32_instr f ->
let offs_dest = (SeekReadInt32 ctxt.is (start + (!curr)))
curr := !curr + 4;
let dest = !curr + offs_dest
let next = !curr
f prefixes (raw2lab dest, raw2lab next)
| I_conditional_i8_instr f ->
let offs_dest = int (SeekReadSByte ctxt.is (start + (!curr)))
curr := !curr + 1;
let dest = !curr + offs_dest
let next = !curr
f prefixes (raw2lab dest, raw2lab next)
| I_unconditional_i32_instr f ->
let offs_dest = (SeekReadInt32 ctxt.is (start + (!curr)))
curr := !curr + 4;
let dest = !curr + offs_dest
f prefixes (raw2lab dest)
| I_unconditional_i8_instr f ->
let offs_dest = int (SeekReadSByte ctxt.is (start + (!curr)))
curr := !curr + 1;
let dest = !curr + offs_dest
f prefixes (raw2lab dest)
| I_invalid_instr -> dprintn ("invalid instruction: "^string !lastb^ (if !lastb = 0xfe then ","^string !lastb2 else "")); I_ret
| I_tok_instr f ->
let (tab,idx) = SeekReaduncoded_token ctxt.is (start + (!curr))
curr := !curr + 4;
(* REVIEW: this incorrectly labels all MemberRef tokens as Token_method's: we should go look at the MemberRef sig to determine if it ctxt.is a field or method *)
let token_info =
if tab = tab_Method or tab = tab_MemberRef (* REVIEW:generics or tab = tab_MethodSpec *) then
Token_method ((mk_mspec_in_typ (SeekReadMethodDefOrRefNoVarargs ctxt numtypars (uncoded_token_to_mdor (tab,idx)))))
elif tab = tab_Field then
Token_field (SeekReadFieldDef_as_fspec ctxt idx)
elif tab = tab_TypeDef or tab = tab_TypeRef or tab = tab_TypeSpec then
Token_type (SeekReadTypeDefOrRef ctxt numtypars AsObject [] (uncoded_token_to_tdor (tab,idx)))
else failwith "bad token for ldtoken"
f prefixes token_info
| I_sig_instr f ->
let (tab,idx) = SeekReaduncoded_token ctxt.is (start + (!curr))
curr := !curr + 4;
if tab <> tab_StandAloneSig then dprintn "strange table for callsig token";
let generic,genarity,cc,retty,argtys,varargs = ReadBlobHeap_as_method_sig ctxt numtypars (SeekReadStandAloneSigRow ctxt idx)
if generic then failwith "bad image: a generic method signature ctxt.is begin used at a calli instruction";
f prefixes (mk_callsig (cc,argtys,retty), varargs)
| I_switch_instr f ->
let n = (SeekReadInt32 ctxt.is (start + (!curr)))
curr := !curr + 4;
let offsets =
List.init n (fun _ ->
let i = (SeekReadInt32 ctxt.is (start + (!curr)))
curr := !curr + 4;
i)
let dests = List.map (fun offs -> raw2lab (!curr + offs)) offsets
let next = raw2lab !curr
f prefixes (dests,next)
ibuf.Add instr
done;
(* Finished reading instructions - mark the end of the instruction stream in case the PDB information refers to it. *)
mark_as_instruction_start !curr ibuf.Count;
(* Build the function that maps from raw labels (offsets into the bytecode stream) to indexes in the AbsIL instruction stream *)
let lab2pc lab =
try
ilOffsetsOfLabels.[lab]
with Not_found -> failwith ("branch destination "^string_of_code_label lab^" not found in code")
// Some offsets used in debug info refer to the end of an instruction, rather than the
// start of the subsequent instruction. But all labels refer to instruction starts,
// apart from a final label which refers to the end of the method. This function finds
// the start of the next instruction referred to by the raw offset.
let raw2nextLab raw_offset =
let isInstrStart x =
match try_raw2lab x with
| None -> false
| Some lab -> ilOffsetsOfLabels.ContainsKey lab
if isInstrStart raw_offset then raw2lab raw_offset
elif isInstrStart (raw_offset+1) then raw2lab (raw_offset+1)
else failwith ("the bytecode raw offset "^string raw_offset^" did not refer either to the start or end of an instruction")
let instrs = ibuf |> ResizeArray.to_array
instrs,raw2lab, lab2pc, raw2nextLab
and SeekReadMethodRVA ctxt (idx,nm,internalcall,noinline,numtypars) rva =
mk_lazy_mbody
(lazy
begin
// Read any debug information for this method into temporary data structures
// -- a list of locals, marked with the raw offsets (actually closures which accept the resolution function that maps raw offsets to labels)
// -- an overall range for the method
// -- the sequence points for the method
let local_pdb_infos, mrange_pdb_info, seqpoints =
match ctxt.pdb with
| None ->
[], None, []
| Some (pdbr, get_doc) ->
try
let pdbm = pdbReaderGetMethod pdbr (uncoded_token tab_Method idx)
let rootScope = pdbMethodGetRootScope pdbm
let sps = pdbMethodGetSequencePoints pdbm
(*dprintf "#sps for 0x%lx = %d\n" (uncoded_token tab_Method idx) (Array.length sps); *)
(* let roota,rootb = pdbScopeGetOffsets rootScope in *)
let seqpoints =
let arr =
sps |> Array.map (fun sp ->
(* It is VERY annoying to have to call GetURL for the document for each sequence point. This appears to be a short coming of the PDB reader API. They should return an index into the array of documents for the reader *)
let sourcedoc = get_doc (pdbDocumentGetURL sp.pdbSeqPointDocument)
let source =
ILSourceMarker.Create(document = sourcedoc,
line = sp.pdbSeqPointLine,
column = sp.pdbSeqPointColumn,
endLine = sp.pdbSeqPointEndLine,
endColumn = sp.pdbSeqPointEndColumn)
(sp.pdbSeqPointOffset,source))
Array.sortInPlaceBy fst arr;
Array.to_list arr
let rec scopes scp =
let a,b = pdbScopeGetOffsets scp
let lvs = pdbScopeGetLocals scp
let ilvs =
lvs
|> Array.to_list
|> List.filter (fun l ->
let k,idx = pdbVariableGetAddressAttributes l
k = 1 (* ADDR_IL_OFFSET *))
let ilinfos =
ilvs |> List.map (fun ilv ->
let k,idx = pdbVariableGetAddressAttributes ilv
let n = pdbVariableGetName ilv
if logging then dprintn ("local variable debug info: name="^n^", kind = "^string k^", localNum = "^string idx);
{ localNum= idx;
localName=n})
let this_one =
(fun raw2nextLab ->
{ locRange= (raw2nextLab a,raw2nextLab b);
locInfos = ilinfos })
if logging then dprintn ("this scope covers IL range: "^string a^"-"^string b);
let others = List.foldBack (scopes >> (@)) (Array.to_list (pdbScopeGetChildren scp)) []
this_one :: others
let local_pdb_infos = [] (* <REVIEW> scopes fail for mscorlib </REVIEW> scopes rootScope *)
if logging then dprintn ("done local_pdb_infos");
// REVIEW: look through sps to get ranges? Use GetRanges?? Change AbsIL??
(local_pdb_infos,None,seqpoints)
with e ->
if logging then dprintn ("* Warning: PDB info for method "^nm^" could not be read and will be ignored: "^e.Message);
[],None,[]
let baseRVA = ctxt.anyV2P("method rva",rva)
if logging then dprintn (ctxt.infile ^ ": reading body of method "^nm^" at rva "^string rva^", phys "^string baseRVA);
let b = SeekReadByteAsInt32 ctxt.is baseRVA
if (b &&& e_CorILMethod_FormatMask) = e_CorILMethod_TinyFormat then
let code_base = baseRVA + 1
let code_size = (b lsr 2)
if logging then dprintn (ctxt.infile ^ ": tiny format for "^nm^", code size = " ^ string code_size);
let instrs,_,lab2pc,raw2nextLab = SeekReadTopCode ctxt nm numtypars code_size code_base seqpoints
(* Convert the linear code format to the nested code format *)
if logging then dprintn ("doing local_pdb_infos2 (tiny format)");
let local_pdb_infos2 = List.map (fun f -> f raw2nextLab) local_pdb_infos
if logging then dprintn ("done local_pdb_infos2 (tiny format), checking code...");
let code = check_code (build_code nm lab2pc instrs [] local_pdb_infos2)
if logging then dprintn ("done checking code (tiny format).");
MethodBody_il
{ ilZeroInit=false;
ilMaxStack= 8;
ilNoInlining=noinline;
ilLocals=[];
ilSource=mrange_pdb_info;
ilCode=code }
elif (b &&& e_CorILMethod_FormatMask) = e_CorILMethod_FatFormat then
let has_more_sects = (b &&& e_CorILMethod_MoreSects) <> 0x0
let initlocals = (b &&& e_CorILMethod_InitLocals) <> 0x0
let maxstack = SeekReadUInt16AsInt32 ctxt.is (baseRVA + 2)
let code_size = SeekReadInt32 ctxt.is (baseRVA + 4)
let locals_tab,localtoken = SeekReaduncoded_token ctxt.is (baseRVA + 8)
let code_base = baseRVA + 12
let locals =
if localtoken = 0x0 then []
else
if locals_tab <> tab_StandAloneSig then dprintn "strange table for locals token";
ReadBlobHeap_as_locals_sig ctxt numtypars (SeekReadStandAloneSigRow ctxt localtoken)
if logging then dprintn (ctxt.infile ^ ": fat format for "^nm^", code size = " ^ string code_size^", has_more_sects = "^(if has_more_sects then "true" else "false")^",b = "^string b);
(* Read the method body *)
let instrs,raw2lab,lab2pc,raw2nextLab = SeekReadTopCode ctxt nm numtypars ( code_size) code_base seqpoints
(* Read all the sections that follow the method body. *)
(* These contain the exception clauses. *)
let next_sect_base = ref (align 4 (code_base + code_size))
let more_sects = ref has_more_sects
let seh = ref []
while !more_sects do
let sect_base = !next_sect_base
let sect_flag = SeekReadByteAsInt32 ctxt.is sect_base
if logging then dprintn (ctxt.infile ^ ": fat format for "^nm^", sect_flag = " ^ string sect_flag);
let sect_size, clauses =
if (sect_flag &&& e_CorILMethod_Sect_FatFormat) <> 0x0 then
let big_size = (SeekReadInt32 ctxt.is sect_base) lsr 8
if logging then dprintn (nm^": one more section");
if logging then dprintn (ctxt.infile ^ ": big_size = "^string big_size);
let clauses =
if (sect_flag &&& e_CorILMethod_Sect_EHTable) <> 0x0 then
// WORKAROUND: The ECMA spec says this should be
// let num_clauses = ((big_size - 4) / 24) in
// but the CCI IL generator generates multiples of 24
let num_clauses = (big_size / 24)
if logging then dprintn (nm^" has "^string num_clauses ^" fat seh clauses");
List.init num_clauses (fun i ->
let clause_base = sect_base + 4 + (i * 24)
let kind = SeekReadInt32 ctxt.is (clause_base + 0)
if logging then dprintn ("One fat SEH clause, kind = "^string kind);
let st1 = SeekReadInt32 ctxt.is (clause_base + 4)
let sz1 = SeekReadInt32 ctxt.is (clause_base + 8)
let st2 = SeekReadInt32 ctxt.is (clause_base + 12)
let sz2 = SeekReadInt32 ctxt.is (clause_base + 16)
let extra = SeekReadInt32 ctxt.is (clause_base + 20)
(kind,st1,sz1,st2,sz2,extra))
else []
big_size, clauses
else
let small_size = SeekReadByteAsInt32 ctxt.is (sect_base + 0x01)
let clauses =
if (sect_flag &&& e_CorILMethod_Sect_EHTable) <> 0x0 then begin
if logging then dprintn (nm^": small_size = "^string small_size);
(* WORKAROUND: The ECMA spec says this should be *)
(* let num_clauses = ((small_size - 4) / 12) in *)
(* but the C# compiler (or some IL generator) generates multiples of 12 *)
let num_clauses = (small_size / 12)
if logging then dprintn (nm^" has "^string num_clauses ^" tiny seh clauses");
List.init num_clauses (fun i ->
let clause_base = sect_base + 4 + (i * 12)
let kind = SeekReadUInt16AsInt32 ctxt.is (clause_base + 0)
if logging then dprintn ("One tiny SEH clause, kind = "^string kind);
let st1 = SeekReadUInt16AsInt32 ctxt.is (clause_base + 2)
let sz1 = SeekReadByteAsInt32 ctxt.is (clause_base + 4)
let st2 = SeekReadUInt16AsInt32 ctxt.is (clause_base + 5)
let sz2 = SeekReadByteAsInt32 ctxt.is (clause_base + 7)
let extra = SeekReadInt32 ctxt.is (clause_base + 8)
(kind,st1,sz1,st2,sz2,extra))
end else []
small_size, clauses
(* Morph together clauses that cover the same range *)
let seh_clauses =
let seh_map = Dictionary.create (List.length clauses)
List.iter
(fun (kind,st1,sz1,st2,sz2,extra) ->
let try_start = raw2lab ( st1)
let try_finish = raw2lab ( (st1 + sz1))
let handler_start = raw2lab ( st2)
let handler_finish = raw2lab ( (st2 + sz2))
let clause =
if kind = e_COR_ILEXCEPTION_CLAUSE_EXCEPTION then
SEH_type_catch(SeekReadTypeDefOrRef ctxt numtypars AsObject [] (uncoded_token_to_tdor (i32_to_uncoded_token extra)), (handler_start, handler_finish) )
elif kind = e_COR_ILEXCEPTION_CLAUSE_FILTER then
let filter_start = raw2lab ( extra)
let filter_finish = handler_start
SEH_filter_catch((filter_start, filter_finish), (handler_start, handler_finish))
elif kind = e_COR_ILEXCEPTION_CLAUSE_FINALLY then
SEH_finally(handler_start, handler_finish)
elif kind = e_COR_ILEXCEPTION_CLAUSE_FAULT then
SEH_fault(handler_start, handler_finish)
else begin
dprintn (ctxt.infile ^ ": unknown exception handler kind: "^string kind);
SEH_finally(handler_start, handler_finish)
end
let key = (try_start, try_finish)
if Dictionary.mem seh_map key then
let prev = Dictionary.find seh_map key
Dictionary.replace seh_map key (prev @ [clause])
else
Dictionary.add seh_map key [clause])
clauses;
Dictionary.fold (fun key bs acc -> {exnRange=key; exnClauses=bs} :: acc) seh_map []
seh := seh_clauses;
more_sects := (sect_flag &&& e_CorILMethod_Sect_MoreSects) <> 0x0;
next_sect_base := sect_base + sect_size;
done; (* while *)
(* Convert the linear code format to the nested code format *)
if logging then dprintn ("doing local_pdb_infos2");
let local_pdb_infos2 = List.map (fun f -> f raw2nextLab) local_pdb_infos
if logging then dprintn ("done local_pdb_infos2, checking code...");
let code = check_code (build_code nm lab2pc instrs !seh local_pdb_infos2)
if logging then dprintn ("done checking code.");
MethodBody_il
{ ilZeroInit=initlocals;
ilMaxStack= maxstack;
ilNoInlining=noinline;
ilLocals=locals;
ilCode=code;
ilSource=mrange_pdb_info}
else
if logging then failwith "unknown format";
MethodBody_abstract
end)
and i32_as_variant_typ ctxt (n:int32) =
if List.mem_assoc n (Lazy.force variant_type_rmap) then
List.assoc n (Lazy.force variant_type_rmap)
elif (n &&& vt_ARRAY) <> 0x0 then VariantType_array (i32_as_variant_typ ctxt (n &&& (~~~ vt_ARRAY)))
elif (n &&& vt_VECTOR) <> 0x0 then VariantType_vector (i32_as_variant_typ ctxt (n &&& (~~~ vt_VECTOR)))
elif (n &&& vt_BYREF) <> 0x0 then VariantType_byref (i32_as_variant_typ ctxt (n &&& (~~~ vt_BYREF)))
else (dprintn (ctxt.infile ^ ": i32_as_variant_typ ctxt: unexpected variant type, n = "^string n) ; VariantType_empty)
and ReadBlobHeapAsNativeType ctxt blob_idx =
if logging then dprintn (ctxt.infile ^ ": reading native type blob "^string blob_idx);
let bytes = ReadBlobHeap ctxt blob_idx
let res,_ = sigptr_get_native_typ ctxt bytes 0
res
and sigptr_get_native_typ ctxt bytes sigptr =
if logging then dprintn (ctxt.infile ^ ": reading native type blob, sigptr= "^string sigptr);
let ntbyte,sigptr = sigptr_get_byte bytes sigptr
if List.mem_assoc ntbyte (Lazy.force native_type_map) then
List.assoc ntbyte (Lazy.force native_type_map), sigptr
elif ntbyte = 0x0 then NativeType_empty, sigptr
elif ntbyte = nt_CUSTOMMARSHALER then
if logging then
for i = 0 to Bytes.length bytes - 1 do
if logging then dprintn (ctxt.infile ^ ": byte "^string i^" = "^string(Bytes.get bytes i));
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM1) , sigptr= "^string sigptr^ ", Bytes.length bytes = "^string(Bytes.length bytes));
let guidLen,sigptr = sigptr_get_z_i32 bytes sigptr
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM2) , sigptr= "^string sigptr^", guidLen = "^string ( guidLen));
let guid,sigptr = sigptr_get_bytes ( guidLen) bytes sigptr
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM3) , sigptr= "^string sigptr);
let nativeTypeNameLen,sigptr = sigptr_get_z_i32 bytes sigptr
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM4) , sigptr= "^string sigptr^", nativeTypeNameLen = "^string ( nativeTypeNameLen));
let nativeTypeName,sigptr = sigptr_get_string ( nativeTypeNameLen) bytes sigptr
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM4) , sigptr= "^string sigptr^", nativeTypeName = "^nativeTypeName);
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM5) , sigptr= "^string sigptr);
let custMarshallerNameLen,sigptr = sigptr_get_z_i32 bytes sigptr
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM6) , sigptr= "^string sigptr^", custMarshallerNameLen = "^string ( custMarshallerNameLen));
let custMarshallerName,sigptr = sigptr_get_string ( custMarshallerNameLen) bytes sigptr
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM7) , sigptr= "^string sigptr^", custMarshallerName = "^custMarshallerName);
let cookieStringLen,sigptr = sigptr_get_z_i32 bytes sigptr
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM8) , sigptr= "^string sigptr^", cookieStringLen = "^string ( cookieStringLen));
let cookieString,sigptr = sigptr_get_bytes ( cookieStringLen) bytes sigptr
if logging then dprintn (ctxt.infile ^ ": reading native type blob (CM9) , sigptr= "^string sigptr);
NativeType_custom (guid,nativeTypeName,custMarshallerName,cookieString), sigptr
elif ntbyte = nt_FIXEDSYSSTRING then
let i,sigptr = sigptr_get_z_i32 bytes sigptr
NativeType_fixed_sysstring i, sigptr
elif ntbyte = nt_FIXEDARRAY then
let i,sigptr = sigptr_get_z_i32 bytes sigptr
NativeType_fixed_array i, sigptr
elif ntbyte = nt_SAFEARRAY then
(if sigptr >= Bytes.length bytes then
NativeType_safe_array(VariantType_empty, None),sigptr
else
let i,sigptr = sigptr_get_z_i32 bytes sigptr
if sigptr >= Bytes.length bytes then
NativeType_safe_array (i32_as_variant_typ ctxt i, None), sigptr
else
let len,sigptr = sigptr_get_z_i32 bytes sigptr
let s,sigptr = sigptr_get_string ( len) bytes sigptr
NativeType_safe_array (i32_as_variant_typ ctxt i, Some s), sigptr)
elif ntbyte = nt_ARRAY then
if sigptr >= Bytes.length bytes then
NativeType_array(None,None),sigptr
else
let nt,sigptr =
let u,sigptr' = sigptr_get_z_i32 bytes sigptr
if (u = nt_MAX) then
NativeType_empty, sigptr'
else
(* note: go back to start and read native type *)
sigptr_get_native_typ ctxt bytes sigptr
if sigptr >= Bytes.length bytes then
NativeType_array (Some nt,None), sigptr
else
let pnum,sigptr = sigptr_get_z_i32 bytes sigptr
if sigptr >= Bytes.length bytes then
NativeType_array (Some nt,Some(pnum,None)), sigptr
else
let additive,sigptr =
if sigptr >= Bytes.length bytes then 0, sigptr
else sigptr_get_z_i32 bytes sigptr
NativeType_array (Some nt,Some(pnum,Some(additive))), sigptr
else (dprintn (ctxt.infile ^ ": unexpected native type, nt = "^string ntbyte); NativeType_empty, sigptr)
and SeekReadManifestResources ctxt () =
mk_lazy_resources
(lazy
[ for i = 1 to ctxt.nrows (tab_ManifestResource) do
let (offset,flags,name_idx,impl_idx) = SeekReadManifestResourceRow ctxt i
let scoref = SeekReadImplAsScopeRef ctxt impl_idx
let datalab =
match scoref with
| ScopeRef_local ->
let start = ctxt.anyV2P ("resource",offset + ctxt.resources_addr)
let len = SeekReadInt32 ctxt.is start
Resource_local (fun () -> SeekReadBytes ctxt.is (start + 4) len)
| ScopeRef_module mref -> Resource_file (mref,offset)
| ScopeRef_assembly aref -> Resource_assembly aref
let r =
{ resourceName= ReadStringHeap ctxt name_idx;
resourceWhere = datalab;
resourceAccess = (if (flags &&& 0x01) <> 0x0 then Resource_public else Resource_private);
resourceCustomAttrs = SeekReadCustomAttrs ctxt (TaggedIndex(hca_ManifestResource, i)) }
yield r ])
and SeekReadNestedExportedTypes ctxt parent_idx =
mk_lazy_nested_exported_types
(lazy
[ for i = 1 to ctxt.nrows tab_ExportedType do
let (flags,tok,name_idx,namespace_idx,impl_idx) = SeekReadExportedTypeRow ctxt i
if not (seek_is_top_TypeDef flags) then
let (TaggedIndex(tag,idx) ) = impl_idx
//let isTopTypeDef = (idx = 0 || tag <> i_ExportedType)
//if not isTopTypeDef then
match tag with
| tag when tag = i_ExportedType && idx = parent_idx ->
let nm = ReadBlobHeapAsTypeName ctxt (name_idx,namespace_idx)
yield
{ nestedExportedTypeName=nm;
nestedExportedTypeAccess=(match type_access_of_flags flags with TypeAccess_nested n -> n | _ -> failwith "non-nested access for a nested type described as being in an auxiliary module");
nestedExportedTypeNested=SeekReadNestedExportedTypes ctxt i;
nestedExportedTypeCustomAttrs=SeekReadCustomAttrs ctxt (TaggedIndex(hca_ExportedType, i)) }
| _ -> () ])
and SeekReadTopExportedTypes ctxt () =
mk_lazy_exported_types
(lazy
begin
let res = ref []
for i = 1 to ctxt.nrows tab_ExportedType do
let (flags,tok,name_idx,namespace_idx,impl_idx) = SeekReadExportedTypeRow ctxt i
if seek_is_top_TypeDef flags then
//let (TaggedIndex(tag,idx) ) = impl_idx
//let isTopTypeDef = (idx = 0 || tag <> i_ExportedType)
//if isTopTypeDef then
try
let nm = ReadBlobHeapAsTypeName ctxt (name_idx,namespace_idx)
let scoref = SeekReadImplAsScopeRef ctxt impl_idx
let entry =
{ exportedTypeScope=scoref;
exportedTypeName=nm;
exportedTypeForwarder = ((flags &&& 0x00200000) <> 0);
exportedTypeAccess=type_access_of_flags flags;
exportedTypeNested=SeekReadNestedExportedTypes ctxt i;
exportedTypeCustomAttrs=SeekReadCustomAttrs ctxt (TaggedIndex(hca_ExportedType, i)) }
res := entry :: !res;
with _ -> // BUG 3794: Type forwarding is broken for nested types
()
done;
List.rev !res
end)
let getPDBReader opts infile =
match opts.pdbPath with
| None -> None
| Some pdbpath ->
try
let pdbr = pdbReadOpen infile pdbpath
let pdbdocs = pdbReaderGetDocuments pdbr
let tab = new Dictionary<_,_>(Array.length pdbdocs)
pdbdocs |> Array.iter (fun pdbdoc ->
let url = pdbDocumentGetURL pdbdoc
tab.[url] <-
ILSourceDocument.Create(language=Some (pdbDocumentGetLanguage pdbdoc),
vendor = Some (pdbDocumentGetLanguageVendor pdbdoc),
documentType = Some (pdbDocumentGetType pdbdoc),
file = url));
let docfun url = if tab.ContainsKey url then tab.[url] else failwith ("Document with URL "^url^" not found in list of documents in the PDB file")
Some (pdbr, docfun)
with e -> dprintn ("* Warning: PDB file could not be read and will be ignored: "^e.Message); None
(*-----------------------------------------------------------------------
* Crack the binary headers, build a reader context and return the lazy
* read of the AbsIL module.
* ----------------------------------------------------------------------*)
let rec gen_open_binary_reader infile is opts =
(* MSDOS HEADER *)
let pe_signature_phys_loc = SeekReadInt32 is 0x3c
(* PE HEADER *)
let pe_file_header_phys_loc = pe_signature_phys_loc + 0x04
let pe_optional_header_phys_loc = pe_file_header_phys_loc + 0x14
let pe_signature = SeekReadInt32 is (pe_signature_phys_loc + 0)
if pe_signature <> 0x4550 then failwithf "not a PE file - bad magic PE number 0x%08x, is = %A" pe_signature is;
(* PE SIGNATURE *)
let machine = SeekReadUInt16AsInt32 is (pe_file_header_phys_loc + 0)
let num_sections = SeekReadUInt16AsInt32 is (pe_file_header_phys_loc + 2)
let opt_header_size = SeekReadUInt16AsInt32 is (pe_file_header_phys_loc + 16)
if opt_header_size <> 0xe0 &&
opt_header_size <> 0xf0 then failwith "not a PE file - bad optional header size";
let x64adjust = opt_header_size - 0xe0
let only64 = (opt_header_size = 0xf0) (* May want to read in the optional header Magic number and check that as well... *)
let platform = match machine with | 0x8664 -> Some(AMD64) | 0x200 -> Some(IA64) | _ -> Some(X86)
let section_headers_start_phys_loc = pe_optional_header_phys_loc + opt_header_size
let flags = SeekReadUInt16AsInt32 is (pe_file_header_phys_loc + 18)
let is_dll = (flags &&& 0x2000) <> 0x0
(* OPTIONAL PE HEADER *)
let text_phys_size = SeekReadInt32 is (pe_optional_header_phys_loc + 4) (* Size of the code (text) section, or the sum of all code sections if there are multiple sections. *)
(* x86: 000000a0 *)
let initdata_phys_size = SeekReadInt32 is (pe_optional_header_phys_loc + 8) (* Size of the initialized data section, or the sum of all such sections if there are multiple data sections. *)
let uninitdata_phys_size = SeekReadInt32 is (pe_optional_header_phys_loc + 12) (* Size of the uninitialized data section, or the sum of all such sections if there are multiple data sections. *)
let entrypoint_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 16) (* RVA of entry point , needs to point to bytes 0xFF 0x25 followed by the RVA+!0x4000000 in a section marked execute/read for EXEs or 0 for DLLs e.g. 0x0000b57e *)
let text_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 20) (* e.g. 0x0002000 *)
(* x86: 000000b0 *)
let data_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 24) (* e.g. 0x0000c000 *)
(* REVIEW: For now, we'll use the DWORD at offset 24 for x64. This currently ok since fsc doesn't support true 64-bit image bases,
but we'll have to fix this up when such support is added. *)
let image_base_real = if only64 then data_addr else SeekReadInt32 is (pe_optional_header_phys_loc + 28) (* Image Base Always 0x400000 (see Section 23.1). - QUERY : no it's not always 0x400000, e.g. 0x034f0000 *)
let align_virt = SeekReadInt32 is (pe_optional_header_phys_loc + 32) (* Section Alignment Always 0x2000 (see Section 23.1). *)
let align_phys = SeekReadInt32 is (pe_optional_header_phys_loc + 36) (* File Alignment Either 0x200 or 0x1000. *)
(* x86: 000000c0 *)
let os_major = SeekReadUInt16 is (pe_optional_header_phys_loc + 40) (* OS Major Always 4 (see Section 23.1). *)
let os_minor = SeekReadUInt16 is (pe_optional_header_phys_loc + 42) (* OS Minor Always 0 (see Section 23.1). *)
let user_major = SeekReadUInt16 is (pe_optional_header_phys_loc + 44) (* User Major Always 0 (see Section 23.1). *)
let user_minor = SeekReadUInt16 is (pe_optional_header_phys_loc + 46) (* User Minor Always 0 (see Section 23.1). *)
let subsys_major = SeekReadUInt16 is (pe_optional_header_phys_loc + 48) (* SubSys Major Always 4 (see Section 23.1). *)
let subsys_minor = SeekReadUInt16 is (pe_optional_header_phys_loc + 50) (* SubSys Minor Always 0 (see Section 23.1). *)
(* x86: 000000d0 *)
let image_end_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 56) (* Image Size: Size, in bytes, of image, including all headers and padding; shall be a multiple of Section Alignment. e.g. 0x0000e000 *)
let header_phys_size = SeekReadInt32 is (pe_optional_header_phys_loc + 60) (* Header Size Combined size of MS-DOS Header, PE Header, PE Optional Header and padding; shall be a multiple of the file alignment. *)
let subsys = SeekReadUInt16 is (pe_optional_header_phys_loc + 68) (* SubSystem Subsystem required to run this image. Shall be either IMAGE_SUBSYSTEM_WINDOWS_CE_GUI (!0x3) or IMAGE_SUBSYSTEM_WINDOWS_GUI (!0x2). QUERY: Why is this 3 on the images ILASM produces??? *)
(* x86: 000000e0 *)
(* WARNING: THESE ARE 64 bit ON x64/ia64 *)
(* REVIEW: If we ever decide that we need these values for x64, we'll have to read them in as 64bit and fix up the rest of the offsets.
Then again, it should suffice to just use the defaults, and still not bother... *)
(* let stack_reserve = SeekReadInt32 is (pe_optional_header_phys_loc + 72) in *) (* Stack Reserve Size Always 0x100000 (1Mb) (see Section 23.1). *)
(* let stack_commit = SeekReadInt32 is (pe_optional_header_phys_loc + 76) in *) (* Stack Commit Size Always 0x1000 (4Kb) (see Section 23.1). *)
(* let heap_reserve = SeekReadInt32 is (pe_optional_header_phys_loc + 80) in *) (* Heap Reserve Size Always 0x100000 (1Mb) (see Section 23.1). *)
(* let heap_commit = SeekReadInt32 is (pe_optional_header_phys_loc + 84) in *) (* Heap Commit Size Always 0x1000 (4Kb) (see Section 23.1). *)
(* x86: 000000f0, x64: 00000100 *)
let num_data_directories = SeekReadInt32 is (pe_optional_header_phys_loc + 92 + x64adjust) (* Number of Data Directories: Always 0x10 (see Section 23.1). *)
(* 00000100 - these addresses are for x86 - for the x64 location, add x64adjust (0x10) *)
let import_tab_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 104 + x64adjust) (* Import Table RVA of Import Table, (see clause 24.3.1). e.g. 0000b530 *)
let import_tab_size = SeekReadInt32 is (pe_optional_header_phys_loc + 108 + x64adjust) (* Size of Import Table, (see clause 24.3.1). *)
let native_resources_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 112 + x64adjust)
let native_resources_size = SeekReadInt32 is (pe_optional_header_phys_loc + 116 + x64adjust)
(* 00000110 *)
(* 00000120 *)
(* let base_reloc_tab_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 136)
let base_reloc_tab_size = SeekReadInt32 is (pe_optional_header_phys_loc + 140) in *)
(* 00000130 *)
(* 00000140 *)
(* 00000150 *)
let import_addr_tab_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 192 + x64adjust) (* RVA of Import Addr Table, (see clause 24.3.1). e.g. 0x00002000 *)
let import_addr_tab_size = SeekReadInt32 is (pe_optional_header_phys_loc + 196 + x64adjust) (* Size of Import Addr Table, (see clause 24.3.1). e.g. 0x00002000 *)
(* 00000160 *)
let cli_header_addr = SeekReadInt32 is (pe_optional_header_phys_loc + 208 + x64adjust)
let cli_header_size = SeekReadInt32 is (pe_optional_header_phys_loc + 212 + x64adjust)
(* 00000170 *)
(* Crack section headers *)
let section_headers =
[ for i in 0 .. num_sections-1 do
let pos = section_headers_start_phys_loc + i * 0x28
let virt_size = SeekReadInt32 is (pos + 8)
let virt_addr = SeekReadInt32 is (pos + 12)
let phys_loc = SeekReadInt32 is (pos + 20)
yield (virt_addr,virt_size,phys_loc) ]
let find_section_header addr =
let rec look i pos =
if i >= num_sections then 0x0
else
let virt_size = SeekReadInt32 is (pos + 8)
let virt_addr = SeekReadInt32 is (pos + 12)
if (addr >= virt_addr && addr < virt_addr + virt_size) then pos
else look (i+1) (pos + 0x28)
look 0 section_headers_start_phys_loc
let text_header_start = find_section_header cli_header_addr
let data_header_start = find_section_header data_addr
(* let reloc_header_start = find_section_header base_reloc_tab_addr in *)
let text_size = if text_header_start = 0x0 then 0x0 else SeekReadInt32 is (text_header_start + 8)
let text_addr = if text_header_start = 0x0 then 0x0 else SeekReadInt32 is (text_header_start + 12)
let text_phys_size = if text_header_start = 0x0 then 0x0 else SeekReadInt32 is (text_header_start + 16)
let text_phys_loc = if text_header_start = 0x0 then 0x0 else SeekReadInt32 is (text_header_start + 20)
(*
let reloc_size = if reloc_header_start = 0x0 then 0x0 else SeekReadInt32 is (reloc_header_start + 8)
let reloc_addr = if reloc_header_start = 0x0 then 0x0 else SeekReadInt32 is (reloc_header_start + 12)
let reloc_phys_size = if reloc_header_start = 0x0 then 0x0 else SeekReadInt32 is (reloc_header_start + 16)
let reloc_phys_loc = if reloc_header_start = 0x0 then 0x0 else SeekReadInt32 is (reloc_header_start + 20)
*)
if logging then dprintn (infile ^ ": text_header_start = "^string text_header_start);
if logging then dprintn (infile ^ ": data_header_start = "^string data_header_start);
if logging then dprintn (infile ^ ": data_addr (pre section crack) = "^string data_addr);
let data_size = if data_header_start = 0x0 then 0x0 else SeekReadInt32 is (data_header_start + 8)
let data_addr = if data_header_start = 0x0 then 0x0 else SeekReadInt32 is (data_header_start + 12)
let data_phys_size = if data_header_start = 0x0 then 0x0 else SeekReadInt32 is (data_header_start + 16)
let data_phys_loc = if data_header_start = 0x0 then 0x0 else SeekReadInt32 is (data_header_start + 20)
if logging then dprintn (infile ^ ": data_addr (post section crack) = "^string data_addr);
let anyV2P (n,v) =
let rec look i pos =
if i >= num_sections then (failwith (infile ^ ": bad "^n^", rva "^string v); 0x0)
else
let virt_size = SeekReadInt32 is (pos + 8)
let virt_addr = SeekReadInt32 is (pos + 12)
let phys_loc = SeekReadInt32 is (pos + 20)
if (v >= virt_addr && (v < virt_addr + virt_size)) then (v - virt_addr) + phys_loc
else look (i+1) (pos + 0x28)
look 0 section_headers_start_phys_loc
(* let relocV2P v = v - reloc_addr + reloc_phys_loc in *)
if logging then dprintn (infile ^ ": num_sections = "^string num_sections);
if logging then dprintn (infile ^ ": cli_header_addr = "^string cli_header_addr);
if logging then dprintn (infile ^ ": cli_header_phys = "^string (anyV2P ("cli header",cli_header_addr)));
if logging then dprintn (infile ^ ": data_size = "^string data_size);
if logging then dprintn (infile ^ ": data_addr = "^string data_addr);
let cli_header_phys_loc = anyV2P ("cli header",cli_header_addr)
let major_runtime_version = SeekReadUInt16 is (cli_header_phys_loc + 4)
let minor_runtime_version = SeekReadUInt16 is (cli_header_phys_loc + 6)
let metadata_addr = SeekReadInt32 is (cli_header_phys_loc + 8)
let metadata_size = SeekReadInt32 is (cli_header_phys_loc + 12)
let cli_flags = SeekReadInt32 is (cli_header_phys_loc + 16)
let ilonly = (cli_flags &&& 0x01) <> 0x00
let only32 = (cli_flags &&& 0x02) <> 0x00
let strongname_signed = (cli_flags &&& 0x08) <> 0x00
let trackdebugdata = (cli_flags &&& 0x010000) <> 0x00
let eptoken = SeekReaduncoded_token is (cli_header_phys_loc + 20)
let resources_addr = SeekReadInt32 is (cli_header_phys_loc + 24)
let resources_size = SeekReadInt32 is (cli_header_phys_loc + 28)
let strongname_addr = SeekReadInt32 is (cli_header_phys_loc + 32)
let strongname_size = SeekReadInt32 is (cli_header_phys_loc + 36)
let vtable_fixups_addr = SeekReadInt32 is (cli_header_phys_loc + 40)
let vtable_fixups_size = SeekReadInt32 is (cli_header_phys_loc + 44)
if logging then dprintn (infile ^ ": metadata_addr = "^string metadata_addr);
if logging then dprintn (infile ^ ": resources_addr = "^string resources_addr);
if logging then dprintn (infile ^ ": resources_size = "^string resources_size);
if logging then dprintn (infile ^ ": native_resources_addr = "^string native_resources_addr);
if logging then dprintn (infile ^ ": native_resources_size = "^string native_resources_size);
let metadata_phys_loc = anyV2P ("metadata",metadata_addr)
let magic = SeekReadUInt16AsInt32 is metadata_phys_loc
if magic <> 0x5342 then failwith (infile ^ ": bad metadata magic number: " ^ string magic);
let magic2 = SeekReadUInt16AsInt32 is (metadata_phys_loc + 2)
if magic2 <> 0x424a then failwith "bad metadata magic number";
let major_metadata_version = SeekReadUInt16 is (metadata_phys_loc + 4)
let minor_metadata_version = SeekReadUInt16 is (metadata_phys_loc + 6)
let version_length = SeekReadInt32 is (metadata_phys_loc + 12)
let x = align 0x04 (16 + version_length)
let num_streams = SeekReadUInt16AsInt32 is (metadata_phys_loc + x + 2)
let stream_headers_start = (metadata_phys_loc + x + 4)
if logging then dprintn (infile ^ ": num_streams = "^string num_streams);
if logging then dprintn (infile ^ ": stream_headers_start = "^string stream_headers_start);
(* Crack stream headers *)
let try_find_stream name =
let rec look i pos =
if i >= num_streams then raise Not_found
else
let offset = SeekReadInt32 is (pos + 0)
let length = SeekReadInt32 is (pos + 4)
let res = ref true
let fin = ref false
let n = ref 0
// read and compare the stream name byte by byte
while (not !fin) do
let c= SeekReadByteAsInt32 is (pos + 8 + (!n))
if c = 0 then
fin := true
elif !n >= Array.length name or c <> name.[!n] then
res := false;
incr n
if !res then (offset + metadata_phys_loc,length)
else look (i+1) (align 0x04 (pos + 8 + (!n)))
look 0 stream_headers_start
let find_stream name = try try_find_stream name with Not_found -> (0x0, 0x0)
let (tables_stream_phys_loc, tables_stream_size) =
try try_find_stream [| 0x23; 0x7e |] (* #~ *)
with Not_found ->
try try_find_stream [| 0x23; 0x2d |] (* #-: at least one DLL I've seen uses this! *)
with Not_found ->
dprintf "no metadata tables found under stream names '#~' or '#-', please report this\n";
let first_stream_offset = SeekReadInt32 is (stream_headers_start + 0)
let first_stream_length = SeekReadInt32 is (stream_headers_start + 4)
first_stream_offset,first_stream_length
let (strings_stream_phys_loc, strings_stream_size) = find_stream [| 0x23; 0x53; 0x74; 0x72; 0x69; 0x6e; 0x67; 0x73; |] (* #Strings *)
let (user_strings_stream_phys_loc, user_strings_stream_size) = find_stream [| 0x23; 0x55; 0x53; |] (* #US *)
let (guids_stream_phys_loc, guids_stream_size) = find_stream [| 0x23; 0x47; 0x55; 0x49; 0x44; |] (* #GUID *)
let (blobs_stream_phys_loc, blobs_stream_size) = find_stream [| 0x23; 0x42; 0x6c; 0x6f; 0x62; |] (* #Blob *)
if logging then dprintn (infile ^ ": tables_addr = "^string tables_stream_phys_loc);
if logging then dprintn (infile ^ ": tables_size = "^string tables_stream_size);
if logging then dprintn (infile ^ ": strings_addr = "^string strings_stream_phys_loc);
if logging then dprintn (infile ^ ": strings_size = "^string strings_stream_size);
if logging then dprintn (infile ^ ": user_strings_addr = "^string user_strings_stream_phys_loc);
if logging then dprintn (infile ^ ": guids_addr = "^string guids_stream_phys_loc);
if logging then dprintn (infile ^ ": blobs_addr = "^string blobs_stream_phys_loc);
let tables_stream_major_version = SeekReadByteAsInt32 is (tables_stream_phys_loc + 4)
let tables_stream_minor_version = SeekReadByteAsInt32 is (tables_stream_phys_loc + 5)
let usingWhidbeyBeta1TableSchemeForGenericParam = (tables_stream_major_version = 1) && (tables_stream_minor_version = 1)
let table_kinds =
[|kind_Module (* Table 0 *);
kind_TypeRef (* Table 1 *);
kind_TypeDef (* Table 2 *);
kind_Illegal (* kind_FieldPtr *) (* Table 3 *);
kind_FieldDef (* Table 4 *);
kind_Illegal (* kind_MethodPtr *) (* Table 5 *);
kind_MethodDef (* Table 6 *);
kind_Illegal (* kind_ParamPtr *) (* Table 7 *);
kind_Param (* Table 8 *);
kind_InterfaceImpl (* Table 9 *);
kind_MemberRef (* Table 10 *);
kind_Constant (* Table 11 *);
kind_CustomAttribute (* Table 12 *);
kind_FieldMarshal (* Table 13 *);
kind_DeclSecurity (* Table 14 *);
kind_ClassLayout (* Table 15 *);
kind_FieldLayout (* Table 16 *);
kind_StandAloneSig (* Table 17 *);
kind_EventMap (* Table 18 *);
kind_Illegal (* kind_EventPtr *) (* Table 19 *);
kind_Event (* Table 20 *);
kind_PropertyMap (* Table 21 *);
kind_Illegal (* kind_PropertyPtr *) (* Table 22 *);
kind_Property (* Table 23 *);
kind_MethodSemantics (* Table 24 *);
kind_MethodImpl (* Table 25 *);
kind_ModuleRef (* Table 26 *);
kind_TypeSpec (* Table 27 *);
kind_ImplMap (* Table 28 *);
kind_FieldRVA (* Table 29 *);
kind_Illegal (* kind_ENCLog *) (* Table 30 *);
kind_Illegal (* kind_ENCMap *) (* Table 31 *);
kind_Assembly (* Table 32 *);
kind_Illegal (* kind_AssemblyProcessor *) (* Table 33 *);
kind_Illegal (* kind_AssemblyOS *) (* Table 34 *);
kind_AssemblyRef (* Table 35 *);
kind_Illegal (* kind_AssemblyRefProcessor *) (* Table 36 *);
kind_Illegal (* kind_AssemblyRefOS *) (* Table 37 *);
kind_FileRef (* Table 38 *);
kind_ExportedType (* Table 39 *);
kind_ManifestResource (* Table 40 *);
kind_Nested (* Table 41 *);
(if usingWhidbeyBeta1TableSchemeForGenericParam then kind_GenericParam_v1_1 else kind_GenericParam_v2_0); (* Table 42 *)
kind_MethodSpec (* Table 43 *);
kind_GenericParamConstraint (* Table 44 *);
kind_Illegal (* Table 45 *);
kind_Illegal (* Table 46 *);
kind_Illegal (* Table 47 *);
kind_Illegal (* Table 48 *);
kind_Illegal (* Table 49 *);
kind_Illegal (* Table 50 *);
kind_Illegal (* Table 51 *);
kind_Illegal (* Table 52 *);
kind_Illegal (* Table 53 *);
kind_Illegal (* Table 54 *);
kind_Illegal (* Table 55 *);
kind_Illegal (* Table 56 *);
kind_Illegal (* Table 57 *);
kind_Illegal (* Table 58 *);
kind_Illegal (* Table 59 *);
kind_Illegal (* Table 60 *);
kind_Illegal (* Table 61 *);
kind_Illegal (* Table 62 *);
kind_Illegal (* Table 63 *);
|]
let heap_sizes = SeekReadByteAsInt32 is (tables_stream_phys_loc + 6)
let valid = SeekReadInt64 is (tables_stream_phys_loc + 8)
let sorted = SeekReadInt64 is (tables_stream_phys_loc + 16)
let tables_present, table_num_rows, start_of_tables =
let present = ref []
let num_rows = Array.create 64 0
let prev_numrow_idx = ref (tables_stream_phys_loc + 24)
for i = 0 to 63 do
if (valid &&& (int64 1 <<< i)) <> int64 0 then
present := i :: !present;
num_rows.[i] <- (SeekReadInt32 is !prev_numrow_idx);
prev_numrow_idx := !prev_numrow_idx + 4
List.rev !present, num_rows, !prev_numrow_idx
let nrows t = table_num_rows.[tag_of_table t]
let num_tables = List.length tables_present
let strings_big = (heap_sizes &&& 1) <> 0
let guids_big = (heap_sizes &&& 2) <> 0
let blobs_big = (heap_sizes &&& 4) <> 0
if logging then dprintn (infile ^ ": num_tables = "^string num_tables);
if logging && strings_big then dprintn (infile ^ ": strings are big");
if logging && blobs_big then dprintn (infile ^ ": blobs are big");
let table_bignesses = Array.map (fun n -> n >= 0x10000) table_num_rows
let coded_bigness nbits tab =
let rows = nrows tab
rows >= (0x10000 lsr nbits)
let tdor_bigness =
coded_bigness 2 tab_TypeDef ||
coded_bigness 2 tab_TypeRef ||
coded_bigness 2 tab_TypeSpec
let tomd_bigness =
coded_bigness 1 tab_TypeDef ||
coded_bigness 1 tab_Method
let hc_bigness =
coded_bigness 2 tab_Field ||
coded_bigness 2 tab_Param ||
coded_bigness 2 tab_Property
let hca_bigness =
coded_bigness 5 tab_Method ||
coded_bigness 5 tab_Field ||
coded_bigness 5 tab_TypeRef ||
coded_bigness 5 tab_TypeDef ||
coded_bigness 5 tab_Param ||
coded_bigness 5 tab_InterfaceImpl ||
coded_bigness 5 tab_MemberRef ||
coded_bigness 5 tab_Module ||
coded_bigness 5 tab_Permission ||
coded_bigness 5 tab_Property ||
coded_bigness 5 tab_Event ||
coded_bigness 5 tab_StandAloneSig ||
coded_bigness 5 tab_ModuleRef ||
coded_bigness 5 tab_TypeSpec ||
coded_bigness 5 tab_Assembly ||
coded_bigness 5 tab_AssemblyRef ||
coded_bigness 5 tab_File ||
coded_bigness 5 tab_ExportedType ||
coded_bigness 5 tab_ManifestResource ||
coded_bigness 5 tab_GenericParam ||
coded_bigness 5 tab_GenericParamConstraint ||
coded_bigness 5 tab_MethodSpec
let hfm_bigness =
coded_bigness 1 tab_Field ||
coded_bigness 1 tab_Param
let hds_bigness =
coded_bigness 2 tab_TypeDef ||
coded_bigness 2 tab_Method ||
coded_bigness 2 tab_Assembly
let mrp_bigness =
coded_bigness 3 tab_TypeRef ||
coded_bigness 3 tab_ModuleRef ||
coded_bigness 3 tab_Method ||
coded_bigness 3 tab_TypeSpec
let hs_bigness =
coded_bigness 1 tab_Event ||
coded_bigness 1 tab_Property
let mdor_bigness =
coded_bigness 1 tab_Method ||
coded_bigness 1 tab_MemberRef
let mf_bigness =
coded_bigness 1 tab_Field ||
coded_bigness 1 tab_Method
let i_bigness =
coded_bigness 2 tab_File ||
coded_bigness 2 tab_AssemblyRef ||
coded_bigness 2 tab_ExportedType
let cat_bigness =
coded_bigness 3 tab_Method ||
coded_bigness 3 tab_MemberRef
let rs_bigness =
coded_bigness 2 tab_Module ||
coded_bigness 2 tab_ModuleRef ||
coded_bigness 2 tab_AssemblyRef ||
coded_bigness 2 tab_TypeRef
let row_kind_size (RowKind kinds) =
List.fold
(fun sofar x ->
sofar +
match x with
| UShort -> 2
| ULong -> 4
| Byte -> 1
| Data -> 4
| GGuid -> (if guids_big then 4 else 2)
| Blob -> (if blobs_big then 4 else 2)
| SString -> (if strings_big then 4 else 2)
| SimpleIndex (Table tab) -> (if table_bignesses.[tab] then 4 else 2)
| TypeDefOrRefOrSpec -> (if tdor_bigness then 4 else 2)
| TypeOrMethodDef -> (if tomd_bigness then 4 else 2)
| HasConstant -> (if hc_bigness then 4 else 2)
| HasCustomAttribute -> (if hca_bigness then 4 else 2)
| HasFieldMarshal -> (if hfm_bigness then 4 else 2)
| HasDeclSecurity -> (if hds_bigness then 4 else 2)
| MemberRefParent -> (if mrp_bigness then 4 else 2)
| HasSemantics -> (if hs_bigness then 4 else 2)
| MethodDefOrRef -> (if mdor_bigness then 4 else 2)
| MemberForwarded -> (if mf_bigness then 4 else 2)
| Implementation -> (if i_bigness then 4 else 2)
| CustomAttributeType -> (if cat_bigness then 4 else 2)
| ResolutionScope -> (if rs_bigness then 4 else 2)) 0 kinds
let table_row_sizes =
let res = Array.create 64 0x0
for i = 0 to 63 do
res.[i] <- (row_kind_size (table_kinds.[i]));
(* dprintf "table_row_sizes.[%d] = %ld\n" i res.[i]; *)
res
let table_phys_locs =
let res = Array.create 64 0x0
let prev_table_phys_loc = ref start_of_tables
for i = 0 to 63 do
res.[i] <- !prev_table_phys_loc;
prev_table_phys_loc := !prev_table_phys_loc + ((table_num_rows.[i]) * table_row_sizes.[i]);
if logging then dprintf "table_phys_locs.[%d] = %ld, offset from start_of_tables = 0x%08lx\n" i res.[i] (res.[i] - start_of_tables);
res
let inbase = System.IO.Path.GetFileName infile^": "
// All the caches. The sizes are guesstimates for the rough sharing-density of the assembly
// We should also take a parameter that indicates how much of the assembly we actually
// expect to get read at all
let cache_AssemblyRef = mk_cache_int32 opts.optimizeForMemory inbase "ILAssemblyRef" (nrows (tab_AssemblyRef))
let cache_MethodSpec_as_mdata = mk_cache_gen opts.optimizeForMemory inbase "MethodSpec_as_mdata" (nrows (tab_MethodSpec) / 20 + 1)
let cache_MemberRef_as_mdata = mk_cache_gen opts.optimizeForMemory inbase "MemberRef_as_mdata" (nrows (tab_MemberRef) / 20 + 1)
//let cache_MemberRef_as_fspec = mk_cache_gen opts.optimizeForMemory inbase "MemberRef_as_fspec" (nrows (tab_MemberRef) / 40 + 1)
let cache_CustomAttr = mk_cache_gen opts.optimizeForMemory inbase "CustomAttr" (nrows (tab_CustomAttribute) / 50 + 1)
//let cache_SecurityDecl = mk_cache_gen opts.optimizeForMemory inbase "SecurityDecl" (nrows (tab_Permission) / 20 + 1)
let cache_TypeRef = mk_cache_int32 opts.optimizeForMemory inbase "ILTypeRef" (nrows (tab_TypeRef) / 20 + 1)
let cache_TypeRef_as_typ = mk_cache_gen opts.optimizeForMemory inbase "TypeRef_as_typ" (nrows (tab_TypeRef) / 20 + 1)
let cache_blob_heap_as_property_sig = mk_cache_gen opts.optimizeForMemory inbase "blob_heap_as_property_sig" (nrows (tab_Property) / 20 + 1)
let cache_blob_heap_as_field_sig = mk_cache_gen opts.optimizeForMemory inbase "blob_heap_as_field_sig" (nrows (tab_Field) / 20 + 1)
let cache_blob_heap_as_method_sig = mk_cache_gen opts.optimizeForMemory inbase "blob_heap_as_method_sig" (nrows (tab_Method) / 20 + 1)
//let cache_blob_heap_as_locals_sig = mk_cache_gen opts.optimizeForMemory inbase "blob_heap_as_locals_sig" (nrows (tab_Method) / 20 + 1)
let cache_TypeDef_as_typ = mk_cache_gen opts.optimizeForMemory inbase "TypeDef_as_typ" (nrows (tab_TypeDef) / 20 + 1)
let cache_MethodDef_as_mdata = mk_cache_int32 opts.optimizeForMemory inbase "MethodDef_as_mdata" (nrows (tab_Method) / 20 + 1)
let cache_GenericParams = mk_cache_gen opts.optimizeForMemory inbase "GenericParams" (nrows (tab_GenericParam) / 20 + 1)
let cache_GenericParamConstraints = mk_cache_gen opts.optimizeForMemory inbase "GenericParamConstraints" (nrows (tab_GenericParamConstraint) / 8 + 1)
let cache_FieldDef_as_fspec = mk_cache_int32 opts.optimizeForMemory inbase "FieldDef_as_fspec" (nrows (tab_Field) / 20 + 1)
let cache_user_string_heap = mk_cache_int32 opts.optimizeForMemory inbase "user_string heap" ( user_strings_stream_size / 20 + 1)
(* nb. Lots and lots of cache hits on this cache, hence never optimize cache away *)
let cache_string_heap = mk_cache_int32 false inbase "string heap" ( strings_stream_size / 50 + 1)
let cache_blob_heap = mk_cache_int32 opts.optimizeForMemory inbase "blob heap" ( blobs_stream_size / 50 + 1)
// These tables are not required to enforce sharing fo the final data
// structure, but are very useful as searching these tables gives rise to many reads
// in standard applications.
let cache_Nested_row = mk_cache_int32 opts.optimizeForMemory inbase "Nested Table Rows" (nrows (tab_Nested) / 20 + 1)
let cache_Constant_row = mk_cache_int32 opts.optimizeForMemory inbase "Constant Rows" (nrows (tab_Constant) / 20 + 1)
let cache_MethodSemantics_row = mk_cache_int32 opts.optimizeForMemory inbase "MethodSemantics Rows" (nrows (tab_MethodSemantics) / 20 + 1)
let cache_TypeDef_row = mk_cache_int32 opts.optimizeForMemory inbase "ILTypeDef Rows" (nrows (tab_TypeDef) / 20 + 1)
let cache_InterfaceImpl_row = mk_cache_int32 opts.optimizeForMemory inbase "InterfaceImpl Rows" (nrows (tab_InterfaceImpl) / 20 + 1)
let cache_FieldMarshal_row = mk_cache_int32 opts.optimizeForMemory inbase "FieldMarshal Rows" (nrows (tab_FieldMarshal) / 20 + 1)
let cache_PropertyMap_row = mk_cache_int32 opts.optimizeForMemory inbase "PropertyMap Rows" (nrows (tab_PropertyMap) / 20 + 1)
let mk_row_counter nm =
let count = ref 0
add_report (fun oc -> if !count <> 0 then output_string oc (inbase^string !count ^ " "^nm^" rows read"^"\n"));
count
let count_TypeRef = mk_row_counter "ILTypeRef"
let count_TypeDef = mk_row_counter "ILTypeDef"
let count_Field = mk_row_counter "Field"
let count_Method = mk_row_counter "Method"
let count_Param = mk_row_counter "Param"
let count_InterfaceImpl = mk_row_counter "InterfaceImpl"
let count_MemberRef = mk_row_counter "MemberRef"
let count_Constant = mk_row_counter "Constant"
let count_CustomAttribute = mk_row_counter "CustomAttribute"
let count_FieldMarshal = mk_row_counter "FieldMarshal"
let count_Permission = mk_row_counter "Permission"
let count_ClassLayout = mk_row_counter "ClassLayout"
let count_FieldLayout = mk_row_counter "FieldLayout"
let count_StandAloneSig = mk_row_counter "StandAloneSig"
let count_EventMap = mk_row_counter "EventMap"
let count_Event = mk_row_counter "Event"
let count_PropertyMap = mk_row_counter "PropertyMap"
let count_Property = mk_row_counter "Property"
let count_MethodSemantics = mk_row_counter "MethodSemantics"
let count_MethodImpl = mk_row_counter "MethodImpl"
let count_ModuleRef = mk_row_counter "ILModuleRef"
let count_TypeSpec = mk_row_counter "ILTypeSpec"
let count_ImplMap = mk_row_counter "ImplMap"
let count_FieldRVA = mk_row_counter "FieldRVA"
let count_Assembly = mk_row_counter "Assembly"
let count_AssemblyRef = mk_row_counter "ILAssemblyRef"
let count_File = mk_row_counter "File"
let count_ExportedType = mk_row_counter "ILExportedType"
let count_ManifestResource = mk_row_counter "ManifestResource"
let count_Nested = mk_row_counter "Nested"
let count_GenericParam = mk_row_counter "GenericParam"
let count_GenericParamConstraint = mk_row_counter "GenericParamConstraint"
let count_MethodSpec = mk_row_counter "ILMethodSpec"
(*-----------------------------------------------------------------------
* Set up the PDB reader so we can read debug info for methods.
* ----------------------------------------------------------------------*)
let pdb = if runningOnMono then None else getPDBReader opts infile
let row_addr tab idx = table_phys_locs.[tag_of_table tab] + (idx - 1) * table_row_sizes.[tag_of_table tab]
// Build the reader context
// Use an initialization hole
let ctxtH = ref None
let ctxt = { ilg=opts.ilGlobals;
data_end_points = data_end_points ctxtH;
pdb=pdb;
sorted=sorted;
nrows=nrows;
text_phys_loc=text_phys_loc;
text_phys_size=text_phys_size;
data_phys_loc=data_phys_loc;
data_phys_size=data_phys_size;
anyV2P=anyV2P;
metadata_addr=metadata_addr;
section_headers=section_headers;
native_resources_addr=native_resources_addr;
native_resources_size=native_resources_size;
resources_addr=resources_addr;
strongname_addr=strongname_addr;
vtable_fixups_addr=vtable_fixups_addr;
is=is;
infile=infile;
user_strings_stream_phys_loc=user_strings_stream_phys_loc;
strings_stream_phys_loc=strings_stream_phys_loc;
blobs_stream_phys_loc=blobs_stream_phys_loc;
MemoizeString = memoize id;
ReadUserStringHeap = cache_user_string_heap (ReadUserStringHeapUncached ctxtH);
ReadStringHeap = cache_string_heap (ReadStringHeapUncached ctxtH);
ReadBlobHeap = cache_blob_heap (ReadBlobHeapUncached ctxtH);
SeekReadNestedRow = cache_Nested_row (SeekReadNestedRowUncached ctxtH);
SeekReadConstantRow = cache_Constant_row (SeekReadConstantRowUncached ctxtH);
SeekReadMethodSemanticsRow = cache_MethodSemantics_row (SeekReadMethodSemanticsRowUncached ctxtH);
SeekReadTypeDefRow = cache_TypeDef_row (SeekReadTypeDefRowUncached ctxtH);
SeekReadInterfaceImplRow = cache_InterfaceImpl_row (SeekReadInterfaceImplRowUncached ctxtH);
SeekReadFieldMarshalRow = cache_FieldMarshal_row (SeekReadFieldMarshalRowUncached ctxtH);
SeekReadPropertyMapRow = cache_PropertyMap_row (SeekReadPropertyMapRowUncached ctxtH);
SeekReadAssemblyRef = cache_AssemblyRef (SeekReadAssemblyRefUncached ctxtH);
SeekReadMethodSpec_as_mdata = cache_MethodSpec_as_mdata (SeekReadMethodSpec_as_mdataUncached ctxtH);
SeekReadMemberRef_as_mdata = cache_MemberRef_as_mdata (SeekReadMemberRef_as_mdataUncached ctxtH);
SeekReadMemberRef_as_fspec = (* cache_MemberRef_as_fspec *) (SeekReadMemberRef_as_fspecUncached ctxtH);
SeekReadCustomAttr = cache_CustomAttr (SeekReadCustomAttrUncached ctxtH);
SeekReadSecurityDecl = (* cache_SecurityDecl *) (SeekReadSecurityDeclUncached ctxtH);
SeekReadTypeRef = cache_TypeRef (SeekReadTypeRefUncached ctxtH);
ReadBlobHeap_as_property_sig = cache_blob_heap_as_property_sig (ReadBlobHeap_as_property_sigUncached ctxtH);
ReadBlobHeap_as_field_sig = cache_blob_heap_as_field_sig (ReadBlobHeap_as_field_sigUncached ctxtH);
ReadBlobHeap_as_method_sig = cache_blob_heap_as_method_sig (ReadBlobHeap_as_method_sigUncached ctxtH);
ReadBlobHeap_as_locals_sig = (* cache_blob_heap_as_locals_sig *) (ReadBlobHeap_as_locals_sigUncached ctxtH);
SeekReadTypeDefAsType = cache_TypeDef_as_typ (SeekReadTypeDefAsTypeUncached ctxtH);
SeekReadTypeRef_as_typ = cache_TypeRef_as_typ (SeekReadTypeRef_as_typUncached ctxtH);
SeekReadMethodDef_as_mdata = cache_MethodDef_as_mdata (SeekReadMethodDef_as_mdataUncached ctxtH);
SeekReadGenericParams = cache_GenericParams (SeekReadGenericParamsUncached ctxtH);
SeekReadFieldDef_as_fspec = cache_FieldDef_as_fspec (SeekReadFieldDef_as_fspecUncached ctxtH);
guids_stream_phys_loc = guids_stream_phys_loc;
row_addr=row_addr;
eptoken=eptoken;
rs_bigness =rs_bigness;
tdor_bigness =tdor_bigness;
tomd_bigness =tomd_bigness;
hc_bigness =hc_bigness;
hca_bigness =hca_bigness;
hfm_bigness =hfm_bigness;
hds_bigness =hds_bigness;
mrp_bigness =mrp_bigness;
hs_bigness =hs_bigness;
mdor_bigness =mdor_bigness;
mf_bigness =mf_bigness;
i_bigness =i_bigness;
cat_bigness =cat_bigness;
strings_big=strings_big;
guids_big=guids_big;
blobs_big=blobs_big;
table_bignesses=table_bignesses;
count_TypeRef = count_TypeRef;
count_TypeDef = count_TypeDef;
count_Field = count_Field;
count_Method = count_Method;
count_Param = count_Param;
count_InterfaceImpl = count_InterfaceImpl;
count_MemberRef = count_MemberRef;
count_Constant = count_Constant;
count_CustomAttribute = count_CustomAttribute;
count_FieldMarshal = count_FieldMarshal;
count_Permission = count_Permission;
count_ClassLayout = count_ClassLayout;
count_FieldLayout = count_FieldLayout;
count_StandAloneSig = count_StandAloneSig;
count_EventMap = count_EventMap;
count_Event = count_Event;
count_PropertyMap = count_PropertyMap;
count_Property = count_Property;
count_MethodSemantics = count_MethodSemantics;
count_MethodImpl = count_MethodImpl;
count_ModuleRef = count_ModuleRef;
count_TypeSpec = count_TypeSpec;
count_ImplMap = count_ImplMap;
count_FieldRVA = count_FieldRVA;
count_Assembly = count_Assembly;
count_AssemblyRef = count_AssemblyRef;
count_File = count_File;
count_ExportedType = count_ExportedType;
count_ManifestResource = count_ManifestResource;
count_Nested = count_Nested;
count_GenericParam = count_GenericParam;
count_GenericParamConstraint = count_GenericParamConstraint;
count_MethodSpec = count_MethodSpec; }
ctxtH := Some ctxt;
let ilModule = SeekReadModule ctxt (subsys,ilonly,only32,only64,platform,is_dll, align_virt,align_phys,image_base_real) 1
let ilAssemblyRefs = lazy [ for i in 1 .. nrows (tab_AssemblyRef) do yield SeekReadAssemblyRef ctxt i ]
ilModule,ilAssemblyRefs,pdb
let CloseILModuleReader x = x.dispose()
let defaults =
{ optimizeForMemory=false;
pdbPath= None;
ilGlobals=ecmaILGlobals }
let OpenILModuleReader infile opts =
try
let mmap = MMapChannel.open_in infile
let modul,ilAssemblyRefs,pdb = gen_open_binary_reader infile (MMap mmap) opts
{ modul = modul;
ilAssemblyRefs=ilAssemblyRefs;
dispose = (fun () ->
MMapChannel.close mmap;
match pdb with
| Some (pdbr,_) -> pdbReadClose pdbr
| None -> ()) }
with :? System.DllNotFoundException ->
let is = open_in_bin infile
let cell = ref (Some is)
let modul,ilAssemblyRefs,pdb = gen_open_binary_reader infile (Chan (infile,cell)) opts
{ modul = modul;
ilAssemblyRefs = ilAssemblyRefs;
dispose = (fun () ->
cell := None;
close_in is;
match pdb with
| Some (pdbr,_) -> pdbReadClose pdbr
| None -> ()) }
let ilModuleReaderCache = new Internal.Utilities.Collections.AgedLookup<(string * System.DateTime),ILModuleReader>(0)
let OpenILModuleReaderAfterReadingAllBytes infile opts =
// Use GetDirectoryName and GetFileName to pseudo-normalize the paths.
let key,succeeded =
try (Path.GetFullPath(infile), File.GetLastWriteTime(infile)), true
with e ->
System.Diagnostics.Debug.Assert(false, "Failed to compute key in OpenILModuleReaderAfterReadingAllBytes cache. Falling back to uncached.")
("",System.DateTime.Now), false
let cacheResult =
if not succeeded then None // Fall back to uncached.
else if opts.pdbPath.IsSome then None // can't used a cached entry when reading PDBs, since it makes the returned object IDisposable
else ilModuleReaderCache.TryGet(key)
match cacheResult with
| Some(ilModuleReader) -> ilModuleReader
| None ->
let mc = MemChannel.open_in infile
let modul,ilAssemblyRefs,pdb = gen_open_binary_reader infile (Mem mc) opts
let ilModuleReader =
{ modul = modul;
ilAssemblyRefs = ilAssemblyRefs
dispose = (fun () ->
match pdb with
| Some (pdbr,_) -> pdbReadClose pdbr
| None -> ()) }
if isNone pdb && succeeded then
ilModuleReaderCache.Put(key, ilModuleReader)
ilModuleReader